From afd34f2893a06a3aecf17e8e83b1df6ed2ae91a2 Mon Sep 17 00:00:00 2001 From: iroul Date: Fri, 4 Apr 2014 07:35:14 -0700 Subject: move to my github. --- src/CMakeLists.txt | 13 + src/common/CMakeLists.txt | 36 + src/common/common.cpp | 53 + src/common/common.h | 64 + src/common/fqterm.h | 350 + src/common/fqterm_config.cpp | 181 + src/common/fqterm_config.h | 61 + src/common/fqterm_exif_extractor.cpp | 647 + src/common/fqterm_exif_extractor.h | 126 + src/common/fqterm_filedialog.cpp | 157 + src/common/fqterm_filedialog.h | 49 + src/common/fqterm_font.cpp | 261 + src/common/fqterm_font.h | 34 + src/common/fqterm_param.cpp | 274 + src/common/fqterm_param.h | 221 + src/common/fqterm_path.cpp | 601 + src/common/fqterm_path.h | 46 + src/common/fqterm_shortcuthelper.cpp | 298 + src/common/fqterm_shortcuthelper.h | 175 + src/common/fqterm_sound.cpp | 733 ++ src/common/fqterm_sound.h | 79 + src/common/fqterm_trace.cpp | 328 + src/common/fqterm_trace.h | 331 + src/fqterm/3rdparty/dotnetstyle.cpp | 1274 ++ src/fqterm/3rdparty/dotnetstyle.h | 77 + src/fqterm/3rdparty/qxtglobal.h | 207 + src/fqterm/3rdparty/qxtglobalshortcut.cpp | 193 + src/fqterm/3rdparty/qxtglobalshortcut.h | 58 + src/fqterm/3rdparty/qxtglobalshortcut_mac.cpp | 262 + src/fqterm/3rdparty/qxtglobalshortcut_p.h | 63 + src/fqterm/3rdparty/qxtglobalshortcut_win.cpp | 214 + src/fqterm/3rdparty/qxtglobalshortcut_x11.cpp | 115 + src/fqterm/3rdparty/uaocodec.cpp | 15761 ++++++++++++++++++++++++ src/fqterm/3rdparty/uaocodec.h | 69 + src/fqterm/CMakeLists.txt | 83 + src/fqterm/fqterm.rc | Bin 0 -> 330 bytes src/fqterm/fqterm_app.cpp | 38 + src/fqterm/fqterm_app.h | 41 + src/fqterm/fqterm_autoupdate.cpp | 178 + src/fqterm/fqterm_autoupdate.h | 61 + src/fqterm/fqterm_frame.cpp | 2162 ++++ src/fqterm/fqterm_frame.h | 326 + src/fqterm/fqterm_python.cpp | 826 ++ src/fqterm/fqterm_python.h | 51 + src/fqterm/fqterm_screen.cpp | 1868 +++ src/fqterm/fqterm_screen.h | 281 + src/fqterm/fqterm_scriptengine.cpp | 488 + src/fqterm/fqterm_scriptengine.h | 147 + src/fqterm/fqterm_window.cpp | 2531 ++++ src/fqterm/fqterm_window.h | 345 + src/fqterm/fqterm_wndmgr.cpp | 381 + src/fqterm/fqterm_wndmgr.h | 115 + src/fqterm/main.cpp | 135 + src/protocol/CMakeLists.txt | 65 + src/protocol/fqterm_socket.cpp | 672 + src/protocol/fqterm_socket.h | 196 + src/protocol/fqterm_ssh_socket.cpp | 352 + src/protocol/fqterm_ssh_socket.h | 131 + src/protocol/internal/crc32.cpp | 84 + src/protocol/internal/crc32.h | 37 + src/protocol/internal/fqterm_serialization.h | 54 + src/protocol/internal/fqterm_ssh1_packet.cpp | 148 + src/protocol/internal/fqterm_ssh1_packet.h | 40 + src/protocol/internal/fqterm_ssh2_kex.cpp | 394 + src/protocol/internal/fqterm_ssh2_kex.h | 105 + src/protocol/internal/fqterm_ssh2_packet.cpp | 267 + src/protocol/internal/fqterm_ssh2_packet.h | 51 + src/protocol/internal/fqterm_ssh_auth.cpp | 223 + src/protocol/internal/fqterm_ssh_auth.h | 112 + src/protocol/internal/fqterm_ssh_buffer.cpp | 302 + src/protocol/internal/fqterm_ssh_buffer.h | 83 + src/protocol/internal/fqterm_ssh_channel.cpp | 439 + src/protocol/internal/fqterm_ssh_channel.h | 130 + src/protocol/internal/fqterm_ssh_cipher.h | 58 + src/protocol/internal/fqterm_ssh_const.h | 146 + src/protocol/internal/fqterm_ssh_des.cpp | 180 + src/protocol/internal/fqterm_ssh_des.h | 74 + src/protocol/internal/fqterm_ssh_hash.h | 47 + src/protocol/internal/fqterm_ssh_kex.cpp | 210 + src/protocol/internal/fqterm_ssh_kex.h | 100 + src/protocol/internal/fqterm_ssh_mac.cpp | 53 + src/protocol/internal/fqterm_ssh_mac.h | 54 + src/protocol/internal/fqterm_ssh_md5.cpp | 36 + src/protocol/internal/fqterm_ssh_md5.h | 50 + src/protocol/internal/fqterm_ssh_packet.cpp | 242 + src/protocol/internal/fqterm_ssh_packet.h | 148 + src/protocol/internal/fqterm_ssh_pubkey.h | 37 + src/protocol/internal/fqterm_ssh_rsa.cpp | 67 + src/protocol/internal/fqterm_ssh_rsa.h | 41 + src/protocol/internal/fqterm_ssh_types.h | 43 + src/terminal/CMakeLists.txt | 46 + src/terminal/fqterm_buffer.cpp | 998 ++ src/terminal/fqterm_buffer.h | 297 + src/terminal/fqterm_session.cpp | 1648 +++ src/terminal/fqterm_session.h | 344 + src/terminal/fqterm_text_line.cpp | 541 + src/terminal/fqterm_text_line.h | 159 + src/terminal/internal/fqterm_decode.cpp | 1279 ++ src/terminal/internal/fqterm_decode.h | 194 + src/terminal/internal/fqterm_telnet.cpp | 1041 ++ src/terminal/internal/fqterm_telnet.h | 195 + src/terminal/internal/fqterm_zmodem.cpp | 3056 +++++ src/terminal/internal/fqterm_zmodem.h | 623 + src/ui/CMakeLists.txt | 122 + src/ui/aboutdialog.cpp | 71 + src/ui/aboutdialog.h | 39 + src/ui/aboutdialog.ui | 175 + src/ui/addrdialog.cpp | 396 + src/ui/addrdialog.h | 87 + src/ui/addrdialog.ui | 1211 ++ src/ui/articledialog.cpp | 105 + src/ui/articledialog.h | 52 + src/ui/articledialog.ui | 132 + src/ui/defineescape.cpp | 51 + src/ui/defineescape.h | 44 + src/ui/defineescape.ui | 68 + src/ui/fqterm_canvas.cpp | 537 + src/ui/fqterm_canvas.h | 105 + src/ui/fqterm_time_label.cpp | 50 + src/ui/fqterm_time_label.h | 44 + src/ui/fqterm_tool_button.cpp | 41 + src/ui/fqterm_tool_button.h | 46 + src/ui/imageviewer.cpp | 1749 +++ src/ui/imageviewer.h | 336 + src/ui/iplookup.cpp | 56 + src/ui/iplookup.h | 43 + src/ui/iplookup.ui | 76 + src/ui/keydialog.cpp | 285 + src/ui/keydialog.h | 63 + src/ui/keydialog.ui | 665 + src/ui/msgdialog.cpp | 43 + src/ui/msgdialog.h | 35 + src/ui/msgdialog.ui | 86 + src/ui/osdmessage.cpp | 210 + src/ui/osdmessage.h | 69 + src/ui/overlayWidget.cpp | 84 + src/ui/overlayWidget.h | 51 + src/ui/pictureflow.cpp | 1201 ++ src/ui/pictureflow.h | 198 + src/ui/popupMessage.cpp | 316 + src/ui/popupMessage.h | 116 + src/ui/popwidget.cpp | 177 + src/ui/popwidget.h | 70 + src/ui/prefdialog.cpp | 332 + src/ui/prefdialog.h | 66 + src/ui/prefdialog.ui | 644 + src/ui/progressBar.cpp | 100 + src/ui/progressBar.h | 71 + src/ui/quickdialog.cpp | 258 + src/ui/quickdialog.h | 73 + src/ui/quickdialog.ui | 211 + src/ui/schemadialog.cpp | 323 + src/ui/schemadialog.h | 80 + src/ui/schemadialog.ui | 539 + src/ui/shortcutdialog.cpp | 176 + src/ui/shortcutdialog.h | 61 + src/ui/sitemanager.cpp | 412 + src/ui/sitemanager.h | 104 + src/ui/sitemanager.ui | 593 + src/ui/soundconf.cpp | 178 + src/ui/soundconf.h | 57 + src/ui/soundconf.ui | 162 + src/ui/sshlogin.ui | 75 + src/ui/sshlogindialog.cpp | 80 + src/ui/sshlogindialog.h | 45 + src/ui/statusBar.cpp | 530 + src/ui/statusBar.h | 148 + src/ui/zmodemdialog.cpp | 73 + src/ui/zmodemdialog.h | 51 + src/ui/zmodemdialog.ui | 105 + src/unite/CMakeLists.txt | 46 + src/unite/fqterm_mini_server.cpp | 71 + src/unite/fqterm_mini_server.h | 69 + src/unite/internal/article.cpp | 19 + src/unite/internal/article.h | 28 + src/unite/internal/board.cpp | 19 + src/unite/internal/board.h | 28 + src/unite/internal/session.cpp | 138 + src/unite/internal/session.h | 77 + src/unite/internal/state.cpp | 676 + src/unite/internal/state.h | 219 + src/unite/internal/statebuilder.cpp | 32 + src/unite/internal/statebuilder.h | 16 + src/unite/internal/unite.h | 35 + src/unite/internal/user.cpp | 19 + src/unite/internal/user.h | 35 + src/utilities/CMakeLists.txt | 33 + src/utilities/fqterm_convert.cpp | 3485 ++++++ src/utilities/fqterm_convert.h | 44 + src/utilities/fqterm_http.cpp | 264 + src/utilities/fqterm_http.h | 83 + src/utilities/fqterm_ip_location.cpp | 265 + src/utilities/fqterm_ip_location.h | 73 + src/utilities/fqwcwidth.cpp | 468 + src/utilities/fqwcwidth.h | 60 + 195 files changed, 70514 insertions(+) create mode 100644 src/CMakeLists.txt create mode 100644 src/common/CMakeLists.txt create mode 100644 src/common/common.cpp create mode 100644 src/common/common.h create mode 100644 src/common/fqterm.h create mode 100644 src/common/fqterm_config.cpp create mode 100644 src/common/fqterm_config.h create mode 100644 src/common/fqterm_exif_extractor.cpp create mode 100644 src/common/fqterm_exif_extractor.h create mode 100644 src/common/fqterm_filedialog.cpp create mode 100644 src/common/fqterm_filedialog.h create mode 100644 src/common/fqterm_font.cpp create mode 100644 src/common/fqterm_font.h create mode 100644 src/common/fqterm_param.cpp create mode 100644 src/common/fqterm_param.h create mode 100644 src/common/fqterm_path.cpp create mode 100644 src/common/fqterm_path.h create mode 100644 src/common/fqterm_shortcuthelper.cpp create mode 100644 src/common/fqterm_shortcuthelper.h create mode 100644 src/common/fqterm_sound.cpp create mode 100644 src/common/fqterm_sound.h create mode 100644 src/common/fqterm_trace.cpp create mode 100644 src/common/fqterm_trace.h create mode 100644 src/fqterm/3rdparty/dotnetstyle.cpp create mode 100644 src/fqterm/3rdparty/dotnetstyle.h create mode 100644 src/fqterm/3rdparty/qxtglobal.h create mode 100644 src/fqterm/3rdparty/qxtglobalshortcut.cpp create mode 100644 src/fqterm/3rdparty/qxtglobalshortcut.h create mode 100644 src/fqterm/3rdparty/qxtglobalshortcut_mac.cpp create mode 100644 src/fqterm/3rdparty/qxtglobalshortcut_p.h create mode 100644 src/fqterm/3rdparty/qxtglobalshortcut_win.cpp create mode 100644 src/fqterm/3rdparty/qxtglobalshortcut_x11.cpp create mode 100644 src/fqterm/3rdparty/uaocodec.cpp create mode 100644 src/fqterm/3rdparty/uaocodec.h create mode 100644 src/fqterm/CMakeLists.txt create mode 100644 src/fqterm/fqterm.rc create mode 100644 src/fqterm/fqterm_app.cpp create mode 100644 src/fqterm/fqterm_app.h create mode 100644 src/fqterm/fqterm_autoupdate.cpp create mode 100644 src/fqterm/fqterm_autoupdate.h create mode 100644 src/fqterm/fqterm_frame.cpp create mode 100644 src/fqterm/fqterm_frame.h create mode 100644 src/fqterm/fqterm_python.cpp create mode 100644 src/fqterm/fqterm_python.h create mode 100644 src/fqterm/fqterm_screen.cpp create mode 100644 src/fqterm/fqterm_screen.h create mode 100644 src/fqterm/fqterm_scriptengine.cpp create mode 100644 src/fqterm/fqterm_scriptengine.h create mode 100644 src/fqterm/fqterm_window.cpp create mode 100644 src/fqterm/fqterm_window.h create mode 100644 src/fqterm/fqterm_wndmgr.cpp create mode 100644 src/fqterm/fqterm_wndmgr.h create mode 100644 src/fqterm/main.cpp create mode 100644 src/protocol/CMakeLists.txt create mode 100644 src/protocol/fqterm_socket.cpp create mode 100644 src/protocol/fqterm_socket.h create mode 100644 src/protocol/fqterm_ssh_socket.cpp create mode 100644 src/protocol/fqterm_ssh_socket.h create mode 100644 src/protocol/internal/crc32.cpp create mode 100644 src/protocol/internal/crc32.h create mode 100644 src/protocol/internal/fqterm_serialization.h create mode 100644 src/protocol/internal/fqterm_ssh1_packet.cpp create mode 100644 src/protocol/internal/fqterm_ssh1_packet.h create mode 100644 src/protocol/internal/fqterm_ssh2_kex.cpp create mode 100644 src/protocol/internal/fqterm_ssh2_kex.h create mode 100644 src/protocol/internal/fqterm_ssh2_packet.cpp create mode 100644 src/protocol/internal/fqterm_ssh2_packet.h create mode 100644 src/protocol/internal/fqterm_ssh_auth.cpp create mode 100644 src/protocol/internal/fqterm_ssh_auth.h create mode 100644 src/protocol/internal/fqterm_ssh_buffer.cpp create mode 100644 src/protocol/internal/fqterm_ssh_buffer.h create mode 100644 src/protocol/internal/fqterm_ssh_channel.cpp create mode 100644 src/protocol/internal/fqterm_ssh_channel.h create mode 100644 src/protocol/internal/fqterm_ssh_cipher.h create mode 100644 src/protocol/internal/fqterm_ssh_const.h create mode 100644 src/protocol/internal/fqterm_ssh_des.cpp create mode 100644 src/protocol/internal/fqterm_ssh_des.h create mode 100644 src/protocol/internal/fqterm_ssh_hash.h create mode 100644 src/protocol/internal/fqterm_ssh_kex.cpp create mode 100644 src/protocol/internal/fqterm_ssh_kex.h create mode 100644 src/protocol/internal/fqterm_ssh_mac.cpp create mode 100644 src/protocol/internal/fqterm_ssh_mac.h create mode 100644 src/protocol/internal/fqterm_ssh_md5.cpp create mode 100644 src/protocol/internal/fqterm_ssh_md5.h create mode 100644 src/protocol/internal/fqterm_ssh_packet.cpp create mode 100644 src/protocol/internal/fqterm_ssh_packet.h create mode 100644 src/protocol/internal/fqterm_ssh_pubkey.h create mode 100644 src/protocol/internal/fqterm_ssh_rsa.cpp create mode 100644 src/protocol/internal/fqterm_ssh_rsa.h create mode 100644 src/protocol/internal/fqterm_ssh_types.h create mode 100644 src/terminal/CMakeLists.txt create mode 100644 src/terminal/fqterm_buffer.cpp create mode 100644 src/terminal/fqterm_buffer.h create mode 100644 src/terminal/fqterm_session.cpp create mode 100644 src/terminal/fqterm_session.h create mode 100644 src/terminal/fqterm_text_line.cpp create mode 100644 src/terminal/fqterm_text_line.h create mode 100644 src/terminal/internal/fqterm_decode.cpp create mode 100644 src/terminal/internal/fqterm_decode.h create mode 100644 src/terminal/internal/fqterm_telnet.cpp create mode 100644 src/terminal/internal/fqterm_telnet.h create mode 100644 src/terminal/internal/fqterm_zmodem.cpp create mode 100644 src/terminal/internal/fqterm_zmodem.h create mode 100644 src/ui/CMakeLists.txt create mode 100644 src/ui/aboutdialog.cpp create mode 100644 src/ui/aboutdialog.h create mode 100644 src/ui/aboutdialog.ui create mode 100644 src/ui/addrdialog.cpp create mode 100644 src/ui/addrdialog.h create mode 100644 src/ui/addrdialog.ui create mode 100644 src/ui/articledialog.cpp create mode 100644 src/ui/articledialog.h create mode 100644 src/ui/articledialog.ui create mode 100644 src/ui/defineescape.cpp create mode 100644 src/ui/defineescape.h create mode 100644 src/ui/defineescape.ui create mode 100644 src/ui/fqterm_canvas.cpp create mode 100644 src/ui/fqterm_canvas.h create mode 100644 src/ui/fqterm_time_label.cpp create mode 100644 src/ui/fqterm_time_label.h create mode 100644 src/ui/fqterm_tool_button.cpp create mode 100644 src/ui/fqterm_tool_button.h create mode 100644 src/ui/imageviewer.cpp create mode 100644 src/ui/imageviewer.h create mode 100644 src/ui/iplookup.cpp create mode 100644 src/ui/iplookup.h create mode 100644 src/ui/iplookup.ui create mode 100644 src/ui/keydialog.cpp create mode 100644 src/ui/keydialog.h create mode 100644 src/ui/keydialog.ui create mode 100644 src/ui/msgdialog.cpp create mode 100644 src/ui/msgdialog.h create mode 100644 src/ui/msgdialog.ui create mode 100644 src/ui/osdmessage.cpp create mode 100644 src/ui/osdmessage.h create mode 100644 src/ui/overlayWidget.cpp create mode 100644 src/ui/overlayWidget.h create mode 100644 src/ui/pictureflow.cpp create mode 100644 src/ui/pictureflow.h create mode 100644 src/ui/popupMessage.cpp create mode 100644 src/ui/popupMessage.h create mode 100644 src/ui/popwidget.cpp create mode 100644 src/ui/popwidget.h create mode 100644 src/ui/prefdialog.cpp create mode 100644 src/ui/prefdialog.h create mode 100644 src/ui/prefdialog.ui create mode 100644 src/ui/progressBar.cpp create mode 100644 src/ui/progressBar.h create mode 100644 src/ui/quickdialog.cpp create mode 100644 src/ui/quickdialog.h create mode 100644 src/ui/quickdialog.ui create mode 100644 src/ui/schemadialog.cpp create mode 100644 src/ui/schemadialog.h create mode 100644 src/ui/schemadialog.ui create mode 100644 src/ui/shortcutdialog.cpp create mode 100644 src/ui/shortcutdialog.h create mode 100644 src/ui/sitemanager.cpp create mode 100644 src/ui/sitemanager.h create mode 100644 src/ui/sitemanager.ui create mode 100644 src/ui/soundconf.cpp create mode 100644 src/ui/soundconf.h create mode 100644 src/ui/soundconf.ui create mode 100644 src/ui/sshlogin.ui create mode 100644 src/ui/sshlogindialog.cpp create mode 100644 src/ui/sshlogindialog.h create mode 100644 src/ui/statusBar.cpp create mode 100644 src/ui/statusBar.h create mode 100644 src/ui/zmodemdialog.cpp create mode 100644 src/ui/zmodemdialog.h create mode 100644 src/ui/zmodemdialog.ui create mode 100644 src/unite/CMakeLists.txt create mode 100644 src/unite/fqterm_mini_server.cpp create mode 100644 src/unite/fqterm_mini_server.h create mode 100644 src/unite/internal/article.cpp create mode 100644 src/unite/internal/article.h create mode 100644 src/unite/internal/board.cpp create mode 100644 src/unite/internal/board.h create mode 100644 src/unite/internal/session.cpp create mode 100644 src/unite/internal/session.h create mode 100644 src/unite/internal/state.cpp create mode 100644 src/unite/internal/state.h create mode 100644 src/unite/internal/statebuilder.cpp create mode 100644 src/unite/internal/statebuilder.h create mode 100644 src/unite/internal/unite.h create mode 100644 src/unite/internal/user.cpp create mode 100644 src/unite/internal/user.h create mode 100644 src/utilities/CMakeLists.txt create mode 100644 src/utilities/fqterm_convert.cpp create mode 100644 src/utilities/fqterm_convert.h create mode 100644 src/utilities/fqterm_http.cpp create mode 100644 src/utilities/fqterm_http.h create mode 100644 src/utilities/fqterm_ip_location.cpp create mode 100644 src/utilities/fqterm_ip_location.h create mode 100644 src/utilities/fqwcwidth.cpp create mode 100644 src/utilities/fqwcwidth.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..e8aedb4 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,13 @@ +add_subdirectory(common) + +add_subdirectory(protocol) + +add_subdirectory(ui) + +add_subdirectory(terminal) + +add_subdirectory(utilities) + +add_subdirectory(unite) + +add_subdirectory(fqterm) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt new file mode 100644 index 0000000..d3f0c09 --- /dev/null +++ b/src/common/CMakeLists.txt @@ -0,0 +1,36 @@ +set(fqterm_common_SRCS + common.h + common.cpp + fqterm.h + fqterm_trace.h + fqterm_trace.cpp + fqterm_config.h + fqterm_config.cpp + fqterm_sound.h + fqterm_sound.cpp + fqterm_param.h + fqterm_param.cpp + fqterm_path.h + fqterm_path.cpp + fqterm_font.h + fqterm_font.cpp + fqterm_exif_extractor.h + fqterm_exif_extractor.cpp + fqterm_filedialog.h + fqterm_filedialog.cpp + fqterm_shortcuthelper.h + fqterm_shortcuthelper.cpp +) + +qt4_automoc(${fqterm_common_SRCS}) + +include_directories( + ${QT_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} + ${QT_QTGUI_INCLUDE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_library(fqterm_common + ${fqterm_common_SRCS} +) diff --git a/src/common/common.cpp b/src/common/common.cpp new file mode 100644 index 0000000..ec08bef --- /dev/null +++ b/src/common/common.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#include +#include +#include +#include "common.h" + +namespace FQTerm { + +void runProgram(const QString &cmd, const QString& arg, bool bg) { + if (bg) { + QProcess::startDetached(cmd, QStringList(arg)); + } else { + QProcess::execute(cmd, QStringList(arg)); + } + + return; + /* +#if defined(WIN32) + QString strCmd = "\"\"" + cmd + "\" \"" + arg + "\"\""; +#else + QString strCmd = "'" + cmd + "' '" + arg + "'"; +#endif +#if !defined(WIN32) + if (bg) { + strCmd += " &"; + } +#endif + system(strCmd.toLocal8Bit()); + */ +} + +} // namespace FQTerm diff --git a/src/common/common.h b/src/common/common.h new file mode 100644 index 0000000..5720ddc --- /dev/null +++ b/src/common/common.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_COMMON_H +#define FQTERM_COMMON_H + +#if defined(WIN32) +#define OS_NEW_LINE "\r\n" +#elif defined(__APPLE__) +#define OS_NEW_LINE "\r" +#else +#define OS_NEW_LINE "\n" +#endif + +class QString; + +namespace FQTerm { + +enum Directions { + kHome = 0, + kEnd = 1, + kPageUp = 2, + kPageDown = 3, + kUp = 4, + kDown = 5, + kLeft = 6, + kRight = 7 +}; + +const char * const kDirections[] = { + // 4 + "\x1b[1~", // 0 HOME + "\x1b[4~", // 1 END + "\x1b[5~", // 2 PAGE UP + "\x1b[6~", // 3 PAGE DOWN + // 3 + "\x1b[A", // 4 UP + "\x1b[B", // 5 DOWN + "\x1b[D", // 6 LEFT + "\x1b[C" // 7 RIGHT +}; + +void runProgram(const QString &cmd, const QString& arg = "", bool bg = true); + +} // namespace FQTerm + +#endif // FQTERM_COMMON_H diff --git a/src/common/fqterm.h b/src/common/fqterm.h new file mode 100644 index 0000000..515cedc --- /dev/null +++ b/src/common/fqterm.h @@ -0,0 +1,350 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_GLOBAL_H +#define FQTERM_GLOBAL_H + +#ifndef BUFSIZE +#define BUFSIZE (1024) +#endif + +#include +#include +#include "fqterm_trace.h" + +namespace FQTerm { + +#if defined(WIN32) && (_MSC_VER >= 1400) + //Using vc2005 or + +#define fq_strdup _strdup +#else +#define fq_strdup strdup +#endif + +#ifdef FOUND_PYTHON +//#define HAVE_PYTHON +#endif //FOUND_PYTHON + +#define USE_GLOBAL_HOTKEY + +//code convert +enum EncodingID {FQTERM_ENCODING_GBK = 0, FQTERM_ENCODING_BIG5 = 1, + FQTERM_ENCODING_UTF8 = 2, FQTERM_ENCODING_HKSCS = 3, + FQTERM_ENCODING_UAO = 4}; + +#if QT_VERSION >= 0X040700 +#define GBK_CODECS_NAME "GB18030" +#else +#define GBK_CODECS_NAME "GBK" +#endif + +#define G2U(s) ( QTextCodec::codecForName(GBK_CODECS_NAME)->toUnicode(s) ) +#define U2G(s) ( QTextCodec::codecForName(GBK_CODECS_NAME)->fromUnicode(s) ) +#define B2U(s) ( QTextCodec::codecForName("Big5")->toUnicode(s) ) +#define U2B(s) ( QTextCodec::codecForName("Big5")->fromUnicode(s) ) +#define H2U(s) ( QTextCodec::codecForName("Big5-HKSCS")->toUnicode(s) ) +#define U2H(s) ( QTextCodec::codecForName("Big5-HKSCS")->fromUnicode(s) ) +#define U2U8(s) ( s.toUtf8() ) +#define U82U(s) ( QString::fromUtf8(s) ) +#define A2U(s) (QTextCodec::codecForName("UAO")->toUnicode(s) ) +#define U2A(s) ( QTextCodec::codecForName("UAO")->fromUnicode(s) ) + +inline QByteArray unicode2encoding(const QString &text, int encoding) { + switch(encoding) + { + case FQTERM_ENCODING_GBK: + return(U2G(text)); + case FQTERM_ENCODING_BIG5: + return(U2B(text)); + case FQTERM_ENCODING_UTF8: + return(U2U8(text)); + case FQTERM_ENCODING_HKSCS: + return (U2H(text)); + case FQTERM_ENCODING_UAO: + return (U2A(text)); + } + + return ""; +} + +inline QString encoding2unicode(const QByteArray &text, int encoding) { + switch(encoding) + { + case FQTERM_ENCODING_GBK: + return(G2U(text)); + case FQTERM_ENCODING_BIG5: + return(B2U(text)); + case FQTERM_ENCODING_UTF8: + return(U82U(text)); + case FQTERM_ENCODING_HKSCS: + return (H2U(text)); + case FQTERM_ENCODING_UAO: + return (A2U(text)); + } + + return ""; +} + +#define FQTERM_CTRL(c) ((c)&0x1f) + +// every character has a 16-bit description +// low 8 for colors +// hight 8 for attributes +#define COLORMASK 0x00ff +#define ATTRMASK 0xff00 + +// color 8-bit +// bit 0-2 foreground +// 0 black +// 1 red +// 2 green +// 3 yellow +// 4 blue +// 5 magenta +// 6 cyan +// 7 white +// bit 3 highlight foreground +// 0 no +// 1 highlight +// bit 4-6 background +// 0 black +// 1 red +// 2 green +// 3 yellow +// 4 blue +// 5 magenta +// 6 cyan +// 7 white +// bit 7 highlight background (unused) +// 0 no +// 1 highlight + +#define FGMASK 0x0f +#define BGMASK 0xf0 +#define FG_HIGHLIGHT_MASK 0x08 +#define BG_HIGHLIGHT_MASK 0x80 + +//set color +#define SETFG(c) ( (c) & FGMASK ) +#define SETBG(c) ( ( (c) << 4 ) & BGMASK ) +#define SET_FG_HIGHLIGHT(c) ( ( (c) << 3 ) & FG_HIGHLIGHT_MASK ) +#define SET_BG_HIGHLIGHT(c) ( ( (c) << 7 ) & BG_HIGHLIGHT_MASK ) + +//get color +#define GETFG(c) ( (c) & FGMASK ) +#define GETBG(c) ( ( (c) & BGMASK ) >> 4 ) + +#define GET_FG_HIGHLIGHT(c) ( ( (c) & FG_HIGHLIGHT_MASK ) >> 3 ) +#define GET_BG_HIGHLIGHT(c) ( ( (c) & BG_HIGHLIGHT_MASK ) >> 7 ) + +//#define GET_INVERSE_COLOR(c) ( SETFG( (7 - (c & 0x7)) | (c & 0x08) ) | SETBG(15-GETBG(c)) ) +#define GET_INVERSE_COLOR(c) ( SETFG(15-GETFG(c)) | SETBG(15-GETBG(c)) ) + +// mask for attr +#define BRIGHTMASK 0x01 +#define DIMMASK 0x02 +#define UNDERLINEMASK 0x08 +#define BLINKMASK 0x10 +#define RAPIDBLINKMASK 0x20 +#define REVERSEMASK 0x40 +#define INVISIBLEMASK 0x80 + +//set attributes +#define SETBRIGHT(a) ( (a) | BRIGHTMASK ) +#define SETDIM(a) ( (a) | DIMMASK ) +#define SETUNDERLINE(a) ( (a) | UNDERLINEMASK ) +#define SETBLINK(a) ( (a) | BLINKMASK ) +#define SETRAPIDBLINK(a) ( (a) | RAPIDBLINKMASK ) +#define SETREVERSE(a) ( (a) | REVERSEMASK ) +#define SETINVISIBLE(a) ( (a) | INVISIBLEMASK ) + +//get attributes +#define GETBRIGHT(a) ( (a) & BRIGHTMASK ) +#define GETDIM(a) ( (a) & DIMMASK ) +#define GETUNDERLINE(a) ( (a) & UNDERLINEMASK ) +#define GETBLINK(a) ( (a) & BLINKMASK ) +#define GETRAPIDBLINK(a) ( (a) & RAPIDBLINKMASK ) +#define GETREVERSE(a) ( (a) & REVERSEMASK ) +#define GETINVISIBLE(a) ( (a) & INVISIBLEMASK ) + +//default color +#define NO_COLOR ( SETFG(7) | SETBG(0) ) +//default attribute +#define NO_ATTR 0x04 + +// other definations +#ifndef NULL +#define NULL 0 +#endif + +#define DAE_FINISH 10001 +#define DAE_TIMEOUT 10002 + +#define PYE_ERROR 10003 +#define PYE_FINISH 10004 + +// some keys +#define CHAR_NUL 0x00 // ^@ +#define CHAR_ENQ 0x05 // ^E +#define CHAR_BELL 0x07 // ^G +#define CHAR_BS 0x08 // ^H +#define CHAR_TAB 0x09 // ^I +#define CHAR_LF 0x0a // ^J +#define CHAR_VT 0x0b // ^K +#define CHAR_FF 0x0c // ^L +#define CHAR_CR 0x0d // ^M +#define CHAR_SO 0x0e // ^N +#define CHAR_SI 0x0f // ^O +#define CHAR_CAN 0x18 // ^X +#define CHAR_ESC 0x1b // ^[ +#define CHAR_DEL 0x7f // DEL + +#define CHAR_NORMAL -1 + +const char ANSWERBACK_MESSAGE[] = "This is fqterm."; + +// telnet state +#define TSRESOLVING 30 +#define TSHOSTFOUND 31 +#define TSHOSTNOTFOUND 32 +#define TSCONNECTING 33 +#define TSHOSTCONNECTED 34 +#define TSPROXYCONNECTED 35 +#define TSPROXYAUTH 36 +#define TSPROXYFAIL 38 +#define TSREFUSED 39 +#define TSREADERROR 40 +#define TSCLOSED 41 +#define TSCLOSEFINISH 42 +#define TSCONNECTVIAPROXY 43 +#define TSEGETHOSTBYNAME 44 +#define TSEINIWINSOCK 45 +#define TSERROR 46 +#define TSPROXYERROR 47 +#define TSWRITED 48 + +// zmodem types +#define RcvByteCount 0 /* value is # bytes received */ +#define SndByteCount 1 /* value is # bytes sent */ +#define RcvTimeout 2 /* receiver did not respond, aborting */ +#define SndTimeout 3 /* value is # of consecutive send timeouts */ +#define RmtCancel 4 /* remote end has cancelled */ +#define ProtocolErr 5 /* protocol error has occurred, val=hdr */ +#define RemoteMessage 6 /* message from remote end */ +#define DataErr 7 /* data error, val=error count */ +#define FileErr 8 /* error writing file, val=errno */ +#define FileBegin 9 /* file transfer begins, str=name */ +#define FileEnd 10 /* file transfer ends, str=name */ +#define FileSkip 11 /* file being skipped, str=name */ + + +// proxy type +#define NOPROXY 0 +#define WINGATE 1 +#define SOCKS4 2 +#define SOCKS5 3 +#define HTTP 4 + +// UI ID +#define ID_FILE_CONNECT 0x00 +#define ID_FILE_DISCONNECT 0x01 +#define ID_FILE_ADDRESS 0x02 +#define ID_FILE_QUICK 0x03 +#define ID_FILE_EXIT 0x04 + +#define ID_EDIT_COPY 0x10 +#define ID_EDIT_PASTE 0x11 +#define ID_EDIT_COLOR 0x12 +#define ID_EDIT_RECT 0x13 +#define ID_EDIT_AUTO 0x14 +#define ID_EDIT_WW 0x15 + +#define ID_EDIT_ESC_NO 0x17 +#define ID_EDIT_ESC_ESC 0x18 +#define ID_EDIT_ESC_U 0x19 +#define ID_EDIT_ESC_CUS 0x1a + +#define ID_EDIT_CODEC_GBK 0x1b +#define ID_EDIT_CODEC_BIG5 0x1c + + +#define ID_VIEW_FONT 0x20 +#define ID_VIEW_COLOR 0x21 +#define ID_VIEW_REFRESH 0x22 +#define ID_VIEW_LANG 0x23 +#define ID_VIEW_FULL 0x24 +#define ID_VIEW_BOSS 0x25 +#define ID_VIEW_SCROLL_HIDE 0x26 +#define ID_VIEW_SCROLL_LEFT 0x27 +#define ID_VIEW_SCROLL_RIGHT 0x28 +#define ID_VIEW_SWITCH 0x29 +#define ID_VIEW_STATUS 0x3a + +#define ID_OPTION_CURRENT 0x30 +#define ID_OPTION_DEFAULT 0x31 +#define ID_OPTION_PREF 0x32 + +#define ID_SPEC_ANTI 0x40 +#define ID_SPEC_AUTO 0x41 +#define ID_SPEC_MESSAGE 0x42 +#define ID_SPEC_BEEP 0x43 +#define ID_SPEC_MOUSE 0x44 +#define ID_SPEC_ARTICLE 0x45 + +#define ID_SCRIPT_RUN 0x50 +#define ID_SCRIPT_STOP 0x51 + +#define ID_HELP_ABOUT 0x60 +#define ID_HELP_HOMEPAGE 0x61 + +//for open last addr +#define LAST_ADDRESS_INDEX -321 + +//script function names: +#define SFN_ANTI_IDLE "antiIdle" +#define SFN_ON_BELL "onBell" +#define SFN_AUTO_REPLY "autoReply" +#define SFN_DATA_EVENT "dataEvent" +#define SFN_KEY_EVENT "keyEvent" +#define SFN_MOUSE_EVENT "mouseEvent" +#define SFN_DETECT_MENU "detectMenu" + +//script key event type +#define SKET_KEY_PRESS 0 + +//script mouse event type +#define SMET_UNKOWN -1 +#define SMET_MOUSE_PRESS 0 +#define SMET_MOUSE_RELEASE 1 +#define SMET_MOUSE_MOVE 2 +#define SMET_MOUSE_DBCLICK 3 +#define SMET_WHEEL 4 + +//script button state & key modifier +#define SBS_LEFT_BUTTON 0x01 +#define SBS_RIGHT_BUTTON 0x02 +#define SBS_MID_BUTTON 0x04 +#define SBS_ALT 0x08 +#define SBS_CTRL 0x10 +#define SBS_SHIFT 0x20 + +} // namespace FQTerm + +#endif // FQTERM_GLOBAL_H diff --git a/src/common/fqterm_config.cpp b/src/common/fqterm_config.cpp new file mode 100644 index 0000000..19e0db4 --- /dev/null +++ b/src/common/fqterm_config.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "fqterm_trace.h" +#include "fqterm_config.h" + +namespace FQTerm { + +FQTermConfig::FQTermConfig(const QString &szFileName) { + load(szFileName); +} + +FQTermConfig::~FQTermConfig(){ + +} + +bool FQTermConfig::save(const QString &szFileName) { + QFile file(szFileName); + if (!file.open(QIODevice::WriteOnly)) { + FQ_TRACE("config", 0) << "Failed to open the file for writing: " + << szFileName; + return false; + } + + QTextStream os; + os.setDevice(&file); + saveToStream(os); + // os.unsetDevice(); + file.close(); + + + return true; +} + +bool FQTermConfig::loadFromStream(QTextStream &is) { + QString strLine, strSection; + + data.clear(); + + is.setCodec(QTextCodec::codecForName("UTF-8")); + + while (!is.atEnd()) { + strLine = is.readLine().trimmed(); + if (strLine.isEmpty() || strLine[0] == '#') { + continue; + } + + if (strLine.left(1) == "[" && strLine.right(1) == "]") { + strSection = strLine.mid(1, strLine.length() - 2); + addSection(strSection); + } else { + QString strValue = strLine.section('=', 1).trimmed(); + setItemValue(strSection, strLine.section('=', 0, 0).trimmed(), + strValue.isNull() ? QString(""): strValue); + } + } + return true; +} + +bool FQTermConfig::saveToStream(QTextStream &os) { + QString strLine, strSection; + Section::iterator iStr; + + os.setCodec(QTextCodec::codecForName("UTF-8")); + + for (StrSecMap::iterator iSec = data.begin(); iSec != data.end(); ++iSec) { + os << '[' << iSec.key() << "]\n"; + for (iStr = iSec.value().begin(); iStr != iSec.value().end(); ++iStr) { + os << iStr.key() << '=' << iStr.value() << '\n'; + } + os << '\n'; + } + return true; +} + + +bool FQTermConfig::addSection(const QString &szSection) { + if (hasSection(szSection)) { + return false; + } + Section sec; + data[szSection] = sec; + return true; +} + +bool FQTermConfig::hasSection(const QString &szSection) const +{ + return data.find(szSection) != data.end(); +} + +bool FQTermConfig::setItemValue(const QString &szSection, const QString + &szItemName, const QString &szItemValue) { + if (!hasSection(szSection)) + if (!addSection(szSection)) { + return false; + } + + data[szSection][szItemName] = szItemValue; + return true; +} + +QString FQTermConfig::getItemValue(const QString &szSection, + const QString &szItemName) const { + if (hasSection(szSection)) + if (data[szSection].find(szItemName) != data[szSection].end()) + if (!data[szSection][szItemName].isEmpty()) { + return data[szSection][szItemName]; + } + return ""; +} + +bool FQTermConfig::renameSection(const QString &szSection, const QString + &szNewName) { + if (hasSection(szNewName) || !hasSection(szSection)) { + return false; + } + + if (!addSection(szNewName)) { + return false; + } + data[szNewName] = data[szSection]; + + return deleteSection(szSection); +} + +bool FQTermConfig::deleteSection(const QString &szSection) { + if (hasSection(szSection)) { + data.remove(szSection); + return true; + } + return false; +} + +bool FQTermConfig::deleteItem(const QString &szSection, const QString + &szItemName) { + if (hasSection(szSection)) + if (data[szSection].find(szItemName) != data[szSection].end()) { + data[szSection].remove(szItemName); + return true; + } + return false; +} + +bool FQTermConfig::load(const QString &filename) { + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + FQ_TRACE("config", 0) << "Failed to open the file for reading " + << filename; + return false; + } + QTextStream is; + is.setDevice(&file); + loadFromStream(is); + //is.unsetDevice(); + file.close(); + return true; +} + +} // namespace FQTerm diff --git a/src/common/fqterm_config.h b/src/common/fqterm_config.h new file mode 100644 index 0000000..2f88602 --- /dev/null +++ b/src/common/fqterm_config.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_CFG_H +#define FQTERM_CFG_H + +#include +#include +#include + +namespace FQTerm { +typedef QMap Section; +typedef QMap StrSecMap; + +class FQTermConfig { + private: + StrSecMap data; + bool loadFromStream(QTextStream &); + bool saveToStream(QTextStream &); + + bool addSection(const QString §ionName); + public: + FQTermConfig(const QString &fileName); + ~FQTermConfig(); + + bool load(const QString &filename); + bool save(const QString &fileName); + + bool setItemValue(const QString §ionName, const QString &itemName, + const QString &itemValue); + + QString getItemValue(const QString §ionName, + const QString &itemName) const; + + bool deleteItem(const QString §ionName, const QString &itemName); + bool deleteSection(const QString §ionName); + + bool renameSection(const QString §ionName, const QString &newName); + bool hasSection(const QString §ionName) const; +}; + +} // namespace FQTerm + +#endif // FQTERM_CFG_H diff --git a/src/common/fqterm_exif_extractor.cpp b/src/common/fqterm_exif_extractor.cpp new file mode 100644 index 0000000..05d318e --- /dev/null +++ b/src/common/fqterm_exif_extractor.cpp @@ -0,0 +1,647 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_exif_extractor.h" + +namespace FQTerm { + +const ExifExtractor::uint16 ExifExtractor::IFD0Tag[16] = {0x010e, 0x010f, 0x0110, 0x0112, 0x011a, + 0x011b, 0x0128, 0x0131, 0x0132, 0x013e, + 0x013f, 0x0211, 0x0213, 0x0214, 0x8298, 0x8769 +}; + +const char ExifExtractor::IFD0TagName[16][30] = { "ImageDescription", "Make", "Model", "Orientation", + "XResolution", "YResolution", "ResolutionUnit", "Software", + "DateTime", "WhitePoint", "PrimaryChromaticities", "YCbCrCoefficients", + "YCbCrPositioning", "ReferenceBlackWhite", "Copyright", "ExifOffset" +}; + +const ExifExtractor::uint16 ExifExtractor::SubIFDTag[38] = {0x829a,0x829d,0x8822,0x8827,0x9000,0x9003,0x9004,0x9101,0x9102,0x9201,0x9202,0x9203,0x9204, + 0x9205,0x9206,0x9207,0x9208,0x9209,0x920a,0x927c,0x9286,0x9290,0x9291,0x9292,0xa000,0xa001, + 0xa002,0xa003,0xa004,0xa005,0xa20e,0xa20f,0xa210,0xa215,0xa217,0xa300,0xa301,0xa302}; + +const char ExifExtractor::SubIFDTagName[38][30] = {"ExposureTime","FNumber","ExposureProgram","ISOSpeedRatings","ExifVersion","DateTimeOriginal","DateTimeDigitized", + "ComponentsConfiguration","CompressedBitsPerPixel","ShutterSpeedValue","ApertureValue","BrightnessValue","ExposureBiasValue", + "MaxApertureValue","SubjectDistance","MeteringMode","LightSource","Flash","FocalLength","MakerNote","UserComment","SubsecTime", + "SubsecTimeOriginal","SubsecTimeDigitized","FlashPixVersion","ColorSpace","ExifImageWidth","ExifImageHeight","RelatedSoundFile", + "ExifInteroperabilityOffset","FocalPlaneXResolution","FocalPlaneYResolution","FocalPlaneResolutionUnit","ExposureIndex", + "SensingMethod","FileSource","SceneType","CFAPattern"}; + +const char ExifExtractor::exifHeaderStandard[6] = {'E', 'x', 'i', 'f', '\0', '\0'}; + +ExifExtractor::ExifExtractor() +{ + exifFile_ = NULL; + reset(); +} + +ExifExtractor::~ExifExtractor() +{ + reset(); +} + +std::string ExifExtractor::extractExifInfo(std::string fileName) { + return extractExifInfo(fopen(fileName.c_str(), "rb")); +} + +std::string ExifExtractor::extractExifInfo(FILE* file) { + reset(); + exifFile_ = file; + if (!exifFile_ || !isReadable() || !checkEndian()) { + return exifInformation_; + } + if (!readIFD0()) + return exifInformation_; + readSubIFD(); + postRead(); + std::map::iterator ii; + for (ii = exifKeyValuePairs_.begin(); + ii != exifKeyValuePairs_.end(); + ++ii) { + if ((*ii).first == "UserComment") { + continue; + } + exifInformation_ += (*ii).first + " : " + (*ii).second + "\n"; + } + fclose(exifFile_); + exifFile_ = NULL; + return exifInformation_; +} +std::string ExifExtractor::info() { + return exifInformation_; +} + +std::string ExifExtractor::operator[]( const std::string& key ) { + std::map::iterator ii; + if ((ii = exifKeyValuePairs_.find(key)) != exifKeyValuePairs_.end()) { + return (*ii).second; + } + return ""; +} + +void ExifExtractor::postRead() { + std::map::iterator ii; + if ((ii = exifKeyValuePairs_.find("Orientation")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "1st row - 1st col : top - left side"; break; + case '2': (*ii).second = "1st row - 1st col : top - right side"; break; + case '3': (*ii).second = "1st row - 1st col : bottom - right side"; break; + case '4': (*ii).second = "1st row - 1st col : bottom - left side"; break; + case '5': (*ii).second = "1st row - 1st col : left side - top"; break; + case '6': (*ii).second = "1st row - 1st col : right side - top"; break; + case '7': (*ii).second = "1st row - 1st col : right side - bottom"; break; + case '8': (*ii).second = "1st row - 1st col : left side - bottom"; break; + default: exifKeyValuePairs_.erase(ii); break; + + } + } + } + if ((ii = exifKeyValuePairs_.find("ResolutionUnit")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "no-unit"; break; + case '2': (*ii).second = "inch"; break; + case '3': (*ii).second = "centimeter"; break; + default: (*ii).second = "inch"; break; + } + } + } + if ((ii = exifKeyValuePairs_.find("DateTime")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + for (size_t i = 0; i < (*ii).second.length() && i < 11; ++i) { + if ((*ii).second[i] == ':'){ + (*ii).second[i] = '.'; + } + } + } + } + if ((ii = exifKeyValuePairs_.find("DateTimeOriginal")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + for (size_t i = 0; i < (*ii).second.length() && i < 11; ++i) { + if ((*ii).second[i] == ':'){ + (*ii).second[i] = '.'; + } + } + } + } + if ((ii = exifKeyValuePairs_.find("DateTimeDigitized")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + for (size_t i = 0; i < (*ii).second.length() && i < 11; ++i) { + if ((*ii).second[i] == ':'){ + (*ii).second[i] = '.'; + } + } + } + } + if ((ii = exifKeyValuePairs_.find("YCbCrPositioning")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "The center of pixel array"; break; + case '2': (*ii).second = "The datum point"; break; + default: exifKeyValuePairs_.erase(ii); break; + } + } + } + if ((ii = exifKeyValuePairs_.find("MeteringMode")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + uint16 value = 123; + sscanf((*ii).second.c_str(), "%hu", &value); + switch(value) { + case 0: (*ii).second = "Unknown"; break; + case 1: (*ii).second = "Average"; break; + case 2: (*ii).second = "CenterWeightedAverage"; break; + case 3: (*ii).second = "Spot"; break; + case 4: (*ii).second = "Multi-spot"; break; + case 5: (*ii).second = "Pattern"; break; + case '6': (*ii).second = "Partial"; break; + case 255: (*ii).second = "Other"; break; + default: exifKeyValuePairs_.erase(ii); break; + + } + } + } + if ((ii = exifKeyValuePairs_.find("LightSource")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + uint16 value = 123; + sscanf((*ii).second.c_str(), "%hu", &value); + switch(value) { + case 0: (*ii).second = "unknown"; break; + case 1: (*ii).second = "daylight"; break; + case 2: (*ii).second = "fluorescent"; break; + case 3: (*ii).second = "tungsten"; break; + case 10: (*ii).second = "flash"; break; + case 17: (*ii).second = "standard light A"; break; + case 18: (*ii).second = "standard light B"; break; + case 19: (*ii).second = "standard light C"; break; + case 20: (*ii).second = "D55"; break; + case 21: (*ii).second = "D65"; break; + case 22: (*ii).second = "D75"; break; + case 255: (*ii).second = "other"; break; + default: exifKeyValuePairs_.erase(ii); break; + + } + } + } + if ((ii = exifKeyValuePairs_.find("Flash")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + uint16 value = 123; + sscanf((*ii).second.c_str(), "%hu", &value); + value &= 0x07; + switch(value) { + case 0: (*ii).second = "Flash did not fire"; break; + case 1: (*ii).second = "Flash fired"; break; + case 5: (*ii).second = "Flash fired but strobe return light not detected"; break; + case 7: (*ii).second = "Flash fired and strobe return light detected"; break; + default: exifKeyValuePairs_.erase(ii); break; + } + } + } + if ((ii = exifKeyValuePairs_.find("ColorSpace")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "sRGB color space"; break; + case '6': (*ii).second = "Uncalibrated"; break; + default: exifKeyValuePairs_.erase(ii); break; + } + } + } + if ((ii = exifKeyValuePairs_.find("FocalPlaneResolutionUnit")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "no-unit"; break; + case '2': (*ii).second = "inch"; break; + case '3': (*ii).second = "centimeter"; break; + default: exifKeyValuePairs_.erase(ii); break; + } + } + } + if ((ii = exifKeyValuePairs_.find("SensingMethod")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '2': (*ii).second = "1 chip color area sensor"; break; + default: (*ii).second = "other"; break; + } + } + } + if ((ii = exifKeyValuePairs_.find("ExifVersion")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 4) { + exifKeyValuePairs_.erase(ii); + } else { + (*ii).second = 'V' + (*ii).second.substr(0, 2) + '.' + (*ii).second.substr(2); + } + } + if ((ii = exifKeyValuePairs_.find("ComponentsConfiguration")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 4) { + exifKeyValuePairs_.erase(ii); + } else { + static const char CCName[7][10] = {"", "[Y]", "[Cb]", "[Cr]", "[Red]", "[Green]", "[Blue]"}; + std::string cc; + for(int i = 0; i < 4; ++i) { + int index = (*ii).second[i]; + if (index < 0 || index >= 7) { + index = 0; + } + cc += CCName[index]; + } + } + } + if ((ii = exifKeyValuePairs_.find("ExifVersion")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 4) { + exifKeyValuePairs_.erase(ii); + } else { + (*ii).second = 'V' + (*ii).second.substr(0, 2) + '.' + (*ii).second.substr(2); + } + } + if ((ii = exifKeyValuePairs_.find("MakerNote")) != exifKeyValuePairs_.end()) { + exifKeyValuePairs_.erase(ii); + } + if ((ii = exifKeyValuePairs_.find("CFAPattern")) != exifKeyValuePairs_.end()) { + exifKeyValuePairs_.erase(ii); + } + if ((ii = exifKeyValuePairs_.find("UserComment")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 8) { + exifKeyValuePairs_.erase(ii); + } else { + //Leave it to higher level which can deal with encoding. + //"\0x41\0x53\0x43\0x49\0x49\0x00\0x00\0x00"//ASCII + //"\0x4a\0x49\0x53\0x00\0x00\0x00\0x00\0x00"//JIS + //"\0x55\0x4e\0x49\0x43\0x4f\0x44\0x45\0x00"//Unicode + //"\0x00\0x00\0x00\0x00\0x00\0x00\0x00\0x00"//Undefined + } + } + if ((ii = exifKeyValuePairs_.find("FlashPixVersion")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 4) { + exifKeyValuePairs_.erase(ii); + } else { + (*ii).second = 'V' + (*ii).second.substr(0, 2) + '.' + (*ii).second.substr(2); + } + } + //FileSource + if ((ii = exifKeyValuePairs_.find("FileSource")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 1) { + exifKeyValuePairs_.erase(ii); + } else { + if ((*ii).second[0] == '\003') { + (*ii).second = "Digital still camera"; + } else { + exifKeyValuePairs_.erase(ii); + } + } + } + if ((ii = exifKeyValuePairs_.find("SceneType")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 1) { + exifKeyValuePairs_.erase(ii); + } else { + if ((*ii).second[0] == '\001') { + (*ii).second = "Directly photographed"; + } else { + exifKeyValuePairs_.erase(ii); + } + } + } + +} + +std::string ExifExtractor::readInfo() { + uint32 count; + uint32 offset; + uint16 shortValue; + uint32 longValue; + uint32 urationalp; + uint32 urationalc; + uint32 urationalgcd; + int32 rationalp; + int32 rationalc; + int32 rationalgcd; + int32 sign; + DATATYPE dataType; + char* buffer; + std::string ret = ""; + + if (!read(&shortValue, 2,1) || shortValue == 0 || shortValue > MAXGUARD) { + return ret; + } + dataType = (DATATYPE)shortValue; + + if (!read(&count, 4,1)) { + return ret; + } + + switch(dataType) { + case UNDEFINED: + buffer = new char[count + 1]; + + if (count < 4) { + if (!read(buffer, 1, count)) { + return ret; + } + } else { + if (!read(&offset, 4, 1)) { + return ret; + } + seek(12 + offset, SEEK_SET); + memset(buffer, 0, count + 1); + read(buffer, 1, count); + } + ret = std::string(buffer, count); + delete []buffer; + break; + case ASCIISTRING: + if (!read(&offset, 4, 1)) { + break; + } + seek(12 + offset, SEEK_SET); + buffer = new char[count + 1]; + memset(buffer, 0, count + 1); + read(buffer, 1, count); + ret = buffer; + delete []buffer; + break; + case UNSIGNEDINT16: + if (!read(&shortValue, 2, 1)) { + break; + } + buffer = new char[256]; + sprintf(buffer, "%hu", shortValue); + ret = buffer; + delete []buffer; + break; + case UNSIGNEDINT32: + if (!read(&longValue, 4, 1)) { + break; + } + buffer = new char[256]; + sprintf(buffer, "%u", longValue); + ret = buffer; + delete []buffer; + + break; + case UNSIGNEDRATIONAL: + if (!read(&offset, 4, 1)) { + break; + } + seek(12 + offset, SEEK_SET); + if (!read(&urationalc, 4, 1)) { + break; + } + if (!read(&urationalp, 4, 1)) { + break; + } + urationalgcd = gcd(urationalp, urationalc); + if (urationalgcd == 0) urationalgcd = 1; + buffer = new char[256]; + sprintf(buffer, "%u/%u", urationalc / urationalgcd, urationalp / urationalgcd); + ret = buffer; + delete []buffer; + break; + case RATIONAL: + if (!read(&offset, 4, 1)) { + break; + } + sign = 1; + seek(12 + offset, SEEK_SET); + if (!read(&rationalc, 4, 1)) { + break; + } + if (rationalc < 0) { + sign *= -1; + rationalc = -rationalc; + } + if (!read(&rationalp, 4, 1)) { + break; + } + if (rationalp < 0) { + sign *= -1; + rationalp = -rationalp; + } + rationalgcd = gcd(rationalp, rationalc); + if (rationalgcd == 0) rationalgcd = 1; + buffer = new char[256]; + sprintf(buffer, "%d/%d", sign * rationalc / rationalgcd, rationalp / rationalgcd); + ret = buffer; + delete []buffer; + break; + default: + break; + } + return ret; +} + +bool ExifExtractor::analyzeIFD0TagInfo() { + bool res = true; + uint16 tag; + if (!read(&tag, 2, 1)) + res = false; + int index; + for (index = 0; index < 16; ++index) { + if (IFD0Tag[index] == tag) { + break; + } + } + if (index == 16) { + res = false; + } + long pos = ftell(exifFile_) + 10; + + if (res) { + std::string info = readInfo(); + if (info != "") + exifKeyValuePairs_[IFD0TagName[index]] = info; + } + + seek(pos, SEEK_SET); + return res; +} + +bool ExifExtractor::analyzeSubIFDTagInfo() { + bool res = true; + uint16 tag; + if (!read(&tag, 2, 1)) + res = false; + int index; + for (index = 0; index < 38; ++index) { + if (SubIFDTag[index] == tag) { + break; + } + } + if (index == 38) { + res = false; + } + long pos = ftell(exifFile_) + 10; + + if (res) { + std::string info = readInfo(); + if (info != "") + exifKeyValuePairs_[SubIFDTagName[index]] = info; + } + + seek(pos, SEEK_SET); + return res; +} + +bool ExifExtractor::readIFD0() { + seek(16, SEEK_SET); + if (!read(&ifdOffset_, 4, 1)) { + return false; + } + seek(ifdOffset_ + 12, SEEK_SET); + uint16 entryCount = 0; + if (!read(&entryCount, 2, 1)) { + return false; + } + int app1Entry = entryCount; + while (app1Entry >= 0) { + analyzeIFD0TagInfo(); + app1Entry--; + } + return true; +} + +bool ExifExtractor::readSubIFD() { + std::map::iterator ii; + if ((ii = exifKeyValuePairs_.find("ExifOffset")) == exifKeyValuePairs_.end()) { + return false; + } + uint32 exifOffset = 0; + sscanf((*ii).second.c_str(), "%u", &exifOffset); + seek(12 + exifOffset, SEEK_SET); + + uint16 entryCount = 0; + if (!read(&entryCount, 2, 1)) { + return false; + } + int app1Entry = entryCount; + while (app1Entry >= 0) { + analyzeSubIFDTagInfo(); + app1Entry--; + } + return true; +} + +bool ExifExtractor::isReadable() { + rewind(); + unsigned char soi[2]; + if (!read(soi, 2, 1)) + return false; + if (soi[0] != 0xFF || soi[1] != 0xD8) { + return false; + } + unsigned char app1[2]; + if (!read(app1, 2, 1)) + return false; + if (app1[0] != 0xFF || app1[1] != 0xE1) { + return false; + } + seek(2, SEEK_CUR); + char exifHeader[6]; + if (!read(exifHeader, 1, 6)) { + return false; + } + for (int i = 0; i < 6; ++i) { + if (exifHeader[i] != exifHeaderStandard[i]) + return false; + } + return true; +} + +bool ExifExtractor::checkEndian() { + toggle_ = false; + seek(12, SEEK_SET); + uint16 endian = 0; + if (!read(&endian, 2, 1)) { + return false; + } + if (endian == 0x4949) { + //II + toggle_ = false; + } + else if (endian == 0x4d4d) { + //MM + toggle_ = true; + } + return true; +} + +void ExifExtractor::toggleEndian( void* buf, size_t s ) { + char* buffer = (char*)buf; + if (!toggle_) { + return; + } + for (size_t i = 0; i < s / 2; ++i) { + char tmp; + tmp = buffer[i]; + buffer[i] = buffer[s - i - 1]; + buffer[s - i - 1] = tmp; + } +} + +void ExifExtractor::reset() { + toggle_ = false; + exifKeyValuePairs_.clear(); + if (exifFile_) { + fclose(exifFile_); + exifFile_ = NULL; + } + ifdOffset_ = 0; + exifInformation_.clear(); +} + +bool ExifExtractor::read( void* buffer, size_t elementSize, size_t count ) { + for (size_t i = 0; i < count; ++i) { + if (fread((char*)buffer + i * elementSize, elementSize, 1, exifFile_) != 1) + return false; + toggleEndian((char*)buffer + i * elementSize, elementSize); + } + return true; +} + +void ExifExtractor::seek( long offset, int origin ) { + fseek(exifFile_, offset, origin); +} + +void ExifExtractor::rewind() { + ::rewind(exifFile_); +} +} //namespace FQTerm diff --git a/src/common/fqterm_exif_extractor.h b/src/common/fqterm_exif_extractor.h new file mode 100644 index 0000000..7f05798 --- /dev/null +++ b/src/common/fqterm_exif_extractor.h @@ -0,0 +1,126 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_EXIF_EXTRACTOR +#define FQTERM_EXIF_EXTRACTOR + +//#include + +#include "fqterm_trace.h" + +#include +#include +#include +#include +#include +#include +#include +//using namespace std; +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +#include +#endif + +namespace FQTerm { + +class ExifExtractor +{ +public: + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + typedef std::uint32_t uint32; + typedef std::uint16_t uint16; + typedef std::int32_t int32; + typedef std::int16_t int16; +#elif defined(QT_VERSION) + typedef quint32 uint32; + typedef quint16 uint16; + typedef qint32 int32; + typedef qint16 int16; +#else + typedef unsigned int uint32; + typedef unsigned short int uint16; + typedef short int int16; + typedef int int32; +#endif + + enum DATATYPE {ZEORGARD = 0, UNSIGNEDCHAR = 1, ASCIISTRING = 2, UNSIGNEDINT16 = 3, UNSIGNEDINT32 = 4, + UNSIGNEDRATIONAL = 5, SIGNEDCHAR = 6, UNDEFINED = 7, SIGNEDSHORT = 8, SIGNEDLONG = 9, RATIONAL = 10, + SIGNEDFLOAT = 11, DOUBLEFLOAT = 12, MAXGUARD = 13}; + + + ExifExtractor(); + ~ExifExtractor(); + std::string extractExifInfo(std::string fileName); + std::string extractExifInfo(FILE* file); + + std::string info(); + + std::string operator[](const std::string& key); + +private: + void postRead(); + + std::string readInfo(); + bool analyzeIFD0TagInfo(); + + bool analyzeSubIFDTagInfo(); + + bool readIFD0(); + bool readSubIFD(); + bool isReadable(); + bool checkEndian(); + void toggleEndian(void* buf, size_t s); + + void reset(); + + bool read(void* buffer, size_t elementSize, size_t count); + + void seek(long offset, int origin); + + void rewind(); + + template + T gcd(T a, T b) { + if (a == 0 || b == 0) + return a + b; + return gcd(b, a % b); + } + + + bool toggle_; + std::map exifKeyValuePairs_; + FILE* exifFile_; + uint32 ifdOffset_; + uint32 subIfdOffset_; + + static const uint16 IFD0Tag[16]; + static const char IFD0TagName[16][30]; + static const uint16 SubIFDTag[38]; + static const char SubIFDTagName[38][30]; + static const char exifHeaderStandard[6]; + + std::string exifInformation_; +}; + + + +} //namespace FQTerm + +#endif diff --git a/src/common/fqterm_filedialog.cpp b/src/common/fqterm_filedialog.cpp new file mode 100644 index 0000000..958fff9 --- /dev/null +++ b/src/common/fqterm_filedialog.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_filedialog.h" +#include "fqterm_trace.h" +#include "fqterm_path.h" +#include "fqterm_config.h" + +/* + * Constructs a articleDialog as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ + +namespace FQTerm { + +FQTermFileDialog::FQTermFileDialog(FQTermConfig *config, QWidget *parent, Qt::WFlags fl) + : QFileDialog(parent, fl) { + + configDir = getPath(USER_CONFIG) + "/"; + userConfig = configDir + "fqterm.cfg"; + strSection = "previous"; + strSave = "save"; + strOpen = "open"; + config_ = config; +} + +/* + * Destroys the object and frees any allocated resources + */ +FQTermFileDialog::~FQTermFileDialog() { + // no need to delete child widgets, Qt does it all for us +} + + + +QString FQTermFileDialog::getSaveName(const QString &fileToSave, const QString &hints, QWidget *widget) { + QString saveFile; + QString strPrevSave, saveName; + QFileDialog fileDialog(widget); + + if (config_->load(userConfig)) { + strPrevSave = config_->getItemValue(strSection, strSave); + } + + QString strTmp(fileToSave); +#if !defined(Q_OS_WIN32) || !defined(_OS_WIN32_) + if (strTmp.toLocal8Bit().contains("/")) { + strTmp.replace(QString("/"), QString("_")); + } +#endif + + if (strPrevSave.isEmpty()) { + saveFile = configDir + strTmp; + } else { + saveFile = strPrevSave + "/" + strTmp; + } + + QString realHints = (hints.isEmpty() ? "*" : hints); + saveName = fileDialog.getSaveFileName(widget, + tr("Save As..."), + saveFile, realHints); + + QFileInfo fi(saveName); + + if (!saveName.isEmpty()) { + config_->setItemValue(strSection, strSave, fi.absolutePath()); + config_->save(userConfig); + } + + return saveName; +} + +QString FQTermFileDialog::getOpenName(const QString &title, const QString &hints, QWidget *widget) { + QString strPrevOpen; + QString openName; + QFileDialog fileDialog(widget); + + strPrevOpen = (config_->load(userConfig) ? config_->getItemValue(strSection, strOpen) : "./"); + + QString realHints = (hints.isEmpty() ? "*" : hints); + QString realTitle = (title.isEmpty() ? "Choose a file to open" : title); + openName = fileDialog.getOpenFileName(widget, realTitle, strPrevOpen, realHints); + + if (!openName.isEmpty()) { + config_->setItemValue(strSection, strOpen, QFileInfo(openName).absolutePath()); + config_->save(userConfig); + } + + return openName; +} + +QStringList FQTermFileDialog::getOpenNames(const QString &title, const QString &hints, QWidget *widget) { + QString openDir, strPrevOpen; + QStringList openNames; + QFileDialog fileDialog(widget); + + strPrevOpen = (config_->load(userConfig) ? config_->getItemValue(strSection, strOpen) : "./"); + + QString realHints = (hints.isEmpty() ? "*" : hints); + QString realTitle = (title.isEmpty() ? "Choose files to open" : title); + openNames = fileDialog.getOpenFileNames(widget, realTitle, strPrevOpen, realHints); + + if (!openNames.isEmpty() && !openNames.at(0).isEmpty()) { + openDir = QFileInfo(openNames.at(0)).absolutePath(); + config_->setItemValue(strSection, strOpen, openDir); + config_->save(userConfig); + } + + return openNames; +} + +QString FQTermFileDialog::getExistingDirectory(const QString &title, const QString &hints, QWidget *widget) { + + QString strPrevOpen; + QFileDialog fileDialog(widget); + + if (hints.isEmpty()) { + strPrevOpen = (config_->load(userConfig) ? config_->getItemValue(strSection, strOpen) : "./"); + } else { + strPrevOpen = hints; + } + + QString realTitle = (title.isEmpty() ? "Open a directory" : title); + QString dir = fileDialog.getExistingDirectory(widget, + realTitle, + strPrevOpen, + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + if (!dir.isEmpty()) { + config_->setItemValue(strSection, strOpen, QFileInfo(dir).absolutePath()); + config_->save(userConfig); + } + + return dir; +} + +} // namespace FQTerm diff --git a/src/common/fqterm_filedialog.h b/src/common/fqterm_filedialog.h new file mode 100644 index 0000000..5248ffd --- /dev/null +++ b/src/common/fqterm_filedialog.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_FILEDIALOG_H +#define FQTERM_FILEDIALOG_H + +#include +#include + +namespace FQTerm { + +class FQTermConfig; + +class FQTermFileDialog: public QFileDialog { +public: + FQTermFileDialog(FQTermConfig *config, QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~FQTermFileDialog(); + + QString getSaveName(const QString &filename, const QString &hints, QWidget *widget = 0); + QString getOpenName(const QString &title, const QString &hints, QWidget *widget = 0); + QStringList getOpenNames(const QString &title, const QString &hints, QWidget *widget = 0); + QString getExistingDirectory(const QString &title, const QString &hints, QWidget *widget = 0); + +private: + QString strSection, strSave, strOpen; + FQTermConfig *config_; + QString configDir, userConfig; +}; + +} // name space FQTerm + +#endif // FQTERM_FILEEDIALOG_H diff --git a/src/common/fqterm_font.cpp b/src/common/fqterm_font.cpp new file mode 100644 index 0000000..f2dcfbd --- /dev/null +++ b/src/common/fqterm_font.cpp @@ -0,0 +1,261 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "fqterm_trace.h" +#include "fqterm_font.h" +#include "fqterm_path.h" +#include "fqterm_config.h" + +using namespace std; + +namespace FQTerm { + +namespace Font { + +enum Language{US_ENGLISH = 0, + SIMPLIFIED_CHINESE, + LANGUAGE_COUNT }; + +QString getLanguageName(Language lang) { + switch (lang){ + case US_ENGLISH: + return "en_US"; + case SIMPLIFIED_CHINESE: + return "zh_CN"; + default: + return "C"; + } +} + +Language getLanguageByName(QString langName) { + if (langName == "zh_CN") { + return SIMPLIFIED_CHINESE; + } + if (langName == "en_US") { + return US_ENGLISH; + } + return LANGUAGE_COUNT; +} + +} // namespace Language + +typedef set LanguageSet; +typedef map > FontLanguagesList; + +typedef map > FontSets; + +// This function will be called only once. +static const FontSets &getPreferedFontSets() { + static FontSets font_sets; + const QString &res_path = getPath(RESOURCE); + + QString filename = res_path + "default_font.conf"; + + if (!QFile::exists(filename)) { + filename = res_path + "/dict/" + "default_font.conf"; + } + + + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + FQ_TRACE("font", 0) << "Failed to open the default font configurations file:" + << filename; + return font_sets; + } + + QTextStream is; + is.setDevice(&file); + is.setCodec(QTextCodec::codecForName("UTF-8")); + +#if defined(WIN32) + QString expected_section = "Windows"; +#elif defined(__APPLE__) + QString expected_section = "Apple"; +#else + QString expected_section = "Linux"; +#endif + + QString line; + + QString current_section; + while (!is.atEnd()) { + line = is.readLine().trimmed(); + if (line.isEmpty() || line[0] == '#') { + continue; + } + + if (line.left(1) == "[" && line.right(1) == "]") { + current_section = line.mid(1, line.length() - 2); + continue; + } + + if (current_section == expected_section) { + QString en_font = line.section('=', 0, 0).trimmed().toLower(); + QString fonts_for_lang = line.section('=', 1).trimmed(); + + map &font_set = font_sets[en_font]; + + QString lang = fonts_for_lang.section(":", 0, 0).trimmed(); + QString fonts = fonts_for_lang.section(":", 1).trimmed(); + + QStringList font_list = fonts.split(",", QString::SkipEmptyParts); + + for (int i = 0; i < font_list.size(); ++i) { + font_list[i] = font_list[i].trimmed(); + } + + font_set[Font::getLanguageByName(lang)] = font_list; + } + } + + return font_sets; +} + +#if 0 +//Not used +static int outputAllSystemFonts(const QStringList &fonts) { + if (isAllowedCategory("font", 9)) { + for (int i = 0; i < fonts.size(); ++i) { + FQ_TRACE("font", 9) << "Found a font: " + << (QFontInfo(QFont(fonts.at(i))).fixedPitch() ? + "fixed-pitch " : "variable-pitch ") + << fonts.at(i); + } + } + return 0; +} +#endif + +static QStringList &getSystemFontFamilies() { + static QStringList list = QFontDatabase().families(); + // static int tmp = outputAllSystemFonts(list); + + return list; +} + +static FontSets &getUserConfigFontSets() { + static FontSets font_sets = getPreferedFontSets(); + return font_sets; +} + +static QString getEnglishFontFamily() { + static const QStringList &families = getSystemFontFamilies(); + static const FontSets &font_sets = getUserConfigFontSets(); + static QString en_font_name; + + if (!en_font_name.isEmpty()) { + return en_font_name; + } + + FontSets::const_iterator it = font_sets.find("default"); + if (it != font_sets.end()) { + map::const_iterator itt + = it->second.find(Font::US_ENGLISH); + if (itt != it->second.end()) { + for (int i = 0; i < itt->second.size(); ++i) { + const QString &font = itt->second[i]; + if (families.contains(font)) { + en_font_name = font; + break; + } + } + } + } + + return en_font_name; +} + + +static QString getFontFamilyForLang(Font::Language lang) { + static const QStringList &families = getSystemFontFamilies(); + static const FontSets &font_sets = getUserConfigFontSets(); + + const QString en_font_name = getEnglishFontFamily(); + + if (lang == Font::US_ENGLISH) { + return en_font_name; + } + + FontSets::const_iterator it = font_sets.find(en_font_name.toLower()); + if (it != font_sets.end()) { + map::const_iterator itt + = it->second.find(lang); + if (itt != it->second.end()) { + for (int i = 0; i < itt->second.size(); ++i) { + const QString &font = itt->second[i]; + if (families.contains(font)) { + return font; + } else { + FQ_TRACE("font", 5) << "Font " << font << " for " + << en_font_name << " not found."; + } + } + } + } else { + FQ_TRACE("font", 3) << "NO fontset for " << en_font_name << " found."; + } + + return en_font_name; +} + +QString getDefaultFontFamilyForLanguage(bool isEnglish) { + Font::Language lang = isEnglish ? Font::US_ENGLISH : Font::SIMPLIFIED_CHINESE; + + static map langs_fonts_list; + + map::iterator it = langs_fonts_list.find(lang); + if (it == langs_fonts_list.end()) { + langs_fonts_list.insert( + make_pair(lang, getFontFamilyForLang(lang))); + it = langs_fonts_list.find(lang); + + FQ_TRACE("font", 3) << "Defaut font for " + << Font::getLanguageName(lang) + << " is: " + << it->second + << " (" << it->second.size() << ")"; + } + + return it->second; +} + +#if 0 +//Not used. +static Font::Language getCurrentSystemLanguage() { + if (QLocale::system().language() == QLocale::Chinese) { + return Font::SIMPLIFIED_CHINESE; + } + + return Font::US_ENGLISH; +} +#endif +} // namespace FQTerm diff --git a/src/common/fqterm_font.h b/src/common/fqterm_font.h new file mode 100644 index 0000000..7d28ffb --- /dev/null +++ b/src/common/fqterm_font.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_FONT_H +#define FQTERM_FONT_H + +#include + +#include "fqterm_param.h" + +namespace FQTerm { + +QString getDefaultFontFamilyForLanguage(bool isEnglish); + +} // namespace FQTerm + +#endif // FQTERM_FONT_H diff --git a/src/common/fqterm_param.cpp b/src/common/fqterm_param.cpp new file mode 100644 index 0000000..9490bdd --- /dev/null +++ b/src/common/fqterm_param.cpp @@ -0,0 +1,274 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_param.h" +#include "fqterm_font.h" + +namespace FQTerm { + +FQTermParam::FQTermParam() { + name_ = "NEW SMTH"; + hostAddress_ = "newsmth.net"; + port_ = 23; + hostType_ = 0; // 0--BBS 1--*NIX + isAutoLogin_ = false; + preLoginCommand_ = ""; + userName_ = ""; + password_ = ""; + postLoginCommand_ = ""; + // Display + serverEncodingID_ = 0; + isFontAutoFit_ = 1; + isAlwaysHighlight_ = 0; + isAnsiColor_ = 1; + + englishFontName_ = getDefaultFontFamilyForLanguage(true); + englishFontSize_ = 14; + otherFontName_ = getDefaultFontFamilyForLanguage(false); + otherFontSize_ = 14; + alignMode_ = 0; + charSpacing_ = 0; + lineSpacing_ = 0; + //charRatio_ = 0; + + backgroundColor_ = QColor(0, 0, 0); + foregroundColor_ = QColor(198, 195, 198); + schemaFileName_ = ""; + // Terminal + virtualTermType_ = "vt102"; + keyboardType_ = 0; + backspaceType_ = 0; + numColumns_ = 80; + numRows_ = 24; + numScrollLines_ = 240; + cursorType_ = 1; // 0--Block 1--Underline 2--I Type + escapeString_ = "^[^[["; + // Connection + proxyType_ = 0; // 0--None 1--Wingate 2--SOCKS4 3--SOCKS5 4--HTTP + proxyHostName_ = ""; + proxyPort_ = 0; + isAuthentation_ = false; + proxyUserName_ = ""; + proxyPassword_ = ""; + protocolType_ = 0; // 0--Telnet 1--SSH1 2--SSH2 + sshUserName_ = ""; + sshPassword_ = ""; + // Misc + maxIdleSeconds_ = 120; + replyKeyCombination_ = "^Z"; + antiIdleMessage_ = "^@"; + isAntiIdle_ = true; + isAutoReply_ = false; + autoReplyMessage_ = "(FQTerm) Sorry, I am not around"; + isAutoReconnect_ = false; + reconnectInterval_ = 3; + retryTimes_ = 0; + isAutoCloseWin_ = false; + isAutoLoadScript_ = false; + enableZmodem_ = true; + autoLoadedScriptFileName_ = ""; + isBeep_ = true; + isBuzz_ = false; + + // Mouse + isSupportMouse_ = true; + // Mouse + menuType_ = 2; + menuColor_ = QColor(0, 65, 132); + + isColorCopy_ = false; + isRectSelect_ = false; + isAutoCopy_ = true; + isAutoWrap_ = false; +} + +FQTermParam::FQTermParam(const FQTermParam ¶m) { + copy(param); +} + +FQTermParam::~FQTermParam(){} + +FQTermParam &FQTermParam::operator = (const FQTermParam ¶m) { + if (this == ¶m) + return *this; + copy(param); + return *this; +} + +void FQTermParam::copy(const FQTermParam& param) { + name_ = param.name_; + hostAddress_ = param.hostAddress_; + port_ = param.port_; + hostType_ = param.hostType_; // 0--BBS 1--*NIX + isAutoLogin_ = param.isAutoLogin_; + preLoginCommand_ = param.preLoginCommand_; + userName_ = param.userName_; + password_ = param.password_; + postLoginCommand_ = param.postLoginCommand_; + // Display + serverEncodingID_ = param.serverEncodingID_; + isFontAutoFit_ = param.isFontAutoFit_; + isAlwaysHighlight_ = param.isAlwaysHighlight_; + isAnsiColor_ = param.isAnsiColor_; + englishFontName_ = param.englishFontName_; + englishFontSize_ = param.englishFontSize_; + otherFontName_ = param.otherFontName_; + otherFontSize_ = param.otherFontSize_; + alignMode_ = param.alignMode_; + charSpacing_ = param.charSpacing_; + lineSpacing_ = param.lineSpacing_; + //charRatio_ = param.charRatio_; + backgroundColor_ = param.backgroundColor_; + foregroundColor_ = param.foregroundColor_; + schemaFileName_ = param.schemaFileName_; + // Terminal + virtualTermType_ = param.virtualTermType_; + keyboardType_ = param.keyboardType_; + backspaceType_ = param.backspaceType_; + numColumns_ = param.numColumns_; + numRows_ = param.numRows_; + numScrollLines_ = param.numScrollLines_; + cursorType_ = param.cursorType_; // 0--Block 1--Underline 2--I Type + escapeString_ = param.escapeString_; // 0--ESC ESC 1--Ctrl+u + // Connection + proxyType_ = param.proxyType_; + // 0--None 1--Wingate 2--SOCKS4 3--SOCKS5 4--HTTP + proxyHostName_ = param.proxyHostName_; + proxyPort_ = param.proxyPort_; + isAuthentation_ = param.isAuthentation_; + proxyUserName_ = param.proxyUserName_; + proxyPassword_ = param.proxyPassword_; + protocolType_ = param.protocolType_; // 0--Telnet 1--SSH1 2--SSH2 + sshUserName_ = param.sshUserName_; + sshPassword_ = param.sshPassword_; + // Misc + maxIdleSeconds_ = param.maxIdleSeconds_; + replyKeyCombination_ = param.replyKeyCombination_; + antiIdleMessage_ = param.antiIdleMessage_; + isAntiIdle_ = param.isAntiIdle_; + isAutoReply_ = param.isAutoReply_; + autoReplyMessage_ = param.autoReplyMessage_; + isAutoReconnect_ = param.isAutoReconnect_; + reconnectInterval_ = param.reconnectInterval_; + retryTimes_ = param.retryTimes_; + isAutoCloseWin_ = param.isAutoCloseWin_; + isAutoLoadScript_ = param.isAutoLoadScript_; + enableZmodem_ = param.enableZmodem_; + autoLoadedScriptFileName_ = param.autoLoadedScriptFileName_; + isBeep_ = param.isBeep_; + isBuzz_ = param.isBuzz_; + + isSupportMouse_ = param.isSupportMouse_; + // Mouse + menuType_ = param.menuType_; + menuColor_ = param.menuColor_; + + isColorCopy_ = param.isColorCopy_; + isRectSelect_ = param.isRectSelect_; + isAutoCopy_ = param.isAutoCopy_; + isAutoWrap_ = param.isAutoWrap_; +} + +bool FQTermParam::operator==(const FQTermParam& param) +{ + if (name_ != param.name_) return false; + if (hostAddress_ != param.hostAddress_) return false; + if (port_ != param.port_) return false; + if (hostType_ != param.hostType_) return false; + if (isAutoLogin_ != param.isAutoLogin_) return false; + if (preLoginCommand_ != param.preLoginCommand_) return false; + if (userName_ != param.userName_) return false; + if (password_ != param.password_) return false; + if (postLoginCommand_ != param.postLoginCommand_) return false; + if (serverEncodingID_ != param.serverEncodingID_) return false; + if (isFontAutoFit_ != param.isFontAutoFit_) return false; + if (isAlwaysHighlight_ != param.isAlwaysHighlight_) return false; + if (isAnsiColor_ != param.isAnsiColor_) return false; + if (englishFontName_ != param.englishFontName_) return false; + if (englishFontSize_ != param.englishFontSize_) return false; + if (otherFontName_ != param.otherFontName_) return false; + if (otherFontSize_ != param.otherFontSize_) return false; + if (alignMode_ != param.alignMode_) return false; + if (charSpacing_ != param.charSpacing_) return false; + if (lineSpacing_ != param.lineSpacing_) return false; + if (backgroundColor_ != param.backgroundColor_) return false; + if (foregroundColor_ != param.foregroundColor_) return false; + if (schemaFileName_ != param.schemaFileName_) return false; + if (virtualTermType_ != param.virtualTermType_) return false; + if (keyboardType_ != param.keyboardType_) return false; + if (backspaceType_ != param.backspaceType_) return false; + if (numColumns_ != param.numColumns_) return false; + if (numRows_ != param.numRows_) return false; + if (numScrollLines_ != param.numScrollLines_) return false; + if (cursorType_ != param.cursorType_) return false; + if (escapeString_ != param.escapeString_) return false; + if (proxyType_ != param.proxyType_) return false; + if (proxyHostName_ != param.proxyHostName_) return false; + if (proxyPort_ != param.proxyPort_) return false; + if (isAuthentation_ != param.isAuthentation_) return false; + if (proxyUserName_ != param.proxyUserName_) return false; + if (proxyPassword_ != param.proxyPassword_) return false; + if (protocolType_ != param.protocolType_) return false; + if (sshUserName_ != param.sshUserName_) return false; + if (sshPassword_ != param.sshPassword_) return false; + if (maxIdleSeconds_ != param.maxIdleSeconds_) return false; + if (replyKeyCombination_ != param.replyKeyCombination_) return false; + if (antiIdleMessage_ != param.antiIdleMessage_) return false; + if (isAntiIdle_ != param.isAntiIdle_) return false; + if (isAutoReply_ != param.isAutoReply_) return false; + if (autoReplyMessage_ != param.autoReplyMessage_) return false; + if (isAutoReconnect_ != param.isAutoReconnect_) return false; + if (reconnectInterval_ != param.reconnectInterval_) return false; + if (retryTimes_ != param.retryTimes_) return false; + if (isAutoCloseWin_ != param.isAutoCloseWin_) return false; + if (isAutoLoadScript_ != param.isAutoLoadScript_) return false; + if (enableZmodem_ != param.enableZmodem_) return false; + if (isBuzz_ != param.isBuzz_) return false; + if (isBeep_ != param.isBeep_) return false; + if (isSupportMouse_ != param.isSupportMouse_) return false; + if (autoLoadedScriptFileName_ != param.autoLoadedScriptFileName_) return false; + if (menuType_ != param.menuType_) return false; + if (isColorCopy_ != param.isColorCopy_) return false; + if (isRectSelect_ != param.isRectSelect_) return false; + if (isAutoCopy_ != param.isAutoCopy_) return false; + if (isAutoWrap_ != param.isAutoWrap_) return false; + return true; +} + +QString FQTermParam::getLanguageName(bool isEnglish, bool translate /* = true */) +{ + if (isEnglish) { + return QString(translate ? QObject::tr("&English") : "English"); + } + return QString(translate ? QObject::tr("&Non-English") : "Non-English"); +} + +const FQTermParam& FQTermParam::getFQBBSParam() { + static bool inited = false; + static FQTermParam param; + if (!inited) { + param.name_ = "FQTermHelp"; + param.hostAddress_ = "127.0.0.1"; + param.port_ = 35172; + param.serverEncodingID_ = 2; + } + return param; +} +} // namespace FQTerm diff --git a/src/common/fqterm_param.h b/src/common/fqterm_param.h new file mode 100644 index 0000000..ef44f59 --- /dev/null +++ b/src/common/fqterm_param.h @@ -0,0 +1,221 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_PARAM_H +#define FQTERM_PARAM_H + +#include +#include + +namespace FQTerm { + + +//The FQTerm Pref also contains global settings. +//TODO: move all global settings into FQTermPref. +struct FQTermPref { + static FQTermPref* getInstance() + { + //Though Singleton, I didn't define a ctor and make it private + //Why? + //I'm lazy. + static FQTermPref* pThis = new FQTermPref(); + return pThis; + } + int displayOffset_; + int vsetting_; + int imeEncodingID_; // 0--GBK 1--BIG5 + int widthToWrapWord_; + // bool bSmartWW; + bool isWheelSupported_; + bool openWarnOnClose_; + bool openTabBlinking_; + bool replyENQ_; + // bool bLogMsg; + QString httpBrowser_; + int openBeep_; + QString beepSoundFileName_; + int beepMethodID_; + QString beepPlayerName_; + bool openUrlCheck_; + // bool bAutoCopy; + bool openAntiAlias_; + bool openMinimizeToTray_; + bool needClearZmodemPoolOnClose_; + bool useStyleSheet_; + QString styleSheetFile_; + QString zmodemDir_; + QString poolDir_; + QString imageViewerName_; + QString externalEditor_; + QString externalEditorArg_; + QString searchEngine_; + //global settings + bool isBossColor_; + bool isAnsciiEnhance_; + QString escapeString_; + int termScrollBarPosition_; // 0--hide 1--LEFT 2--RIGHT + bool runServer_; +}; + + +class FQTermParam { + public: + FQTermParam(); + FQTermParam(const FQTermParam &); + ~FQTermParam(); + + FQTermParam &operator = (const FQTermParam &); + + bool operator==(const FQTermParam &); + + static const FQTermParam& getFQBBSParam(); + static QString getLanguageName(bool isEnglish, bool translate = true); + // General + // Name + QString name_; + // Address + QString hostAddress_; + // Port + quint16 port_; + // Host Type + int hostType_; // 0--BBS 1--*NIX + // Auto Login + bool isAutoLogin_; + // Pre Login + QString preLoginCommand_; + // User Name + QString userName_; + // Password + QString password_; + // Post Login + QString postLoginCommand_; + + // Display + // {FQTERM_ENCODING_GBK = 0, FQTERM_ENCODING_BIG5 = 1, FQTERM_ENCODING_UTF8 = 2, FQTERM_ENCODING_HKSCS = 3, FQTERM_ENCODING_UAO = 4}; + int serverEncodingID_; + + // 0 - keep column/row, adjust font + // 1 - keep font, adjust column/row + // 2 - keep column/row/font + int isFontAutoFit_; + // Always Highlight + bool isAlwaysHighlight_; + // ANSI Color + bool isAnsiColor_; + // Font Name + QString englishFontName_; + QString otherFontName_; + // Font Size + int englishFontSize_; + int otherFontSize_; + + int alignMode_; //how to align english char/chinese char in vertical direction 0 -- vcenter, 1 -- bottom 2 -- top + int charSpacing_; //additional char spacing for English char. + int lineSpacing_; //additional line spacing + //int charRatio_; //height of english char / width of english char + // Background Color + QColor backgroundColor_; + // Foreground Color + QColor foregroundColor_; + // Schema File + QString schemaFileName_; + + // Terminal + // Terminal Type + QString virtualTermType_; + // Key Type + int keyboardType_; // 0--BBS 1--XTERM 2--VT100 + // Columns & Rows + int numColumns_, numRows_; + // Scroll Lines + int numScrollLines_; + // Curor Type + int cursorType_; // 0--Block 1--Underline 2--I Type + // the esacpe string + QString escapeString_; + + //Keyboard + int backspaceType_; //0--^H 1--^?(127) + + + // Connection + // Proxy Type + int proxyType_; // 0--None 1--Wingate 2--SOCKS4 3--SOCKS5 4--HTTP + // Address + QString proxyHostName_; + // Port + quint16 proxyPort_; + // Authentation + bool isAuthentation_; + // User Name + QString proxyUserName_; + // Password + QString proxyPassword_; + // Protocol + int protocolType_; // 0--Telnet 1--SSH1 2--SSH2 3--Local + // User Name + QString sshUserName_; + // Password + QString sshPassword_; + // Misc + // Max Idle Time %s + int maxIdleSeconds_; + QString replyKeyCombination_; + // Send When Idle + QString antiIdleMessage_; + bool isAntiIdle_; + // wether autoreply + bool isAutoReply_; + // Auto Reply Messages + QString autoReplyMessage_; + // Reconnect When Disconnected By Host + bool isAutoReconnect_; + // Reconnect Interval (s) + int reconnectInterval_; + // Retry times + int retryTimes_; // -1 -- infinite + // Close Window When Disconnected By Host + bool isAutoCloseWin_; + + bool isBeep_; + bool isBuzz_; + + // Mouse + bool isSupportMouse_; + int menuType_; // 0--underline 1--reverse 2--color + QColor menuColor_; + // Script + bool isAutoLoadScript_; + QString autoLoadedScriptFileName_; + // Zmodem + bool enableZmodem_; + + bool isColorCopy_; + bool isRectSelect_; + bool isAutoCopy_; + bool isAutoWrap_; + + private: + void copy(const FQTermParam& parm); +}; + +} // namespace FQTerm + +#endif // FQTERM_PARAM_H diff --git a/src/common/fqterm_path.cpp b/src/common/fqterm_path.cpp new file mode 100644 index 0000000..88ee385 --- /dev/null +++ b/src/common/fqterm_path.cpp @@ -0,0 +1,601 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifdef WIN32 +#include +#include +#endif // WIN32 + +#include +#include +#include +#include + +#include "fqterm_config.h" +#include "fqterm_trace.h" +#include "fqterm_param.h" +#include "fqterm_path.h" +#include "fqterm_font.h" + +namespace FQTerm { + +static QString getUserDataDir(); +static QString getInstallPrefix(); +static QString getResourceDir(const QString &prefix); + +const QString &getPath(PathCategory category) { + static QString null_dir = ""; + static QString user_config = getUserDataDir(); + static QString prefix = getInstallPrefix(); + static QString resource = getResourceDir(prefix); + + switch (category) { + case RESOURCE: + return resource; + break; + case USER_CONFIG: + return user_config; + break; + } + return null_dir; +} + +void clearDir(const QString &path) { + QDir dir(path); + if (dir.exists()) { + const QFileInfoList list = dir.entryInfoList(); + //QFileInfoListIterator it( *list ); + //QFileInfo *fi; + foreach(QFileInfo fi, list) { + if (fi.isFile()) { + dir.remove(fi.fileName()); + } + } + } +} + +bool checkPath(const QString &path) { + QDir dir(path); + if (!dir.exists()) { + if (!dir.mkpath(path)) { + FQ_TRACE("path", 0) << "Failed to create directory " << path; + return false; + } + } + return true; +} + +bool checkFile(const QString &src, const QString &dst) { + if (QFile(dst).exists()) { + return true; + } + + if (!QFile::copy(src, dst)) { + FQ_TRACE("path", 0) << "Failed to copy a file from " << src + << " to " << dst; + return false; + } + + FQ_TRACE("path", 5) << "A file copied from " << src + << " to " << dst; + + if (!QFile::setPermissions(dst, QFile::ReadOwner | QFile::WriteOwner)) { + FQ_TRACE("path", 0) << "Failed to change access attributs of "<< dst + << " to make only the owner have rights to " + << "read/write it."; + return false; + } + + return true; +} + +bool iniSettings() { + if (!checkPath(getPath(USER_CONFIG))) { + return false; + } + + if (!checkFile(getPath(RESOURCE) + "userconf/fqterm.cfg.orig", + getPath(USER_CONFIG) + "fqterm.cfg")) { + return false; + } + + if (!checkFile(getPath(RESOURCE) + "userconf/address.cfg.orig", + getPath(USER_CONFIG) + "address.cfg")) { + return false; + } + + if (!checkFile(getPath(RESOURCE) + "userconf/language.cfg.orig", + getPath(USER_CONFIG) + "language.cfg")) { + return false; + } + + //Copy schema files + if (checkPath(getPath(USER_CONFIG) + "schema")) { + checkFile(getPath(RESOURCE) + "schema/default.schema", + getPath(USER_CONFIG) + "schema/default.schema"); + + checkFile(getPath(RESOURCE) + "schema/Linux.schema", + getPath(USER_CONFIG) + "schema/Linux.schema"); + + checkFile(getPath(RESOURCE) + "schema/Softness.schema", + getPath(USER_CONFIG) + "schema/Softness.schema"); + + checkFile(getPath(RESOURCE) + "schema/VIM.schema", + getPath(USER_CONFIG) + "schema/VIM.schema"); + + checkFile(getPath(RESOURCE) + "schema/XTerm.schema", + getPath(USER_CONFIG) + "schema/XTerm.schema"); + } + + + //read settings from fqterm.cfg + FQTermConfig *conf = new FQTermConfig(getPath(USER_CONFIG) + "fqterm.cfg"); + + //set font + QString family = (conf->getItemValue("global", "font")); + + QString pointsize = conf->getItemValue("global", "pointsize"); + QString pixelsize = conf->getItemValue("global", "pixelsize"); + if (!family.isEmpty()) { + QFont font(family); + if (pointsize.toInt() > 0) { + font.setPointSize(pointsize.toInt()); + } + if (pixelsize.toInt() > 0) { + font.setPixelSize(pixelsize.toInt()); + } + QString openAntiAlias_ = conf->getItemValue("global", "antialias"); + if (openAntiAlias_ != "0") { + font.setStyleStrategy(QFont::PreferAntialias); + } + qApp->setFont(font); + } + + // zmodem and pool directory + QString pathZmodem = conf->getItemValue("preference", "zmodem"); + if (pathZmodem.isEmpty()) { + pathZmodem = getPath(USER_CONFIG) + "zmodem"; + } + + if (!checkPath(pathZmodem)) { + return false; + } + + QString pathPool = conf->getItemValue("preference", "pool"); + + if (pathPool.isEmpty()) { + pathPool = getPath(USER_CONFIG) + "pool/"; + } + + if (pathPool.right(1) != "/") { + pathPool.append('/'); + } + + QString pathCache = pathPool + "shadow-cache/"; + + if (!checkPath(pathPool) || !checkPath(pathCache)) { + return false; + } + + delete conf; + return true; +} + +void checkHelpExists(FQTermConfig* pConf) { + QString strTmp = pConf->getItemValue("bbs list", "num"); + int bbsCount = strTmp.toInt(); + + QString strSection; + + for (int i = 0; i < bbsCount; i++) { + strSection.sprintf("bbs %d", i); + strTmp = pConf->getItemValue(strSection, "name"); + if (strTmp == "FQTermHelp") + return; + } + pConf->setItemValue("bbs list", "num", QString("%1").arg(bbsCount + 1)); + saveAddress(pConf, bbsCount, FQTermParam::getFQBBSParam()); + pConf->save(getPath(USER_CONFIG) + "address.cfg"); +} + +void loadNameList(FQTermConfig *pConf, QStringList &listName) { + QString strTmp = pConf->getItemValue("bbs list", "num"); + + QString strSection; + + for (int i = 0; i < strTmp.toInt(); i++) { + strSection.sprintf("bbs %d", i); + listName.append(pConf->getItemValue(strSection, "name")); + } +} + +bool loadAddress(FQTermConfig *pConf, int n, FQTermParam ¶m) { + QString strTmp, strSection; + if (n < 0) { + strSection = "default"; + } else { + strSection.sprintf("bbs %d", n); + } + + if (!pConf->hasSection(strSection)) + return false; + + // check if larger than existence + strTmp = pConf->getItemValue("bbs list", "num"); + if (n >= strTmp.toInt()) { + return false; + } + param.name_ = pConf->getItemValue(strSection, "name"); + param.hostAddress_ = pConf->getItemValue(strSection, "addr"); + strTmp = pConf->getItemValue(strSection, "port"); + param.port_ = strTmp.toUShort(); + strTmp = pConf->getItemValue(strSection, "hosttype"); + param.hostType_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "autologin"); + param.isAutoLogin_ = (strTmp != "0"); + param.preLoginCommand_ = pConf->getItemValue(strSection, "prelogin"); + param.userName_ = pConf->getItemValue(strSection, "user"); + param.password_ = pConf->getItemValue(strSection, "password"); + param.postLoginCommand_ = pConf->getItemValue(strSection, "postlogin"); + + strTmp = pConf->getItemValue(strSection, "bbscode"); + param.serverEncodingID_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "autofont"); + if (strTmp == "0") { + param.isFontAutoFit_ = 0; + } else if (strTmp == "2") { + param.isFontAutoFit_ = 2; + } else { + param.isFontAutoFit_ = 1; + } + strTmp = pConf->getItemValue(strSection, "alwayshighlight"); + param.isAlwaysHighlight_ = (strTmp != "0"); + strTmp = pConf->getItemValue(strSection, "ansicolor"); + param.isAnsiColor_ = (strTmp != "0"); + QString language; + QString font_name; + QString font_size; + language = FQTermParam::getLanguageName(true, false); + font_name = pConf->getItemValue(strSection, language + "fontname"); + font_size = pConf->getItemValue(strSection, language + "fontsize"); + if (!font_name.isEmpty()) { + param.englishFontName_ = font_name; + } + if (!font_size.isEmpty()) { + param.englishFontSize_ = font_size.toInt(); + } + //FIXME: Should be removed in next release!!!!! (Since 0.9.7) + if (font_name.isEmpty()) { + language = FQTermParam::getLanguageName(true); + font_name = pConf->getItemValue(strSection, language + "fontname"); + if (!font_name.isEmpty()) { + param.englishFontName_ = font_name; + } + } + + language = FQTermParam::getLanguageName(false, false); + font_name = pConf->getItemValue(strSection, language + "fontname"); + font_size = pConf->getItemValue(strSection, language + "fontsize"); + if (!font_name.isEmpty()) { + param.otherFontName_ = font_name; + } + if (!font_size.isEmpty()) { + param.otherFontSize_ = font_size.toInt(); + } + + //FIXME: Should be removed in next release!!!!! + if (font_name.isEmpty()) { + language = FQTermParam::getLanguageName(false); + font_name = pConf->getItemValue(strSection, language + "fontname"); + if (!font_name.isEmpty()) { + param.englishFontName_ = font_name; + } + } + + param.foregroundColor_.setNamedColor(pConf->getItemValue(strSection, "fgcolor")); + param.backgroundColor_.setNamedColor(pConf->getItemValue(strSection, "bgcolor")); + param.schemaFileName_ = pConf->getItemValue(strSection, "schemafile"); + + param.virtualTermType_ = pConf->getItemValue(strSection, "termtype"); + strTmp = pConf->getItemValue(strSection, "keytype"); + param.keyboardType_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "backspacetype"); + param.backspaceType_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "column"); + param.numColumns_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "row"); + param.numRows_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "scroll"); + param.numScrollLines_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "cursor"); + param.cursorType_ = strTmp.toInt(); + param.escapeString_ = pConf->getItemValue(strSection, "escape"); + + strTmp = pConf->getItemValue(strSection, "proxytype"); + param.proxyType_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "proxyauth"); + param.isAuthentation_ = (strTmp != "0"); + param.proxyHostName_ = pConf->getItemValue(strSection, "proxyaddr"); + strTmp = pConf->getItemValue(strSection, "proxyport"); + param.proxyPort_ = strTmp.toInt(); + param.proxyUserName_ = pConf->getItemValue(strSection, "proxyuser"); + param.proxyPassword_ = pConf->getItemValue(strSection, "proxypassword"); + strTmp = pConf->getItemValue(strSection, "protocol"); + param.protocolType_ = strTmp.toInt(); + param.sshUserName_ = pConf->getItemValue(strSection, "sshuser"); + param.sshPassword_ = pConf->getItemValue(strSection, "sshpassword"); + + strTmp = pConf->getItemValue(strSection, "maxidle"); + param.maxIdleSeconds_ = strTmp.toInt(); + param.replyKeyCombination_ = pConf->getItemValue(strSection, "replykey"); + if (param.replyKeyCombination_.isNull()) { + Q_ASSERT(false); + } + + param.antiIdleMessage_ = pConf->getItemValue(strSection, "antiidlestring"); + strTmp = pConf->getItemValue(strSection, "isantiidle"); + param.isAntiIdle_ = (strTmp != "0"); + param.autoReplyMessage_ = pConf->getItemValue(strSection, "autoreply"); + strTmp = pConf->getItemValue(strSection, "bautoreply"); + param.isAutoReply_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "reconnect"); + param.isAutoReconnect_ = (strTmp != "0"); + strTmp = pConf->getItemValue(strSection, "interval"); + param.reconnectInterval_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "retrytimes"); + param.retryTimes_ = strTmp.toInt(); + + strTmp = pConf->getItemValue(strSection, "autoclosewin"); + param.isAutoCloseWin_ = (strTmp == "1"); + + strTmp = pConf->getItemValue(strSection, "alignmode"); + param.alignMode_ = strTmp.toInt(); + + + strTmp = pConf->getItemValue(strSection, "charspacing"); + param.charSpacing_ = strTmp.toInt(); + + strTmp = pConf->getItemValue(strSection, "linespacing"); + param.lineSpacing_ = strTmp.toInt(); + + strTmp = pConf->getItemValue(strSection, "loadscript"); + param.isAutoLoadScript_ = (strTmp != "0"); + param.autoLoadedScriptFileName_ = pConf->getItemValue(strSection, "scriptfile"); + + strTmp = pConf->getItemValue(strSection, "enablezmodem"); + param.enableZmodem_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "isbeep"); + param.isBeep_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "isbuzz"); + param.isBuzz_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "ismouse"); + param.isSupportMouse_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "menutype"); + param.menuType_ = strTmp.toInt(); + param.menuColor_.setNamedColor(pConf->getItemValue(strSection, "menucolor")); + + param.isColorCopy_ = (pConf->getItemValue(strSection, "colorcopy") != "0"); + param.isAutoCopy_ = (pConf->getItemValue(strSection, "autocopy") != "0"); + param.isRectSelect_ = (pConf->getItemValue(strSection, "rectselect") != "0"); + param.isAutoWrap_ = (pConf->getItemValue(strSection, "autowrap" ) == "1"); + + return true; +} + +void saveAddress(FQTermConfig *pConf, int n, const FQTermParam ¶m) { + QString strTmp, strSection; + if (n < 0) { + strSection = "default"; + } else { + strSection.sprintf("bbs %d", n); + } + + pConf->setItemValue(strSection, "name", param.name_); + pConf->setItemValue(strSection, "addr", param.hostAddress_); + strTmp.setNum(param.port_); + pConf->setItemValue(strSection, "port", strTmp); + strTmp.setNum(param.hostType_); + pConf->setItemValue(strSection, "hosttype", strTmp); + pConf->setItemValue(strSection, "autologin", param.isAutoLogin_ ? "1" : "0"); + pConf->setItemValue(strSection, "prelogin", param.preLoginCommand_); + pConf->setItemValue(strSection, "user", param.userName_); + pConf->setItemValue(strSection, "password", param.password_); + pConf->setItemValue(strSection, "postlogin", param.postLoginCommand_); + + strTmp.setNum(param.serverEncodingID_); + pConf->setItemValue(strSection, "bbscode", strTmp); + pConf->setItemValue(strSection, "autofont", strTmp.setNum(param.isFontAutoFit_)); + pConf->setItemValue(strSection, "alwayshighlight", param.isAlwaysHighlight_ ? + "1" : "0"); + pConf->setItemValue(strSection, "ansicolor", param.isAnsiColor_ ? "1" : "0"); + + pConf->setItemValue(strSection, FQTermParam::getLanguageName(true, false) + "fontname", param.englishFontName_); + strTmp.setNum(param.englishFontSize_); + pConf->setItemValue(strSection, FQTermParam::getLanguageName(true, false) + "fontsize", strTmp); + + pConf->setItemValue(strSection, FQTermParam::getLanguageName(false, false) + "fontname", param.otherFontName_); + strTmp.setNum(param.otherFontSize_); + pConf->setItemValue(strSection, FQTermParam::getLanguageName(false, false) + "fontsize", strTmp); + + pConf->setItemValue(strSection, "alignmode", strTmp.setNum(param.alignMode_)); + pConf->setItemValue(strSection, "charspacing", strTmp.setNum(param.charSpacing_)); + pConf->setItemValue(strSection, "linespacing", strTmp.setNum(param.lineSpacing_)); + + pConf->setItemValue(strSection, "bgcolor", param.backgroundColor_.name()); + pConf->setItemValue(strSection, "fgcolor", param.foregroundColor_.name()); + + pConf->setItemValue(strSection, "schemafile", param.schemaFileName_); + + pConf->setItemValue(strSection, "termtype", param.virtualTermType_); + strTmp.setNum(param.keyboardType_); + pConf->setItemValue(strSection, "keytype", strTmp); + strTmp.setNum(param.backspaceType_); + pConf->setItemValue(strSection, "backspacetype", strTmp); + strTmp.setNum(param.numColumns_); + pConf->setItemValue(strSection, "column", strTmp); + strTmp.setNum(param.numRows_); + pConf->setItemValue(strSection, "row", strTmp); + strTmp.setNum(param.numScrollLines_); + pConf->setItemValue(strSection, "scroll", strTmp); + strTmp.setNum(param.cursorType_); + pConf->setItemValue(strSection, "cursor", strTmp); + pConf->setItemValue(strSection, "escape", param.escapeString_); + + strTmp.setNum(param.proxyType_); + pConf->setItemValue(strSection, "proxytype", strTmp); + pConf->setItemValue(strSection, "proxyauth", param.isAuthentation_ ? "1" : "0"); + pConf->setItemValue(strSection, "proxyaddr", param.proxyHostName_); + strTmp.setNum(param.proxyPort_); + pConf->setItemValue(strSection, "proxyport", strTmp); + pConf->setItemValue(strSection, "proxyuser", param.proxyUserName_); + pConf->setItemValue(strSection, "proxypassword", param.proxyPassword_); + strTmp.setNum(param.protocolType_); + pConf->setItemValue(strSection, "protocol", strTmp); + pConf->setItemValue(strSection, "sshuser", param.sshUserName_); + pConf->setItemValue(strSection, "sshpassword", param.sshPassword_); + + strTmp.setNum(param.maxIdleSeconds_); + pConf->setItemValue(strSection, "maxidle", strTmp); + pConf->setItemValue(strSection, "replykey", param.replyKeyCombination_); + pConf->setItemValue(strSection, "antiidlestring", param.antiIdleMessage_); + pConf->setItemValue(strSection, "isantiidle", param.isAntiIdle_?"1" : "0"); + pConf->setItemValue(strSection, "bautoreply", param.isAutoReply_ ? "1" : "0"); + pConf->setItemValue(strSection, "autoreply", param.autoReplyMessage_); + pConf->setItemValue(strSection, "reconnect", param.isAutoReconnect_? "1" : "0"); + strTmp.setNum(param.reconnectInterval_); + pConf->setItemValue(strSection, "interval", strTmp); + strTmp.setNum(param.retryTimes_); + pConf->setItemValue(strSection, "retrytimes", strTmp); + pConf->setItemValue(strSection, "autoclosewin", param.isAutoCloseWin_? "1" : "0"); + + pConf->setItemValue(strSection, "loadscript", param.isAutoLoadScript_ ? "1" : "0"); + pConf->setItemValue(strSection, "scriptfile", param.autoLoadedScriptFileName_); + + pConf->setItemValue(strSection, "enablezmodem", param.enableZmodem_? "1" : "0"); + + pConf->setItemValue(strSection, "isbeep", param.isBeep_? "1" : "0"); + pConf->setItemValue(strSection, "isbuzz", param.isBuzz_? "1" : "0"); + pConf->setItemValue(strSection, "ismouse", param.isSupportMouse_? "1" : "0"); + + strTmp.setNum(param.menuType_); + pConf->setItemValue(strSection, "menutype", strTmp); + pConf->setItemValue(strSection, "menucolor", param.menuColor_.name()); + + pConf->setItemValue(strSection, "colorcopy", param.isColorCopy_? "1" : "0"); + pConf->setItemValue(strSection, "autocopy", param.isAutoCopy_? "1" : "0"); + pConf->setItemValue(strSection, "rectselect", param.isRectSelect_? "1" : "0"); + pConf->setItemValue(strSection, "autowrap", param.isAutoWrap_?"1":"0"); + +} + +static QString getResourceDir(const QString &prefix) { + QString res; + + std::string fqterm_resource; + + char *p = NULL; + if ((p = getenv("FQTERM_RESOURCE")) != NULL) + fqterm_resource = p; + + if (fqterm_resource.size() == 0) { +#if defined(WIN32) + res = prefix; +#elif defined(__APPLE__) + res = prefix + "../Resources/"; +#else + res = prefix + "share/FQTerm/"; +#endif + } else { + res = QString::fromLocal8Bit(fqterm_resource.c_str()); + } + + if (res[res.size() - 1] != '/') + res += '/'; + + return res; +} + +static QString getInstallPrefix() { + QString res; + + std::string fqterm_prefix; + + char *p = NULL; + if ((p = getenv("FQTERM_PREFIX")) != NULL) + fqterm_prefix = p; + + if (fqterm_prefix.size() == 0) { + res = QCoreApplication::applicationDirPath() + "/"; + } else { + res = QString::fromLocal8Bit(fqterm_prefix.c_str()); + } + + if (res[res.size() - 1] != '/') + res += '/'; + + return res; +} + +static QString getUserDataDir() { + char *evnDataDir = NULL; + if ((evnDataDir = getenv("FQTERM_DATADIR")) != NULL) { + std::string fqterm_data = evnDataDir; + if (fqterm_data[fqterm_data.size() - 1] != '/' +#ifdef WIN32 + || fqterm_data[fqterm_data.size() - 1] != '\\' +#endif + ) + fqterm_data += '/'; + if (fqterm_data.length() != 0) { + return QString::fromLocal8Bit(fqterm_data.c_str()); + } + } + +#ifdef WIN32 + char buffer[MAX_PATH]; + SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, buffer); + std::string dir(buffer); + + if (dir[dir.size() - 1] != '\\') { + dir += '\\'; + } + return QString::fromLocal8Bit(dir.c_str()) + "FQTerm/"; +#else + char *p = NULL; + + std::string home; + if ((p = getenv("HOME")) != NULL) + home = p; + if (home.size() == 0) + home = "/root/"; + + if (home[home.size() - 1] != '/') + home += '/'; + + return QString::fromLocal8Bit(home.c_str()) + ".fqterm/"; +#endif +} + +} // namespace FQTerm diff --git a/src/common/fqterm_path.h b/src/common/fqterm_path.h new file mode 100644 index 0000000..08611be --- /dev/null +++ b/src/common/fqterm_path.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_PATH_H +#define FQTERM_PATH_H + +class QString; +class QStringList; + +class FQTermConfig; +class FQTermParam; + +namespace FQTerm { + +enum PathCategory {RESOURCE, USER_CONFIG}; + +const QString &getPath(PathCategory category); + +bool iniSettings(); + +void checkHelpExists(FQTermConfig*); +void loadNameList(FQTermConfig *, QStringList &); +bool loadAddress(FQTermConfig *, int, FQTermParam &); +void saveAddress(FQTermConfig *, int, const FQTermParam &); + +void clearDir(const QString &path); +} // namespace FQTerm + +#endif // FQTERM_PATH_H diff --git a/src/common/fqterm_shortcuthelper.cpp b/src/common/fqterm_shortcuthelper.cpp new file mode 100644 index 0000000..8c18643 --- /dev/null +++ b/src/common/fqterm_shortcuthelper.cpp @@ -0,0 +1,298 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ +#include "fqterm_shortcuthelper.h" +#include "fqterm_config.h" +#include "fqterm_path.h" + +#include +#include +#include +namespace FQTerm +{ + +FQTermShortcutHelper::FQTermShortcutHelper(FQTermConfig* config, QWidget* actionParent) : + config_(config), + actionParent_(actionParent) +{ + initShortcutDescriptionTable(); +} + +QString FQTermShortcutHelper::getShortcutText(int shortcut) +{ + if (!config_) + return ""; + QString result = getShortcutConfig(shortcut); + if (result == "") + result = getShortcutDefaultText(shortcut); + else if (result == "Undefined") + result = ""; + return result; +} + +void FQTermShortcutHelper::initShortcutDescriptionTable() +{ + initShortcutDescriptionTableEntry(CONNECT, "connect", tr(""), tr("Connect Host"), "connect"); + initShortcutDescriptionTableEntry(CASCADEWINDOWS, "cascadewindows", tr(""), tr("Cascade Windows")); + initShortcutDescriptionTableEntry(TILEWINDOWS, "tilewindows", tr(""), tr("Tils Windows")); + initShortcutDescriptionTableEntry(DISCONNECT, "disconnect", tr(""), tr("Disconnect Host"), "disconnect"); + initShortcutDescriptionTableEntry(ADDRESSBOOK, "addressbook", tr("F2"), tr("Address Book"), "address_book"); + initShortcutDescriptionTableEntry(QUICKLOGIN, "quicklogin", tr("F3"), tr("Quick Login"), "quick_login"); +#if defined(__APPLE__) + initShortcutDescriptionTableEntry(COPY, "copy", tr("Ctrl+C"), tr("Copy"), "copy"); + initShortcutDescriptionTableEntry(PASTE, "paste", tr("Ctrl+V"), tr("Paste"), "paste"); +#else + initShortcutDescriptionTableEntry(COPY, "copy", tr("Ctrl+Ins"), tr("Copy"), "copy"); + initShortcutDescriptionTableEntry(PASTE, "paste", tr("Shift+Insert"), tr("Paste"), "paste"); +#endif + initShortcutDescriptionTableEntry(COPYWITHCOLOR, "copywithcolor", tr(""), tr("Copy With Color"), "copy_with_color"); + getAction(COPYWITHCOLOR)->setCheckable(true); + initShortcutDescriptionTableEntry(RECTANGLESELECTION, "rectangleselection", tr(""), tr("Rectangle Selection"), "rectangle_selection"); + getAction(RECTANGLESELECTION)->setCheckable(true); + initShortcutDescriptionTableEntry(AUTOCOPYSELECTION, "autocopyselection", tr(""), tr("Auto Copy Selection")); + getAction(AUTOCOPYSELECTION)->setCheckable(true); + initShortcutDescriptionTableEntry(PASTEWORDWRAP, "pastewordwrap", tr(""), tr("Paste With Word Wrap")); + getAction(PASTEWORDWRAP)->setCheckable(true); + initShortcutDescriptionTableEntry(ENGLISHFONT, "englishfont", tr(""), tr("Set English Font")); + initShortcutDescriptionTableEntry(OTHERFONT, "nonenglishfont", tr(""), tr("Set Other Font")); + initShortcutDescriptionTableEntry(COLORSETTING, "colorsetting", tr(""), tr("Color Setting"), "ansi_color"); + initShortcutDescriptionTableEntry(REFRESHSCREEN, "refreshscreen", tr(""), tr("Refresh Screen"), "refresh"); + initShortcutDescriptionTableEntry(ANSICOLOR, "ansicolor", tr(""), tr("Toggle Ansi Color"), "toggle_ansi_color"); + getAction(ANSICOLOR)->setCheckable(true); + initShortcutDescriptionTableEntry(UIFONT, "uifont", tr(""), tr("Set UI Font")); + initShortcutDescriptionTableEntry(FULLSCREEN, "fullscreen", tr("F6"), tr("Toggle Full Screen")); + getAction(FULLSCREEN)->setCheckable(true); + initShortcutDescriptionTableEntry(BOSSCOLOR, "bosscolor", tr("F12"), tr("Toggle Boss Color")); + getAction(BOSSCOLOR)->setCheckable(true); + initShortcutDescriptionTableEntry(SWITCHBAR, "switchbar", tr(""), tr("Toggle Switch Bar")); + getAction(SWITCHBAR)->setCheckable(true); + initShortcutDescriptionTableEntry(CURRENTSETTING, "currentsetting", tr(""), tr("Current Session Setting"), "preferences"); + initShortcutDescriptionTableEntry(SEARCHIT, "googleit", tr("Ctrl+Alt+G"), tr("Google selected words")); + initShortcutDescriptionTableEntry(WEIBOSHARE, "shareit", tr("Alt+`"), tr("Share selected text and highlighted URL to weibo")); + initShortcutDescriptionTableEntry(EXTERNALEDITOR, "externaleditor", tr("Ctrl+Alt+E"), tr("Invoke external editor")); + initShortcutDescriptionTableEntry(FASTPOST, "fastpost", tr("Ctrl+Alt+F"), tr("Fast post from clipboard")); + initShortcutDescriptionTableEntry(DEFAULTSETTING, "defaultsetting", tr(""), tr("Default Setting")); + initShortcutDescriptionTableEntry(PREFERENCE, "preference", tr(""), tr("Preference"), "preferences"); + initShortcutDescriptionTableEntry(EDITSCHEMA, "schema", tr(""), tr("Edit Schema")); + initShortcutDescriptionTableEntry(SHORTCUTSETTING, "shortcut", tr(""), tr("Shorcut Setting")); + initShortcutDescriptionTableEntry(COPYARTICLE, "copyarticle", tr("F9"), tr("Copy Article"), "get_article_fulltext"); + initShortcutDescriptionTableEntry(ANTIIDLE, "antiidle", tr(""), tr("Toggle Anti Idle"), "anti_idle"); + getAction(ANTIIDLE)->setCheckable(true); + initShortcutDescriptionTableEntry(AUTOREPLY, "autoreply", tr(""), tr("Toggle Auto Reply"), "auto_reply"); + getAction(AUTOREPLY)->setCheckable(true); + initShortcutDescriptionTableEntry(VIEWMESSAGE, "viewmessage", tr("F10"), tr("View Messages"), "view_messages"); + initShortcutDescriptionTableEntry(IPLOOKUP, "iplookup", tr(""), tr("IP Lookup")); + initShortcutDescriptionTableEntry(BEEP, "beep", tr(""), tr("Toggle Beep"), "beep"); + getAction(BEEP)->setCheckable(true); + initShortcutDescriptionTableEntry(MOUSESUPPORT, "mousesupport", tr(""), tr("Toggle Mouse Support"), "mouse"); + getAction(MOUSESUPPORT)->setCheckable(true); + initShortcutDescriptionTableEntry(IMAGEVIEWER, "imageviewer", tr(""), tr("Image Viewer"), "image_viewer"); + initShortcutDescriptionTableEntry(RUNSCRIPT, "runscript", tr("F7"), tr("Run Script")); + initShortcutDescriptionTableEntry(STOPSCRIPT, "stop", tr("F8"), tr("Stop Script")); +#ifdef HAVE_PYTHON + initShortcutDescriptionTableEntry(RUNPYTHONSCRIPT, "runpythonscript", tr("Ctrl+F1"), tr("Run Python Script")); +#endif //HAVE_PYTHON + initShortcutDescriptionTableEntry(ABOUT, "about", tr("Shift+F1"), tr("About")); + initShortcutDescriptionTableEntry(HOMEPAGE, "homepage", tr(""), tr("Homepage")); + initShortcutDescriptionTableEntry(EXIT, "exit", tr(""), tr("Exit FQTerm")); + initShortcutDescriptionTableEntry(COLORCTL_NO, "colorctlno", tr(""), tr("Set Color Ctrl to None")); + getAction(COLORCTL_NO)->setCheckable(true); + initShortcutDescriptionTableEntry(COLORCTL_SMTH, "colorctlsmth", tr(""), tr("Set Color Ctrl to **[")); + getAction(COLORCTL_SMTH)->setCheckable(true); + initShortcutDescriptionTableEntry(COLORCTL_PTT, "colorctlptt", tr(""), tr("Set Color Ctrl to ^u[")); + getAction(COLORCTL_PTT)->setCheckable(true); + initShortcutDescriptionTableEntry(COLORCTL_OLD_CUSTOM, "colorctloldcustom", tr(""), tr("Set Color Ctrl to old custom")); + getAction(COLORCTL_OLD_CUSTOM)->setCheckable(true); + initShortcutDescriptionTableEntry(COLORCTL_CUSTOM, "colorctlcustom", tr(""), tr("Set Color Ctrl to custom")); + getAction(COLORCTL_CUSTOM)->setCheckable(false); + initShortcutDescriptionTableEntry(AUTORECONNECT, "autoreconnect", tr(""), tr("Toggle Auto Reconnect"), "auto_reconnect"); + getAction(AUTORECONNECT)->setCheckable(true); + initShortcutDescriptionTableEntry(SCROLLBAR_LEFT, "scrollbarleft", tr(""), tr("Set Scrollbar to Left")); + getAction(SCROLLBAR_LEFT)->setCheckable(true); + initShortcutDescriptionTableEntry(SCROLLBAR_RIGHT, "scrollbarright", tr(""), tr("Set Scrollbar to Right")); + getAction(SCROLLBAR_RIGHT)->setCheckable(true); + initShortcutDescriptionTableEntry(SCROLLBAR_HIDDEN, "scrollbarhidden", tr(""), tr("Set Scrollbar Hidden")); + getAction(SCROLLBAR_HIDDEN)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_GOOGLE, "searchgoogle", tr(""), tr("Use Google")); + getAction(SEARCH_GOOGLE)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_BAIDU, "searchbaidu", tr(""), tr("Use Baidu")); + getAction(SEARCH_BAIDU)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_BING, "searchbing", tr(""), tr("Use Bing")); + getAction(SEARCH_BING)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_YAHOO, "searchyahoo", tr(""), tr("Use Yahoo!")); + getAction(SEARCH_YAHOO)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_CUSTOM, "searchcustom", tr(""), tr("Use Customized SE")); + getAction(SEARCH_CUSTOM)->setCheckable(true); + initShortcutDescriptionTableEntry(LANGUAGE_ENGLISH, "languageenglish", tr(""), tr("Choose UI Language: English")); + getAction(LANGUAGE_ENGLISH)->setCheckable(true); + initShortcutDescriptionTableEntry(SAVESETTING, "savesetting", tr(""), tr("Save Current Session Setting"), "save_setting"); + +#if defined(__APPLE__) + QString opt(tr("Ctrl")); +#else + QString opt(tr("Alt")); +#endif + + initShortcutDescriptionTableEntry(NEXTWINDOW, "nextwindow", opt + tr("+Right"), tr("Next Window")); + initShortcutDescriptionTableEntry(PREVWINDOW, "prevwindow", opt + tr("+Left"), tr("Prev Window")); + + initShortcutDescriptionTableEntry(GLOBAL_SHOW_FQTERM, "showfqterm", tr("Ctrl+Alt+Q"), tr("Show FQTerm")); + //index, key, default shortcut, descritption + + retranslateActions(); +} + +void FQTermShortcutHelper::retranslateAction(int shortcut, const QString& text) +{ + if (getAction(shortcut)) + getAction(shortcut)->setText(text); +} + +void FQTermShortcutHelper::retranslateActions() { + retranslateAction(CONNECT, tr("&Connect")); + retranslateAction(DISCONNECT, tr("&Disconnect")); + retranslateAction(ADDRESSBOOK, tr("&Address book")); + retranslateAction(QUICKLOGIN, tr("&Quick login")); + retranslateAction(COPY, tr("&Copy")); + retranslateAction(PASTE, tr("&Paste")); + retranslateAction(COPYWITHCOLOR, tr("C&opy with color")); + retranslateAction(RECTANGLESELECTION, tr("&Rectangle select")); + retranslateAction(AUTOCOPYSELECTION, tr("Auto copy &select")); + retranslateAction(PASTEWORDWRAP, tr("P&aste with wordwrap")); + retranslateAction(ENGLISHFONT, tr("&English Font")); + retranslateAction(OTHERFONT, tr("O&ther Font")); + retranslateAction(COLORSETTING, tr("&Color Setting")); + retranslateAction(ANSICOLOR, tr("&Use ANSI Color")); + retranslateAction(REFRESHSCREEN, tr("&Refresh")); + retranslateAction(UIFONT, tr("U&I font")); + retranslateAction(FULLSCREEN, tr("Fullscree&n")); + retranslateAction(BOSSCOLOR, tr("B&oss Color")); + retranslateAction(SWITCHBAR, tr("S&witch Bar")); + retranslateAction(SEARCHIT, tr("&Search It")); + retranslateAction(WEIBOSHARE, tr("Sha&re It")); + retranslateAction(EXTERNALEDITOR, tr("E&xternal Editor")); + retranslateAction(FASTPOST, tr("&Fast Post")); + retranslateAction(CURRENTSETTING, tr("&Setting for current session")); + retranslateAction(DEFAULTSETTING, tr("&Default setting")); + retranslateAction(PREFERENCE, tr("&Preferences...")); + retranslateAction(SHORTCUTSETTING, tr("Short&cut Setting")); + retranslateAction(EDITSCHEMA, tr("&Edit Schema")); + retranslateAction(COPYARTICLE, tr("&Copy article")); + retranslateAction(ANTIIDLE, tr("Anti &idle")); + retranslateAction(AUTOREPLY, tr("Auto &reply")); + retranslateAction(VIEWMESSAGE, tr("&View messages")); + retranslateAction(IPLOOKUP, tr("I&P Lookup")); + retranslateAction(BEEP, tr("&Beep")); + retranslateAction(MOUSESUPPORT, tr("&Mouse support")); + retranslateAction(IMAGEVIEWER, tr("Ima&ge viewer")); + retranslateAction(RUNSCRIPT, tr("&Run...")); + retranslateAction(STOPSCRIPT, tr("&Stop")); + retranslateAction(RUNPYTHONSCRIPT, tr("Run &Python...")); + retranslateAction(ABOUT, tr("About &FQTerm")); + retranslateAction(HOMEPAGE, tr("FQTerm's &Homepage")); + retranslateAction(CASCADEWINDOWS, tr("&Cascade")); + retranslateAction(TILEWINDOWS, tr("&Tile")); + retranslateAction(EXIT, tr("&Exit")); + retranslateAction(COLORCTL_NO, tr("&None")); + retranslateAction(COLORCTL_SMTH, tr("&ESC ESC [")); + retranslateAction(COLORCTL_PTT, tr("Ctrl+&U[")); + retranslateAction(COLORCTL_CUSTOM, tr("&Custom...")); + retranslateAction(AUTORECONNECT, tr("Reconnect When Disconnected By Host")); + retranslateAction(NEXTWINDOW, tr("Next Window")); + retranslateAction(PREVWINDOW, tr("Prev Window")); + retranslateAction(LANGUAGE_ENGLISH, tr("&English")); + retranslateAction(SCROLLBAR_HIDDEN, tr("&Hide")); + retranslateAction(SCROLLBAR_RIGHT, tr("&Right")); + retranslateAction(SCROLLBAR_LEFT, tr("&Left")); + retranslateAction(SEARCH_GOOGLE, tr("&Google")); + retranslateAction(SEARCH_BAIDU, tr("&Baidu")); + retranslateAction(SEARCH_BING, tr("&Bing")); + retranslateAction(SEARCH_YAHOO, tr("&Yahoo!")); + retranslateAction(SEARCH_CUSTOM, tr("&Custom")); + retranslateAction(SAVESETTING, tr("Save Settin&g")); +} + + +void FQTermShortcutHelper::resetAllShortcutText() +{ + for (int i = FQTERM_APPLICATION_SHORTCUT_START + 1; i < FQTERM_APPLICATION_SHORTCUT_END; ++i) + { + resetShortcutText(i); + } +} + +void FQTermShortcutHelper::resetShortcutText(int shortcut) +{ + if (!config_) + return; + setShortcutText(shortcut, getShortcutDefaultText(shortcut)); +} + +void FQTermShortcutHelper::setShortcutText(int shortcut, const QString& text) +{ + if (!config_) + return; + QString val = text.trimmed(); + if (val == "") + val = "Undefined"; + setShortcutConfig(shortcut, val); + if (getAction(shortcut)) + getAction(shortcut)->setShortcut(val); +} + +FQTermShortcutHelper::~FQTermShortcutHelper() +{ +} + +QString FQTermShortcutHelper::getShortcutConfig(int shortcut) +{ + return config_->getItemValue(getShortcutSection(), getShortcutKey(shortcut)); +} + +void FQTermShortcutHelper::setShortcutConfig(int shortcut, const QString& text) +{ + config_->setItemValue(getShortcutSection(), getShortcutKey(shortcut), text); +} + +void FQTermShortcutHelper::initShortcutDescriptionTableEntry(int index, const QString& key, const QString& defaultshortcuttext, const QString& description, const QString& actionSkin) { + shortcutDescriptionTable_[index] = ShortcutDescriptionEntry(key, defaultshortcuttext, description); + shortcutDescriptionTable_[index].action_ = new QAction(actionParent_); + if (actionParent_) { + actionParent_->addAction(shortcutDescriptionTable_[index].action_); + } + shortcutDescriptionTable_[index].action_->setShortcut(getShortcutText(index)); + if (actionSkin != QString::null) + shortcutDescriptionTable_[index].action_->setIcon(QPixmap(getPath(RESOURCE) + "pic/" + actionSkin + ".png")); +} + + +FQTermShortcutHelper::ShortcutDescriptionEntry::ShortcutDescriptionEntry(const QString& key /*= QString("")*/, + const QString& defaultshortcuttext /*= QString("")*/, + const QString& description /*= QString("")*/) : + key_(key), + defaultshortcuttext_(defaultshortcuttext), + description_(description), + action_(NULL) {} + +FQTermShortcutHelper::ShortcutDescriptionEntry::~ShortcutDescriptionEntry() { + delete action_; +} +}//namespace FQTerm + +#include "fqterm_shortcuthelper.moc" \ No newline at end of file diff --git a/src/common/fqterm_shortcuthelper.h b/src/common/fqterm_shortcuthelper.h new file mode 100644 index 0000000..7e77df7 --- /dev/null +++ b/src/common/fqterm_shortcuthelper.h @@ -0,0 +1,175 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __FQTERM_SHORTCUTHELPER__ +#define __FQTERM_SHORTCUTHELPER__ + +#include "fqterm.h" +#include +#include +#include + +class QWidget; +class QAction; +namespace FQTerm +{ +class FQTermConfig; + + +#define FQTERM_ADDACTION(WIDGET, NAME, RECEIVER, FUNCTION) \ + do{ \ + QAction *action = getAction((FQTermShortcutHelper::NAME));\ + QObject::disconnect(action, SIGNAL(triggered()), (RECEIVER), SLOT(FUNCTION())); \ + FQ_VERIFY(connect(action, SIGNAL(triggered()), (RECEIVER), SLOT(FUNCTION()))); \ + (WIDGET)->addAction(action);\ + } while(0) + + + +class FQTermShortcutHelper : public QObject +{ + Q_OBJECT; +public: + enum FQTERM_SHORTCUT + { + FQTERM_APPLICATION_SHORTCUT_START = 0, + CONNECT, + DISCONNECT, + ADDRESSBOOK, //F2 + QUICKLOGIN, //F3 + COPY, //Ctrl+Ins under lin & win, Ctrl+C under mac + PASTE, //Shift+Insert under lin & win, Ctrl+V under mac + COPYWITHCOLOR, + RECTANGLESELECTION, + AUTOCOPYSELECTION, + PASTEWORDWRAP, + ENGLISHFONT, + OTHERFONT, + COLORSETTING, + ANSICOLOR, + REFRESHSCREEN, //F5 + UIFONT, + FULLSCREEN, //F6 + BOSSCOLOR, //F12 + SWITCHBAR, + SEARCHIT, //Ctrl+Alt+G + WEIBOSHARE, + EXTERNALEDITOR, //Ctrl+Alt+E + FASTPOST, //Ctrl+Alt+F + CURRENTSETTING, + DEFAULTSETTING, + SAVESETTING, + PREFERENCE, + SHORTCUTSETTING, + EDITSCHEMA, + COPYARTICLE, //F9 + ANTIIDLE, + AUTOREPLY, + VIEWMESSAGE, //F10 + IPLOOKUP, + BEEP, + MOUSESUPPORT, + IMAGEVIEWER, + RUNSCRIPT, //F7 + STOPSCRIPT, //F8 + RUNPYTHONSCRIPT, //Ctrl+F1 + ABOUT, //F1 + HOMEPAGE, + CASCADEWINDOWS, + TILEWINDOWS, + EXIT, + COLORCTL_NO, + COLORCTL_SMTH, + COLORCTL_PTT, + COLORCTL_OLD_CUSTOM, + COLORCTL_CUSTOM, + AUTORECONNECT, + SCROLLBAR_LEFT, + SCROLLBAR_RIGHT, + SCROLLBAR_HIDDEN, + SEARCH_GOOGLE, + SEARCH_BAIDU, + SEARCH_BING, + SEARCH_YAHOO, + SEARCH_CUSTOM, + LANGUAGE_ENGLISH, + NEXTWINDOW, + PREVWINDOW, + GLOBAL_SHOW_FQTERM, + FQTERM_APPLICATION_SHORTCUT_END, + }; + + +public: + FQTermShortcutHelper(FQTermConfig* config, QWidget* actionParent); + ~FQTermShortcutHelper(); + +private: + struct ShortcutDescriptionEntry + { + ShortcutDescriptionEntry(const QString& key = QString(""), const QString& defaultshortcuttext = QString(""), const QString& description = QString("")); + ~ShortcutDescriptionEntry(); + QString key_; + QString defaultshortcuttext_; + QString description_; + QAction* action_; + }; + void initShortcutDescriptionTable(); + FQTermConfig* config_; + QWidget* actionParent_; + QMap shortcutDescriptionTable_; + void initShortcutDescriptionTableEntry(int index, const QString& key, const QString& defaultshortcuttext, const QString& description, const QString& actionSkin = QString::null); + +public: + + QString getShortcutText(int shortcut) ; + QString getShortcutDescription(int shortcut) { + return shortcutDescriptionTable_[shortcut].description_; + } + QString getShortcutDefaultText(int shortcut) { + return shortcutDescriptionTable_[shortcut].defaultshortcuttext_; + } + void setShortcutText(int shortcut, const QString& text); + void resetShortcutText(int shortcut); + void resetAllShortcutText(); + + QAction* getAction(int shortcut) { + return shortcutDescriptionTable_[shortcut].action_; + } + void retranslateActions(); +private: + //These functions are used to save shortcut + QString getShortcutSection() { + return QString("shortcutsettings"); + } + QString getShortcutKey(int shortcut) { + return shortcutDescriptionTable_[shortcut].key_; + } + + QString getShortcutConfig(int shortcut); + void setShortcutConfig(int shortcut, const QString& text); + void retranslateAction(int shortcut, const QString& text); +}; + + +}//namespace FQTerm + + +#endif diff --git a/src/common/fqterm_sound.cpp b/src/common/fqterm_sound.cpp new file mode 100644 index 0000000..96bcc83 --- /dev/null +++ b/src/common/fqterm_sound.cpp @@ -0,0 +1,733 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +/*******************************************************/ +/********** OSS code is from OpenSound System **********/ +/*******************************************************/ +#ifdef AUDIO_OSS +#include +#include +#include + +#if defined(_OS_FREEBSD_) || defined(_OS_LINUX_) +#include +#define FQ_AUDIO_DEV "/dev/dsp" +#else +#include +#define FQ_AUDIO_DEV "/dev/audio" +#endif + +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_ADPCM 0x0002 +#define WAVE_FORMAT_ALAW 0x0006 +#define WAVE_FORMAT_MULAW 0x0007 +#define WAVE_FORMAT_IMA_ADPCM 0x0011 + +#ifndef AFMT_S32_LE +#define AFMT_S32_LE 0x00001000 /* Little endian signed 32-bit */ +#endif + +typedef struct { + int coeff1, coeff2; +} adpcm_coeff; + +#endif /* AUDIO_OSS */ + +/* 2008.07.06, ecore.cn@gmail.com, alsa sound for FQTerm ... */ +#ifdef AUDIO_ALSA +#include +#include +typedef struct tag_FQ_WAVE_FILE_HEADER { + uint32_t rid; /* RIFF ID */ + uint32_t rsz; /* RIFF SIZE */ + uint32_t wid; /* WAVE ID */ +} +FQWFH; + +typedef struct tag_FQ_WAVE_FORMAT_HEADER { + uint32_t fid; /* FORMAT ID */ + uint32_t fsz; /* FORMAT SIZE */ + uint16_t aid; /* AUDIO ID */ + uint16_t ach; /* AUDIO CHANNELS */ + uint32_t asr; /* AUDIO SAMPLE RATE */ + uint32_t abr; /* AUDIO BYTE RATE */ + uint16_t aba; /* AUDIO BLOCK ALIGNMENT */ + uint16_t abps; /* AUDIO BITS PER SAMPLE */ +} +FQWMH; + +typedef struct tag_FQ_WAVE_DATA_HEADER { + uint32_t did; /* DATA ID */ + uint32_t dsz; /* DATA SIZE */ +} +FQWDH; + +#endif /* AUDIO_ALSA */ + +#include "common.h" +#include "fqterm_sound.h" + +namespace FQTerm { + +FQTermSound::FQTermSound(const QString &filename, QObject *parent, + const char *name) + : QThread(parent), soundFile_(filename) { + connect(this, SIGNAL(finished()), SLOT(deleteInstance())); + connect(this, SIGNAL(terminated()), SLOT(deleteInstance())); +} + +FQTermSound::~FQTermSound() { +} + +void FQTermSound::deleteInstance() { + FQ_TRACE("sound", 3) << "sound instance [" << (void*)this << "] is to be deleted!"; + delete this; +} + +void FQTermSound::run() { + if (QFile::exists(soundFile_)) { +#if !defined(AUDIO_OSS) && !defined(AUDIO_ALSA) + QSound::play(soundFile_); +#else + this->play(); +#endif + } +} + +void FQTermExternalSound::setPlayer(const QString &playername) { + playerName_ = playername; +} + +void FQTermExternalSound::play() { + if (QFile::exists(soundFile_)) { + runProgram(playerName_, soundFile_, false); + } +} + +/*******************************************************/ +/********** OSS code is from OpenSound System **********/ +/*******************************************************/ +#ifdef AUDIO_OSS +static int le_int (unsigned char *p, int l) { + + int i, val; + val = 0; + + for (i = l - 1; i >= 0; i--) { + val = (val << 8) | p[i]; + } + + return val; +} + +static int setupDevice(int audiofd, int channels, int bits, int speed) { + + int tmp; + + tmp = bits; + if (ioctl(audiofd, SNDCTL_DSP_SETFMT, &tmp) == -1) { + return 0; + } + + if (tmp != bits) { + return 0; + } + + tmp = channels; + if (ioctl(audiofd, SNDCTL_DSP_CHANNELS, &tmp) == -1) { + return 0; + } + + if (tmp != channels) { + return 0; + } + + tmp = speed; + if (ioctl(audiofd, SNDCTL_DSP_SPEED, &tmp) == -1) { + return 0; + } + + return 1; +} + +static void dumpData(int audiofd, int soundfd, int filesize) { + + int bsize, l; + unsigned char buf[1024]; + bsize = sizeof(buf); + + while (filesize) { + + l = bsize; + + if (l > filesize) { + l = filesize; + } + + if ((l = read(soundfd, buf, l)) <= 0) { + return; + } + + if (write(audiofd, buf, l) == -1) { + return; + } + + filesize -= l; + } +} + +static void dumpData24 (int audiofd, int soundfd, int filesize) { + + int bsize, i, l; + unsigned char buf[1024]; + int outbuf[1024], outlen=0; + int sample_s32; + bsize = sizeof(buf); + + filesize -= filesize % 3; + + while(filesize >= 3) { + + l = bsize - bsize % 3; + if (l > filesize) { + l = filesize; + } + + if(l < 3) { + break; + } + + if ((l = read(soundfd, buf, l)) <= 0) { + return; + } + + outlen=0; + + for(i=0; i32767)s=32767;else if(s<-32768)s=-32768; \ + outbuf[outp++] = (unsigned char)(s & 0xff); \ + outbuf[outp++] = (unsigned char)((s>>8) & 0xff); \ + n+=2; \ + if (outp>=max){write(audiofd, outbuf, outp);outp=0;}\ + } + +#define GETNIBBLE \ + ((nib==0) ? \ + (buf[x + nib++] >> 4) & 0x0f : \ + buf[x++ + --nib] & 0x0f \ + ) + + max = 1024; + outp = 0; + + while (dataleft > nBlockAlign && + read(soundfd, buf, nBlockAlign) == nBlockAlign) { + + int predictor[2], delta[2], samp1[2], samp2[2]; + int x = 0; + dataleft -= nBlockAlign; + + nib = 0; + n = 0; + + for (i = 0; i < channels; i++) { + predictor[i] = buf[x]; + x++; + } + + for (i = 0; i < channels; i++) { + delta[i] = (short)le_int(&buf[x], 2); + x += 2; + } + + for (i = 0; i < channels; i++) { + samp1[i] = (short)le_int(&buf[x], 2); + x += 2; + OUT_SAMPLE(samp1[i]); + } + + for (i = 0; i < channels; i++) { + samp2[i] = (short)le_int(&buf[x], 2); + x += 2; + OUT_SAMPLE(samp2[i]); + } + + while (n < (wSamplesPerBlock * 2 * channels)) { + + for (i = 0; i < channels; i++) { + + int pred, new_pred, error_delta, i_delta; + + pred = ((samp1[i] * coeff[predictor[i]].coeff1) + + (samp2[i] * coeff[predictor[i]].coeff2)) / 256; + i_delta = error_delta = GETNIBBLE; + + if (i_delta & 0x08) { + i_delta -= 0x10; /* Convert to signed */ + } + + new_pred = pred + (delta[i] * i_delta); + OUT_SAMPLE(new_pred); + + delta[i] = delta[i] * AdaptionTable[error_delta] / 256; + if (delta[i] < 16) { + delta[i] = 16; + } + + samp2[i] = samp1[i]; + samp1[i] = new_pred; + } + } + } + } + + if (outp > 0) { + write (audiofd, outbuf, outp /*(outp+3) & ~3 */ ); + } +} + +static void playWave(int audiofd, int soundfd, unsigned char *hdr, int l) { + + int filelen; + int n; + int channels = 1; + int bits = 8; + int file_bits = 8; + int speed = 11025; + int p = 12; + int fmt = -1; + + filelen = le_int(&hdr[4], 4); + + while(p < l - 16 && memcmp(&hdr[p], "data", 4) != 0) { + + n = le_int(&hdr[p + 4], 4); + + if (memcmp(&hdr[p], "fmt ", 4) == 0) { + + fmt = le_int(&hdr[p + 8], 2); + channels = le_int(&hdr[p + 10], 2); + speed = le_int(&hdr[p + 12], 4); + bits = le_int(&hdr[p + 22], 2); + + if (fmt == WAVE_FORMAT_ADPCM) { + playAdpcmWave(audiofd, soundfd, hdr, l); + return; + } + + p += n + 8; + } else { + break; + } + } + + if (p < l - 16 && memcmp(&hdr[p], "data", 4) == 0) { + + n = le_int(&hdr[p + 4], 4); + p += 8; + + if (lseek(soundfd, p, SEEK_SET) == -1) { + return; + } + + if (fmt != WAVE_FORMAT_PCM) { + switch (fmt) { + case WAVE_FORMAT_ALAW: + bits = AFMT_A_LAW; + break; + case WAVE_FORMAT_MULAW: + bits = AFMT_MU_LAW; + break; + case WAVE_FORMAT_IMA_ADPCM: + bits = AFMT_IMA_ADPCM; + break; + default: + return; + } + } + + file_bits = bits; + + if (bits == 32) { + bits = AFMT_S32_LE; + } else if (bits == 24) { + bits = AFMT_S32_LE; + } + + if (!setupDevice(audiofd, channels, bits, speed)) { + return; + } + + if (file_bits != 24) { + dumpData (audiofd, soundfd, n); + } else { + dumpData24 (audiofd, soundfd, n); + } + } +} +#endif /* AUDIO_OSS */ + +void FQTermSystemSound::play() { + +#ifdef AUDIO_OSS + int audio_fd = -1; + if ((audio_fd = open(FQ_AUDIO_DEV, O_WRONLY, 0)) == -1) { + FQ_TRACE("sound", 0) << "Error opening device: " << FQ_AUDIO_DEV; + return; + } + + int sound_fd = -1; + QFile soundFile(soundFile_); + + if (soundFile.open(QFile::ReadOnly)) { + sound_fd = soundFile.handle(); + } else { + FQ_TRACE("sound", 0) << "Error opening file: " << soundFile_; + close(audio_fd); + return; + } + + int l; + unsigned char sound_buf[1024]; + + if ((l = read(sound_fd, sound_buf, sizeof(sound_buf))) == -1) { + FQ_TRACE("sound", 0) << "Error reading file into buffer." << soundFile_; + soundFile.close(); + close(audio_fd); + return; + } + + if (l == 0) { + FQ_TRACE("sound", 0) << "Empty file: " << soundFile_; + soundFile.close(); + close(audio_fd); + return; + } + + lseek(sound_fd, 0, SEEK_SET); /* Start from the beginning */ + + if (l > 16 && + memcmp(&sound_buf[0], "RIFF", 4) == 0 && memcmp(&sound_buf[8], "WAVE", 4) == 0) { + + playWave(audio_fd, sound_fd, sound_buf, l); + } else { + FQ_TRACE("sound", 0) << "We play WAVE files only: " << soundFile_; + } + + soundFile.close(); + close(audio_fd); + +#undef OUTSAMPLE +#undef GETNIBBLE +#endif /* AUDIO_OSS */ + +/* 2008.07.06, ecore.cn@gmail.com, alsa sound for FQTerm ... */ +#ifdef AUDIO_ALSA + FILE *fp; + FQWFH wfh; + FQWMH wmh; + FQWDH wdh; + int endian, sz, len, count, ret; + unsigned int val; + snd_pcm_t *handle; + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + snd_pcm_format_t format; + snd_pcm_uframes_t csz, vsz; + void *data; + +#define WAVE_UINT16(_x) (endian? ( \ + (((_x) & 0x00FF) << 8) | \ + (((_x) & 0xFF00) >> 8)): \ + (_x)) + +#define WAVE_UINT32(_x) (endian? ( \ + (((_x) & 0x000000FF) << 24) | \ + (((_x) & 0x0000FF00) << 8) | \ + (((_x) & 0x00FF0000) >> 8) | \ + (((_x) & 0xFF000000) >> 24)): \ + (_x)) + + do { + if ((fp = fopen(this->soundFile_.toLocal8Bit(), "r")) == NULL) { + continue; + } + + if (fread(&wfh, sizeof(FQWFH), 1, fp) != 1) { + continue; + } + + switch (wfh.rid) { + case 0x52494646: + endian = 1; /* Big-Endian */ + break; + case 0x46464952: + endian = 0; /* Small-Endian */ + break; + default: + continue; + } + + if (WAVE_UINT32(wfh.wid) != 0x45564157) { /* "WAVE" */ + continue; + } + + if (fread(&wmh, sizeof(FQWMH), 1, fp) != 1) { + continue; + } + + if (WAVE_UINT32(wmh.fid) != 0x20746d66) { /* "FMT " */ + continue; + } + + if (WAVE_UINT32(wmh.fsz) != 16 || WAVE_UINT16(wmh.aid) != 1) { /* PCM */ + continue; + } + + if (fread(&wdh, sizeof(FQWDH), 1, fp) != 1) { + continue; + } + + if (WAVE_UINT32(wdh.did) != 0x61746164) { /* "DATA" */ + continue; + } + + if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) { + continue; + } + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_sw_params_alloca(&swparams); + + if (snd_pcm_hw_params_any(handle, hwparams) < 0) { + continue; + } + + if (snd_pcm_hw_params_set_access(handle, hwparams, + SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { + continue; + } + + switch(WAVE_UINT16(wmh.abps)) { + case 8: + format = SND_PCM_FORMAT_U8; + break; + case 16: + format = SND_PCM_FORMAT_S16_LE; + break; + case 24: + switch (WAVE_UINT16(wmh.aba) / WAVE_UINT16(wmh.ach)) { + case 3: + format = SND_PCM_FORMAT_S24_3LE; + break; + case 4: + format = SND_PCM_FORMAT_S24_LE; + break; + default: + continue; + } + + break; + case 32: + format = SND_PCM_FORMAT_S32_LE; + break; + default: + continue; + } + + if (snd_pcm_hw_params_set_format(handle, hwparams, format) < 0) { + continue; + } + + if (snd_pcm_hw_params_set_channels(handle, hwparams, + WAVE_UINT16(wmh.ach)) < 0) { + continue; + } + + val = WAVE_UINT32(wmh.asr); + + if (snd_pcm_hw_params_set_rate_near(handle, hwparams, &val, NULL) < 0) { + continue; + } + + if (snd_pcm_hw_params(handle, hwparams) < 0) { + continue; + } + + snd_pcm_hw_params_get_period_size(hwparams, &csz, NULL); + snd_pcm_hw_params_get_buffer_size(hwparams, &vsz); + + if (csz == vsz) { + continue; + } + + snd_pcm_sw_params_current(handle, swparams); + + if (snd_pcm_sw_params_set_avail_min(handle, swparams, csz) < 0) { + continue; + } + + if (snd_pcm_sw_params_set_start_threshold(handle, swparams, vsz) < 0) { + continue; + } + + if (snd_pcm_sw_params_set_stop_threshold(handle, swparams, vsz) < 0) { + continue; + } + + if (snd_pcm_sw_params(handle, swparams) < 0) { + continue; + } + + sz = csz * snd_pcm_format_physical_width(format) + * WAVE_UINT16(wmh.ach) / 8; + + if ((data = malloc(sz)) == NULL) { + continue; + } + + len = WAVE_UINT32(wdh.dsz); + + while (len > 0) { + count = (len < sz)? len: sz; + + ret = fread(data, 1, count, fp); + + len -= ret; + + if (ret != count) { + continue; + } + + count = ret * csz / sz; + + ret = snd_pcm_writei(handle, data, count); + + if (ret == -EAGAIN || (ret >= 0 && ret < count)) { + snd_pcm_wait(handle, 200); + } + } + + free(data); + + snd_pcm_drain(handle); + snd_pcm_close(handle); + + fclose(fp); + } + while (0); + +#undef WAVE_UINT16 +#undef WAVE_UINT32 +#endif /* AUDIO_ALSA */ +} + +} // namespace FQTerm + +#include "fqterm_sound.moc" diff --git a/src/common/fqterm_sound.h b/src/common/fqterm_sound.h new file mode 100644 index 0000000..ab18645 --- /dev/null +++ b/src/common/fqterm_sound.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SOUND_H +#define FQTERM_SOUND_H + +#include +#include +#include + +#include "fqterm.h" + +namespace FQTerm { +// By using QThread, we avoid blocking the main app. +// FIXME: However, whichever play method we use (ext|int), +// there are some WAVE files we can't play... + +class FQTermSound: public QThread { + Q_OBJECT; + + public: + FQTermSound(const QString &filename, QObject *parent = 0, + const char *name = 0); + + ~FQTermSound(); + + public slots: + void deleteInstance(); + + protected: + QString soundFile_; + virtual void play() = 0; + void run(); +}; + +class FQTermSystemSound: public FQTermSound { + public: + FQTermSystemSound(const QString &filename, QObject *parent = 0, + const char *name = 0) + : FQTermSound(filename, parent, name) { + } + + protected: + void play(); +}; + +class FQTermExternalSound: public FQTermSound { + public: + FQTermExternalSound(const QString &playername, const QString &filename, + QObject *parent = 0, const char *name = 0) + : FQTermSound(filename, parent, name), playerName_(playername) { + } + + protected: + QString playerName_; + void play(); + void setPlayer(const QString &playername); +}; + +} // namespace FQTerm + +#endif // FQTERM_SOUND_H diff --git a/src/common/fqterm_trace.cpp b/src/common/fqterm_trace.cpp new file mode 100644 index 0000000..867b7ad --- /dev/null +++ b/src/common/fqterm_trace.cpp @@ -0,0 +1,328 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#ifdef WIN32 +#include +#else +#include +#endif + +#include "fqterm_trace.h" + +namespace FQTerm { + +int *getDefaultMaxTraceLevel() { + static int max_trace_level = 10; + return &max_trace_level; +} + +int getMaxTraceLevel() { + return *getDefaultMaxTraceLevel(); +} + +void setMaxTraceLevel(int max_trace_level) { + *getDefaultMaxTraceLevel() = max_trace_level; + FQ_TRACE("info", 0) << "The upper bound of maximum trace level is " + << FQTERM_MAX_TRACE_LEVEL; + FQ_TRACE("info", 0) << "The maximum trace level is set to " + << max_trace_level; +} + +#ifdef WIN32 +typedef stdext::hash_set CategorySet; +#else +typedef std::set CategorySet; +#endif + +CategorySet *getAllowedCategories() { + static CategorySet *allowed_categories + = new CategorySet; + return allowed_categories; +} + +int isAllowedCategory(const char *category, int trace_level) { + if (trace_level <= 0) return true; + + const CategorySet &categories = *getAllowedCategories(); + if (categories.empty() + || categories.find(category) != categories.end()) { + return true; + } + return false; +} + +void addAllowedCategory(const char *category) { + CategorySet &categories = *getAllowedCategories(); + + categories.insert(category); + + FQ_TRACE("info", 0) << "Allow category: " << category; +} + +// Event name from event type id (updated to Qt4.3.0). +static const char *kEventName[] = { + "QEvent::None", // 0 + "QEvent::Timer", // 1 + "QEvent::MouseButtonPress", // 2 + "QEvent::MouseButtonRelease", // 3 + "QEvent::MouseButtonDblClick", // 4 + "QEvent::MouseMove", // 5 + "QEvent::KeyPress", // 6 + "QEvent::KeyRelease", // 7 + "QEvent::FocusIn", // 8 + "QEvent::FocusOut", // 9 + "QEvent::Enter", // 10 + "QEvent::Leave", // 11 + "QEvent::Paint", // 12 + "QEvent::Move", // 13 + "QEvent::Resize", // 14 + "None", // 15 + "None", // 16 + "QEvent::Show", // 17 + "QEvent::Hide", // 18 + "QEvent::Close", // 19 + "None", // 20 + "QEvent::ParentChange", // 21 + "None", // 22 + "None", // 23 + "QEvent::WindowActivate", // 24 + "QEvent::WindowDeactivate", // 25 + "QEvent::ShowToParent", // 26 + "QEvent::HideToParent", // 27 + "None", // 28 + "None", // 29 + "None", // 30 + "QEvent::Wheel", // 31 + "None", // 32 + "QEvent::WindowTitleChange", // 33 + "QEvent::WindowIconChange", // 34 + "QEvent::ApplicationWindowIconChange", // 35 + "QEvent::ApplicationFontChange", // 36 + "QEvent::ApplicationLayoutDirectionChange", // 37 + "QEvent::ApplicationPaletteChange", // 38 + "QEvent::PaletteChange", // 39 + "QEvent::Clipboard", // 40 + "None", // 41 + "None", // 42 + "QEvent::MetaCall", // 43 + "None", // 44 + "None", // 45 + "None", // 46 + "None", // 47 + "None", // 48 + "None", // 49 + "QEvent::SockAct", // 50 + "QEvent::ShortcutOverride", // 51 + "QEvent::DeferredDelete", // 52 + "None", // 53 + "None", // 54 + "None", // 55 + "None", // 56 + "None", // 57 + "None", // 58 + "None", // 59 + "QEvent::DragEnter", // 60 + "QEvent::DragMove", // 61 + "QEvent::DragLeave", // 62 + "QEvent::Drop", // 63 + "None", // 64 + "None", // 65 + "None", // 66 + "None", // 67 + "QEvent::ChildAdded", // 68 + "QEvent::ChildPolished", // 69 + "None", // 70 + "QEvent::ChildRemoved", // 71 + "None", // 72 + "None", // 73 + "QEvent::PolishRequest", // 74 + "QEvent::Polish", // 75 + "QEvent::LayoutRequest", // 76 + "QEvent::UpdateRequest", // 77 + "QEvent::UpdateLater", // 78 + "None", // 79 + "None", // 80 + "None", // 81 + "QEvent::ContextMenu", // 82 + "QEvent::InputMethod", // 83 + "None", // 84 + "None", // 85 + "QEvent::AccessibilityPrepare", // 86 + "QEvent::TabletMove", // 87 + "QEvent::LocaleChange", // 88 + "QEvent::LanguageChange", // 89 + "QEvent::LayoutDirectionChange", // 90 + "None", // 91 + "QEvent::TabletPress", // 92 + "QEvent::TabletRelease", // 93 + "None", // 94 + "None", // 95 + "QEvent::IconDrag", // 96 + "QEvent::FontChange", // 97 + "QEvent::EnabledChange", // 98 + "QEvent::ActivationChange", // 99 + "QEvent::StyleChange", // 100 + "QEvent::IconTextChange", // 101 + "QEvent::ModifiedChange", // 102 + "QEvent::WindowBlocked", // 103 + "QEvent::WindowUnblocked", // 104 + "QEvent::WindowStateChange", // 105 + "None", // 106 + "None", // 107 + "None", // 108 + "QEvent::MouseTrackingChange", // 109 + "QEvent::ToolTip", // 110 + "QEvent::WhatsThis", // 111 + "QEvent::StatusTip", // 112 + "QEvent::ActionChanged", // 113 + "QEvent::ActionAdded", // 114 + "QEvent::ActionRemoved", // 115 + "QEvent::FileOpen", // 116 + "QEvent::Shortcut", // 117 + "QEvent::WhatsThisClicked", // 118 + "QEvent::AccessibilityHelp", // 119 + "QEvent::ToolBarChange", // 120 + "QEvent::ApplicationActivate", // 121 + "QEvent::ApplicationDeactivate", // 122 + "QEvent::QueryWhatsThis", // 123 + "QEvent::EnterWhatsThisMode", // 124 + "QEvent::LeaveWhatsThisMode", // 125 + "QEvent::ZOrderChange", // 126 + "QEvent::HoverEnter", // 127 + "QEvent::HoverLeave", // 128 + "QEvent::HoverMove", // 129 + "QEvent::AccessibilityDescription", // 130 + "QEvent::ParentAboutToChange", // 131 + "QEvent::WinEventAct", // 132 + "None", // 133 + "None", // 134 + "None", // 135 + "None", // 136 + "None", // 137 + "None", // 138 + "None", // 139 + "None", // 140 + "None", // 141 + "None", // 142 + "None", // 143 + "None", // 144 + "None", // 145 + "None", // 146 + "None", // 147 + "None", // 148 + "None", // 149 + "QEvent::EnterEditFocus", // 150 + "QEvent::LeaveEditFocus", // 151 + "None", // 152 + "QEvent::MenubarUpdated", // 153 + "None", // 154 + "QEvent::GraphicsSceneMouseMove", // 155 + "QEvent::GraphicsSceneMousePress", // 156 + "QEvent::GraphicsSceneMouseRelease", // 157 + "QEvent::GraphicsSceneMouseDoubleClick", // 158 + "QEvent::GraphicsSceneContextMenu", // 159 + "QEvent::GraphicsSceneHoverEnter", // 160 + "QEvent::GraphicsSceneHoverMove", // 161 + "QEvent::GraphicsSceneHoverLeave", // 162 + "QEvent::GraphicsSceneHelp", // 163 + "QEvent::GraphicsSceneDragEnter", // 164 + "QEvent::GraphicsSceneDragMove", // 165 + "QEvent::GraphicsSceneDragLeave", // 166 + "QEvent::GraphicsSceneDrop", // 167 + "QEvent::GraphicsSceneWheel", // 168 + "QEvent::KeyboardLayoutChange", // 169 + "QEvent::DynamicPropertyChange", // 170 + "QEvent::TabletEnterProximity", // 171 + "QEvent::TabletLeaveProximity", // 172 + // "QEvent::User", // 1000 + // "QEvent::MaxUser", // 65535 +}; + +const char *getEventName(unsigned int type) { + if (type > 1000) { + return "User defined event"; + } + + if (type > 172) { + return "None"; + } + + return kEventName[type]; +} + +} // namespace FQTerm + +#ifdef WIN32 +/* + * Number of micro-seconds between the beginning of the Windows epoch + * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970). + * + * This assumes all Win32 compilers have 64-bit support. + */ + +#include + +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__WATCOMC__) + #define DELTA_EPOCH_IN_USEC 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_USEC 11644473600000000ULL +#endif + +static unsigned long long filetime_to_unix_epoch (const FILETIME *ft) +{ + unsigned long long res = (unsigned long long) ft->dwHighDateTime << 32; + + res |= ft->dwLowDateTime; + res /= 10; /* from 100 nano-sec periods to usec */ + res -= DELTA_EPOCH_IN_USEC; /* from Win epoch to Unix epoch */ + return (res); +} + +int gettimeofday (struct timeval *tv, int unused) +{ + FILETIME ft; + unsigned long long tim; + + GetSystemTimeAsFileTime (&ft); + tim = filetime_to_unix_epoch (&ft); + tv->tv_sec = (long) (tim / 1000000L); + tv->tv_usec = (long) (tim % 1000000L); + return (0); +} +#else + +#include +#include + +#endif + +namespace FQTerm { + +long long getTraceTime() { + struct timeval t; + gettimeofday(&t, 0); + long long sec = t.tv_sec; + long long usec = t.tv_usec; + return sec * 1000 + usec/1000; +} + +} // namespace FQTerm diff --git a/src/common/fqterm_trace.h b/src/common/fqterm_trace.h new file mode 100644 index 0000000..287a8a8 --- /dev/null +++ b/src/common/fqterm_trace.h @@ -0,0 +1,331 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_TRACE_H +#define FQTERM_TRACE_H + +#include +#ifndef WIN32 +#include +#endif // WIN32 + +#include +#include + +namespace FQTerm { + +// define NO_FQTERM_TRACE to avoid all trace output. +// #define NO_FQTERM_TRACE + +// define NO_FQTERM_TRACE_FILE_LINE_NUM to avoid file line number in trace +// output. + +// define NO_FQTERM_TRACE_FUNCTION_NAME to avoid function name in trace output. +// define integer FQTERM_MAX_TRACE_LEVEL to determine the maximize outputed +// trace level. +//#define NO_FQTERM_TRACE +#if defined(NDEBUG) +#define FQTERM_MAX_TRACE_LEVEL 1 +#endif + +#ifndef FQTERM_MAX_TRACE_LEVEL +#define FQTERM_MAX_TRACE_LEVEL 20 +#endif // FQTERM_MAX_TRACE_LEVEL + +int getMaxTraceLevel(); + +void setMaxTraceLevel(int max_trace_level); + +long long getTraceTime(); + +int isAllowedCategory(const char *category, int trace_level); + +void addAllowedCategory(const char *category); + +static void soft_break() { +#if defined(WIN32) + __asm int 03h; +#else + pause(); +#endif +} + +template +class FQTermTrace { + public: + FQTermTrace(const char *category, const char *file_name, int line_num, const char *func_name) + : category_(category), + is_dummy_(!isAllowedCategory(category, trace_level)), + trace_output_((trace_level <= FQTERM_MAX_TRACE_LEVEL + && trace_level <= getMaxTraceLevel()) + ? new QDebug(qDebug().nospace()) + : NULL), + dump_string_(false) { + + if (is_dummy_) return; + +#ifdef NO_FQTERM_TRACE_FILE_LINE_NUM +#ifdef NO_FQTERM_TRACE_FUNCTION_NAME + return; +#endif // NO_FQTERM_TRACE_FUNCTION_NAME +#endif // NO_FQTERM_TRACE_FILE_LINE_NUM + + (*this) << "[" << category_ << " " << trace_level << " "; + +#ifndef NO_FQTERM_TRACE_FILE_LINE_NUM + (*this) << QFileInfo(file_name).fileName().toAscii().constData() + << ": " << line_num; +#endif // NO_FQTERM_TRACE_FILE_LINE_NUM + +#ifndef NO_FQTERM_TRACE_FUNCTION_NAME +#ifndef NO_FQTERM_TRACE_FILE_LINE_NUM + (*this) << ", "; +#endif // NO_FQTERM_TRACE_FILE_LINE_NUM + (*this) << func_name; +#endif // NO_FQTERM_TRACE_FUNCTION_NAME + + (*this) << "] "; + } + + ~FQTermTrace() { + if (is_dummy_) return; + + if (trace_level <= FQTERM_MAX_TRACE_LEVEL && trace_level <= getMaxTraceLevel()) { + delete trace_output_; + + if (trace_level < 0) { + soft_break(); + assert(false); + qFatal("Fatal error occured!\n"); + } + } + } + + template + FQTermTrace &operator << (const T &t) { + if (is_dummy_) return *this; + + if (trace_level <= FQTERM_MAX_TRACE_LEVEL && trace_level <= getMaxTraceLevel()) { + *trace_output_ << t; + } + return *this; + } + + FQTermTrace &operator << (const std::string &t) { + return output_raw_string(t); + } + + FQTermTrace &operator << (const char *t) { + return output_raw_string(t); + } + + FQTermTrace &operator << (void (*setter)(FQTermTrace &)) { + (*setter)(*this); + return *this; + } + + private: + FQTermTrace &output_raw_string(const std::string &t) { + if (is_dummy_) return *this; + + if (trace_level <= FQTERM_MAX_TRACE_LEVEL && trace_level <= getMaxTraceLevel()) { + if (!dump_string_) { + for (std::string::size_type i = 0; i < t.size(); ++i) { + *trace_output_ << t[i]; + } + } else { + for (std::string::size_type i = 0; i < t.size(); ++i) { + unsigned char a = t[i]; + unsigned char b = a / 0x10; + unsigned char c = a % 0x10; + char h = (char) (b < 10 ? '0' + b : 'A' + b - 10); + char l = (char) (c < 10 ? '0' + c : 'A' + c - 10); + + *trace_output_ << h << l << ' '; + } + } + } + return *this; + } + + private: + const char *category_; + bool is_dummy_; + QDebug *trace_output_; + + public: + bool dump_string_; // whether we print string in hex mode. + +}; + +template +class FQTermDummyTrace { + public: + template + FQTermDummyTrace &operator << (const T &) { + return *this; + } + + FQTermDummyTrace &operator << (void (*setter)(FQTermTrace &)) { + return *this; + } +}; + +template +void dumpHexString(FQTermTrace &tracer) { + tracer.dump_string_ = true; +} + +template +void dumpNormalString(FQTermTrace &tracer) { + tracer.dump_string_ = false; +} + +template +class FQTermScopeTrace { + public: + FQTermScopeTrace(const char *category, const char *file_name, int line_num, + const char *func_name, const char *scope_name) + : category_(category), + is_dummy_(!isAllowedCategory(category, trace_level)), + file_name_(file_name), + line_num_(line_num), + func_name_(func_name), + scope_name_(scope_name) { + if (is_dummy_) return; + FQTermTrace(category_, file_name_, line_num_, func_name_) + << "Entering " << scope_name_; + } + + ~FQTermScopeTrace() { + if (is_dummy_) return; + FQTermTrace(category_, file_name_, line_num_, func_name_) + << "Leaving " << scope_name_; + } + + private: + const char *category_; + bool is_dummy_; + + const char *file_name_; + const int line_num_; + const char *func_name_; + const char *scope_name_; +}; + +template +class FQTermTimerTrace { + public: + FQTermTimerTrace(const char *category, const char *file_name, int line_num, + const char *func_name, const char *msg) + : category_(category), + is_dummy_(!isAllowedCategory(category, trace_level)), + file_name_(file_name), + line_num_(line_num), + func_name_(func_name), + msg_(msg), + start_time(is_dummy_? 0: getTraceTime()) { + } + + ~FQTermTimerTrace() { + if (is_dummy_) return; + + long long total_time = getTraceTime() - start_time; + + long long num_sec = total_time / 1000; + long long num_ms = total_time % 1000; + + FQTermTrace(category_, file_name_, line_num_, func_name_) + << msg_ << num_sec << "s" << num_ms << "ms"; + } + + private: + const char *category_; + bool is_dummy_; + + const char *file_name_; + const int line_num_; + const char *func_name_; + const char *msg_; + + long long start_time; // in millisecond. +}; + +// Some macros work in both debug & release version. +#define FQ_FATAL(file, line, func) \ + do {FQTerm::soft_break(); qFatal("%s", (QString(file) + ": %1 " + QString(func)).arg(line).toUtf8().constData());} while(false) + +#define FQ_VERIFY(expr) do { \ + if(!(expr)) { \ + FQ_FATAL(__FILE__, __LINE__, __FUNCTION__); \ + } \ + } while(false) + + + +#ifdef NO_FQTERM_TRACE + +#define FQ_TRACE(category, trace_level) FQTermDummyTrace() +#define FQ_SCOPE_TRACE(category, trace_level, scope_name) do {} while (false) +#define FQ_FUNC_TRACE(category, trace_level) do {} while(false) + +#define FQ_ASSERT(expr) do {} while(false) + +#define FQ_SCOPE_TIMER(category, trace_level, msg) do {} while(false) +#define FQ_FUNC_TIMER(category, trace_level) do {} while(false) + + +#else // NO_FQTERM_TRACE + +#define FQ_TRACE(category, trace_level) \ + FQTermTrace(category, __FILE__, __LINE__, __FUNCTION__) + +#define FQ_SCOPE_TRACE_PRIVATE(file, line, func, category, trace_level, scope_name) \ + FQTermScopeTrace file##line##func(category, file, line, func, scope_name); + +#define FQ_SCOPE_TRACE(category, trace_level, scope_name) \ + FQ_SCOPE_TRACE_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, scope_name) + +#define FQ_FUNC_TRACE(category, trace_level) \ + FQ_SCOPE_TRACE_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, "function") + + +#define FQ_ASSERT(expr) \ + do {if(!(expr)) {FQ_TRACE("assert", -1) << "assertion failed." << #expr;}} while(false) + + +#define FQ_SCOPE_TIMER_PRIVATE(file, line, func, category, trace_level, msg) \ + FQTermTimerTrace file##line##func(category, file, line, func, msg); + +#define FQ_SCOPE_TIMER(category, trace_level, msg) \ + FQ_SCOPE_TIMER_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, msg) + +#define FQ_FUNC_TIMER(category, trace_level) \ + FQ_SCOPE_TIMER_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, "The function runs for ") + + +#endif // NO_FQTERM_TRACE + + +const char *getEventName(unsigned int type); + +} // namespace FQTerm + +#endif // FQTERM_TRACE_H diff --git a/src/fqterm/3rdparty/dotnetstyle.cpp b/src/fqterm/3rdparty/dotnetstyle.cpp new file mode 100644 index 0000000..d016ff2 --- /dev/null +++ b/src/fqterm/3rdparty/dotnetstyle.cpp @@ -0,0 +1,1274 @@ +/**************************************************************************** +** +** Copyright (C) 2007-2007 Trolltech ASA. All rights reserved. +** +** This file is part of the DotNetStyle project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifdef USE_DOTNET_STYLE +#include "dotnetstyle.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef bool (WINAPI *PtrIsAppThemed)(); +typedef HRESULT (WINAPI *PtrGetCurrentThemeName)(OUT LPWSTR pszThemeFileName, int cchMaxNameChars, OUT OPTIONAL LPWSTR pszColorBuff, int cchMaxColorChars, OUT OPTIONAL LPWSTR pszSizeBuff, int cchMaxSizeChars); + +static PtrIsAppThemed pIsAppThemed = 0; +static PtrGetCurrentThemeName pGetCurrentThemeName = 0; + +static const int windowsItemFrame = 2; // menu item frame width +static const int windowsSepHeight = 9; // separator item height +static const int windowsItemHMargin = 3; // menu item hor text margin +static const int windowsItemVMargin = 2; // menu item ver text margin +static const int windowsArrowHMargin = 6; // arrow horizontal margin +static const int windowsRightBorder = 15; // right border on windows + +class DotNetStylePrivate +{ +public: + DotNetStylePrivate() + { + QLibrary themeLib("uxtheme"); + themeLib.load(); + if (themeLib.isLoaded()) { //resolve uxtheme functions + pIsAppThemed = (PtrIsAppThemed)themeLib.resolve("IsAppThemed"); + pGetCurrentThemeName = (PtrGetCurrentThemeName)themeLib.resolve("GetCurrentThemeName"); + } + } + ~DotNetStylePrivate() + {} + + enum InternalPalette { + Blue, + Silver, + Olive, + System, + Classic + }; + + void init(); + QColor gradientDarkColor(const QStyleOption *option) const; + QColor gradientLightColor(const QStyleOption *option) const; + QColor highlightOutlineColor(const QStyleOption *option, bool act) const; + QColor shadowColor(const QStyleOption *option) const; + QBrush highlightBrush(const QStyleOption *option, bool act) const; + QBrush highlightMenuCheckBrush(const QStyleOption *option, bool act) const; + QLinearGradient toolbarGradient(const QStyleOption *option, QRect rect, Qt::Orientation orientaion) const; + QLinearGradient menuGradient(const QStyleOption *option, QRect rect, Qt::Orientation orientaion) const; + void updatePalette(); + + QColor menuSeparatorColor; + QColor menuBackgroundColor; + QColor menuFrameColor; + InternalPalette internalPalette; //internal color theme + DotNetStyle::ColorTheme theme; //external color theme + QPalette currentPal; //used to detect system palette changes + }; + + + +inline QColor DotNetStylePrivate::gradientDarkColor(const QStyleOption *option) const { + QColor color = option->palette.background().color(); + switch (internalPalette) { + case Olive: + color = QColor(217, 217, 167); + break; + case Blue: + color = QColor(158, 190, 245); + break; + case Silver: + color = QColor(216, 216, 229); + break; + default: + break; + } + return color; +} + +inline QColor DotNetStylePrivate::gradientLightColor(const QStyleOption *option) const { + QColor color = option->palette.background().color().lighter(106); + switch (internalPalette) { + case Olive: + color = QColor(241, 240, 227); + break; + case Blue: + color = QColor(196, 217, 249); + break; + case Silver: + color = QColor(242, 242, 247); + break; + case Classic: + color = option->palette.light().color().lighter(106); + default: + break; + } + return color; +} + +inline QColor DotNetStylePrivate::shadowColor(const QStyleOption *option) const { + QColor color; + switch (internalPalette) { + case Blue: + color = QColor(59, 97, 156); + break; + case Silver: + color = QColor(124, 124, 148); + break; + case Olive: + color = QColor(96, 128, 88); + break; + case Classic: + color = option->palette.background().color(); + break; + default: + color = option->palette.dark().color(); + break; + } + return color; +} + +inline QColor DotNetStylePrivate::highlightOutlineColor(const QStyleOption *option, bool act = false) const { + QColor color; + switch (internalPalette) { + case Blue: + color = QColor(0, 0, 128); + break; + case Silver: + color = QColor(75, 75, 111); + break; + case Olive: + color = QColor(63, 93, 56); + break; + default: + if (act) + return option->palette.highlight().color().darker(110); + else + return option->palette.highlight().color().lighter(110); + break; + } + return color; +} + +QBrush DotNetStylePrivate::highlightBrush(const QStyleOption *option, bool act) const { + QBrush brush; + QColor highlight; + switch (internalPalette) { + case Silver: + case Olive: + case Blue: + if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast(option)) { + brush = QColor(255, 238, 194); + } else { + QLinearGradient gradient(option->rect.topLeft(), option->rect.bottomLeft()); + if (act) { + gradient.setColorAt(0, QColor(254, 149, 82)); + gradient.setColorAt(1, QColor(255, 211, 142)); + } else { + gradient.setColorAt(0, QColor(255, 252, 200)); + gradient.setColorAt(1, QColor(255, 208, 145)); + } + brush = gradient; + } + break; + default: + highlight = option->palette.highlight().color().lighter(120); + if (act) + highlight.setHsv(highlight.hue(), 70, 220); + else + highlight.setHsv(highlight.hue(), 40, 230); + brush = QBrush(highlight); + break; + } + return brush; +} + +QBrush DotNetStylePrivate::highlightMenuCheckBrush(const QStyleOption *option, bool act) const { + QBrush brush; + QColor highlight; + + switch (internalPalette) { + case Silver: + case Olive: + case Blue: + if (act) + brush = QColor(254, 128, 62); + else + brush = QColor(255, 192, 111); + break; + default: + highlight = option->palette.highlight().color().lighter(120); + if (act) + highlight.setHsv(highlight.hue(), 120, 180); + else { + highlight.setHsv(highlight.hue(), 30, 230); + } + highlight.setAlpha(170); + brush = highlight; + break; + } + return brush; +} + +QLinearGradient DotNetStylePrivate::toolbarGradient(const QStyleOption *option, QRect rect, Qt::Orientation orientation= Qt::Vertical) const { + QLinearGradient gradient(rect.topLeft(), orientation == Qt::Vertical ? rect.topRight() : rect.bottomLeft()); + QColor start, stop; + switch (internalPalette) + { + case Blue: + start = QColor(220, 235, 254); + stop = QColor(129, 169, 226); + gradient.setColorAt(0.3, start); + break; + case Silver: + start = QColor(242, 242, 249); + stop = QColor(153, 151, 181); + gradient.setColorAt(0.3, start); + break; + case Olive: + start = QColor(241, 245, 217); + stop = QColor(183, 198, 145); + gradient.setColorAt(0.0, start); + break; + default: + start = option->palette.light().color(); + if (internalPalette == Classic) + start = start.lighter(130); + start.setAlpha(180); + stop = option->palette.button().color(); + stop.setHsv(stop.hue(), qMin(stop.saturation()*2, 255), (stop.value()*2)/3); + stop.setAlpha(128); + if (internalPalette == Classic) + stop.setAlpha(0); + gradient.setColorAt(0.3, start); + break; + } + gradient.setColorAt(1, stop); + return gradient; +} + + +QLinearGradient DotNetStylePrivate::menuGradient(const QStyleOption *option, QRect rect, Qt::Orientation orientaion = Qt::Horizontal) const { + + QColor start, stop; + QLinearGradient grad; + if (orientaion == Qt::Vertical) { + grad.setStart(rect.left(), rect.top()); + grad.setFinalStop(rect.left(), rect.bottom()); + } else { + grad.setStart(QPoint(rect.left(), 0)); + grad.setFinalStop(QPoint(rect.left() + 24, 0)); + } + switch (internalPalette) + { + case Blue: + start = QColor(220, 235, 254); + stop = QColor(129, 169, 226); + grad.setColorAt(0.3, start); + break; + case Olive: + start = QColor(246, 248, 224); + stop = QColor(186, 201, 148); + grad.setColorAt(0.0, start); + break; + case Silver: + start = QColor(215, 215, 226); + stop = QColor(138, 137, 166); + grad.setColorAt(0.4, start); + break; + default: + start = option->palette.brush(QPalette::Active, QPalette::Base).color(); + stop = gradientDarkColor(option); + stop.setHsv(stop.hue(), qMin((int)(stop.saturation()*1.2), 255), (5*stop.value()/7)); + if (internalPalette == Classic) + stop.setAlpha(120); + grad.setColorAt(0, start); + break; + } + grad.setColorAt(1, stop); + return grad; +} + + + +/*! + \class DotNetStyle qtdotnetstyle.h + \brief The DotNetStyle class provides an alternative, modern look for Qt applications on Windows. + + The GUI look is very similar to the style introduced in + Visual Studio 2005, Office 2003 as well as in .NET Windows + Forms (when the RenderMode is set to "Professional" + instead of "System"). It gives applications a modern + gradient appearance for tool bars and menus while + retaining the native look and feel for other widgets. + + The style supports different color themes, which may be specified in + the constructor. The default is \c Standard color theme. + + This is the textedit example running with the Standard style: + \img dotnetstyle.png + + This is the textedit example running with the Office style: + \img dotnetstyle2.png + + \sa QStyle, QWindowsVistaStyle, QWindowsXPStyle +*/ + + +/*! + \enum DotNetStyle::ColorTheme + + This enum describes the different color schemes supported by the style. + + \value Standard Use gradients based on the operating system palette. + \value Office Use Microsoft Office 2003 style gradients. +*/ + +/*! + Constructs a DotNetStyle object which uses the default color + theme (\c Office). +*/ +DotNetStyle::DotNetStyle() +: QWindowsVistaStyle(), d(new DotNetStylePrivate()) +{ + d->theme = Office; +} + + +/*! + Constructs a DotNetStyle object which uses the color theme \a + colortheme. +*/ +DotNetStyle::DotNetStyle(ColorTheme colortheme) + : QWindowsVistaStyle(), d(new DotNetStylePrivate()) +{ + d->theme = colortheme; +} + + +/*! + Destroys the DotNetStyle object. +*/ +DotNetStyle::~DotNetStyle() +{ + delete d; +} + + +/*! + \reimp + */ +void DotNetStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const +{ + QColor gradientDark = d->gradientDarkColor(option); + QColor gradientLight = d->gradientLightColor(option); + QColor shadow = d->shadowColor(option); + + QRect rect = option->rect; + switch (element) { + case PE_IndicatorDockWidgetResizeHandle: + break; + case PE_PanelLineEdit: + if (widget && qobject_cast(widget->parentWidget())) { + QRect rect = option->rect.adjusted(2, 1, -2, -2); + painter->save(); + bool active = option->state & State_Active && + ((option->state & State_MouseOver) + || (option->state & State_HasFocus)); + QBrush editBrush = option->palette.brush(QPalette::Base); + painter->setPen(QPen(editBrush.color())); + painter->fillRect(rect, editBrush); + + QRect re = option->rect ; + if (active) { + painter->setPen(d->highlightOutlineColor(option)); + painter->drawRect(rect); + } + painter->restore(); + } else { + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::drawPrimitive(element, option, painter, widget); + else + QWindowsXPStyle::drawPrimitive(element, option, painter, widget); + } + case PE_PanelButtonTool: + { + QStyleOption opt2 = *option; + if (widget) + if(QDockWidget *dw = qobject_cast(widget->parentWidget())) { + if (!dw->isFloating()) + opt2.palette.setBrush(QPalette::Button, Qt::transparent); + } + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::drawPrimitive(element, &opt2, painter, widget); + else + QWindowsXPStyle::drawPrimitive(element, &opt2, painter, widget); + } + break; + case PE_FrameMenu: + { + QPen pen = painter->pen(); + QBrush brush = painter->brush(); + if (const QStyleOptionToolBar *toolbar = qstyleoption_cast(option)) + { + Qt::Orientation orientation =(toolbar->toolBarArea == Qt::RightToolBarArea || + toolbar->toolBarArea == Qt::LeftToolBarArea) ? + Qt::Vertical : Qt::Horizontal; + painter->setBrush(d->toolbarGradient(toolbar, toolbar->rect, orientation)); + } else { + painter->setBrush(d->menuBackgroundColor); + } + painter->setPen(d->menuFrameColor); + painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); + painter->setPen(pen); + painter->setBrush(brush); + } + break; + case PE_Widget: + if (const QMainWindow *mw = qobject_cast(widget)) { + if (d->currentPal != qApp->palette()) //workaround for style polish on theme color change + { + d->currentPal = qApp->palette(); + d->updatePalette(); + } + painter->save(); + QPoint begin = widget->geometry().topRight(); + QPoint end = widget->geometry().topLeft() + QPoint(0, widget->geometry().height()/2); + begin = widget->mapFromGlobal(begin); + end = widget->mapFromGlobal(end); + QLinearGradient menubargradient(begin, end); + menubargradient.setColorAt(0, gradientLight); + if (d->internalPalette == DotNetStylePrivate::System) + menubargradient.setColorAt(0.3, gradientDark); + else + menubargradient.setColorAt(0.8, gradientDark); + menubargradient.setColorAt(1, gradientDark); + QRect windowRect = option->rect; + if (QStatusBar *statusBar = mw->findChild()) { + windowRect.adjust(0, 0, 0, -statusBar->height()); + painter->setPen(option->palette.background().color().lighter(106)); + painter->drawLine(windowRect.bottomLeft() + QPoint(0, 1), + windowRect.bottomRight() + QPoint(0, 1)); + } + painter->fillRect(windowRect, menubargradient); + painter->restore(); + } + break; + case PE_IndicatorToolBarSeparator: + { + QRect rect = option->rect; + shadow.setAlpha(180); + painter->setPen(shadow); + const int margin = 3; + if (option->state & State_Horizontal) { + const int offset = rect.width()/2; + painter->drawLine(rect.bottomLeft().x() + offset, + rect.bottomLeft().y() - margin, + rect.topLeft().x() + offset, + rect.topLeft().y() + margin); + painter->setPen(QPen(option->palette.background().color().light(110))); + painter->drawLine(rect.bottomLeft().x() + offset + 1, + rect.bottomLeft().y() - margin, + rect.topLeft().x() + offset + 1, + rect.topLeft().y() + margin); + } else { //Draw vertical separator + const int offset = rect.height()/2; + painter->setPen(QPen(option->palette.background().color().dark(110))); + painter->drawLine(rect.topLeft().x() + margin , + rect.topLeft().y() + offset, + rect.topRight().x() - margin, + rect.topRight().y() + offset); + painter->setPen(QPen(option->palette.background().color().light(110))); + painter->drawLine(rect.topLeft().x() + margin , + rect.topLeft().y() + offset + 1, + rect.topRight().x() - margin, + rect.topRight().y() + offset + 1); + } + } + break; + case PE_IndicatorToolBarHandle: + painter->save(); + { + QColor gripColor = shadow; + if (d->internalPalette != DotNetStylePrivate::System) + gripColor = shadow.darker(120); + if (option->state & State_Horizontal) { + for (int i = rect.height()/5; i <= 4*(rect.height()/5) ; i+=4) { + int y = rect.topLeft().y() + i + 1; + int x1 = rect.topLeft().x() + 3; + painter->fillRect(x1 + 1, y, 2, 2, Qt::white); + painter->fillRect(x1, y - 1, 2, 2, gripColor); + } + } + else { //vertical toolbar + for (int i = rect.width()/5; i <= 4*(rect.width()/5) ; i+=4) { + int x = rect.topLeft().x() + i + 1; + int y1 = rect.topLeft().y() + 3; + painter->fillRect(x , y1 + 1, 2, 2, Qt::white); + painter->fillRect(x - 1, y1, 2, 2, gripColor); + } + } + } + painter->restore(); + break; + case PE_PanelMenuBar: + break; + default: + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::drawPrimitive(element, option, painter, widget); + else + QWindowsXPStyle::drawPrimitive(element, option, painter, widget); + break; + } +} + +/*! + \reimp + */ +void DotNetStyle::drawControl(ControlElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const +{ + + QColor gradientDark = d->gradientDarkColor(option); + QColor gradientLight = d->gradientLightColor(option); + QColor shadow = d->shadowColor(option); + QRect rect = option->rect; + + switch (element) { +#ifndef QT_NO_MENU + case CE_MenuItem: + painter->save(); + if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast(option)) { + int x, y, w, h; + QStyleOptionMenuItem mbiCopy = *menuitem; + painter->fillRect(rect, d->menuBackgroundColor); + painter->fillRect(QRect(0, rect.top(), 25, rect.bottom()), d->menuGradient(option, rect)); + menuitem->rect.getRect(&x, &y, &w, &h); + + int tab = menuitem->tabWidth; + bool dis = !(menuitem->state & State_Enabled); + bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable + ? menuitem->checked : false; + bool act = menuitem->state & State_Selected; + + // windows always has a check column, regardless whether we have an icon or not + int checkcol = qMax(menuitem->maxIconWidth, 20); + if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) { + int yoff = y-1 + h / 2; + painter->setPen(d->menuSeparatorColor); + painter->drawLine(x + 32, yoff, x + w + 6, yoff); + painter->restore(); + return; + } + + QRect vCheckRect = visualRect(option->direction, menuitem->rect, + QRect(menuitem->rect.x(), menuitem->rect.y(), checkcol, menuitem->rect.height())); + vCheckRect.adjust(2, 0, 0, 0); + + if (act) { + painter->setPen(d->highlightOutlineColor(option)); + painter->setBrush(d->highlightBrush(option, false)); + painter->drawRect(option->rect.adjusted(0, 0, -2, -2)); + } + + if (!menuitem->icon.isNull()) { + QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; + if (act && !dis) + mode = QIcon::Active; + QPixmap pixmap; + if (checked) + pixmap = menuitem->icon.pixmap(pixelMetric(PM_SmallIconSize), mode, QIcon::On); + else + pixmap = menuitem->icon.pixmap(pixelMetric(PM_SmallIconSize), mode); + int pixw = pixmap.width(); + int pixh = pixmap.height(); + QRect pmr(0, 0, pixw, pixh); + pmr.moveCenter(vCheckRect.center()); + painter->setPen(menuitem->palette.text().color()); + painter->drawPixmap(pmr.topLeft(), pixmap); + } else if (checked) { + painter->save(); + painter->setPen(d->highlightOutlineColor(option, act)); + painter->setBrush(d->highlightMenuCheckBrush(option, act)); + painter->drawRect(vCheckRect.adjusted(-1, 1, 0, -3)); + painter->restore(); + + QStyleOptionMenuItem newMi = *menuitem; + newMi.state = State_None; + if (!dis) + newMi.state |= State_Enabled; + if (act) + newMi.state |= State_On; + newMi.rect = visualRect(option->direction, menuitem->rect, + QRect(menuitem->rect.x() + windowsItemFrame, menuitem->rect.y() + windowsItemFrame, + checkcol - 2 * windowsItemFrame, menuitem->rect.height() - 2*windowsItemFrame)); + drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, painter, widget); + } + painter->setPen(menuitem->palette.buttonText().color()); + + QColor discol; + if (dis) { + discol = menuitem->palette.text().color(); + painter->setPen(discol); + } + + int xm = windowsItemFrame + checkcol + windowsItemHMargin; + int xpos = menuitem->rect.x() + xm; + QRect textRect(xpos + 5, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin); + QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect); + QString s = menuitem->text; + + if (!s.isEmpty()) { // draw text + painter->save(); + int t = s.indexOf(QLatin1Char('\t')); + int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; + if (!styleHint(SH_UnderlineShortcut, menuitem, widget)) + text_flags |= Qt::TextHideMnemonic; + text_flags |= Qt::AlignLeft; + if (t >= 0) { + QRect vShortcutRect = visualRect(option->direction, menuitem->rect, + QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom()))); + if (dis && !act) { + painter->setPen(discol); + } + painter->drawText(vShortcutRect, text_flags, s.mid(t + 1)); + s = s.left(t); + } + QFont font = menuitem->font; + if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem) + font.setBold(true); + painter->setFont(font); + if (dis && !act) { + painter->setPen(discol); + } + painter->drawText(vTextRect, text_flags, s.left(t)); + painter->restore(); + } + if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow + int dim = (h - 2 * windowsItemFrame) / 2; + PrimitiveElement arrow; + arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight; + xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim; + QRect vSubMenuRect = visualRect(option->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim)); + QStyleOptionMenuItem newMI = *menuitem; + newMI.rect = vSubMenuRect; + newMI.state = dis ? State_None : State_Enabled; + drawPrimitive(arrow, &newMI, painter, widget); + } + } + painter->restore(); + break; +#endif // QT_NO_MENU + + case CE_MenuEmptyArea: + { + painter->fillRect(option->rect, option->palette.base()); + QLinearGradient grad(QPoint(rect.left() , 0), QPoint(rect.left() + 23, 0)); + grad.setColorAt(0, gradientLight.light(110)); + grad.setColorAt(1, gradientDark); + painter->fillRect(QRect(0, rect.top() + 2, 23, rect.bottom() - 3), grad); + } + break; + case CE_MenuBarItem: + if (const QStyleOptionMenuItem *mbi = qstyleoption_cast(option)) { + QRect rect(QPoint(0, 0), widget->window()->size()); + { + if (widget->window()) + drawPrimitive(PE_Widget, option, painter, widget); + } + if (option->state & (QStyle::State_Sunken | QStyle::State_Selected)) + { + QColor highlight = shadow; + painter->setPen(d->menuFrameColor); + if (option->state & QStyle::State_Sunken) { + + if (d->internalPalette == DotNetStylePrivate::System) + painter->setBrush(Qt::white); + else + painter->setBrush(d->menuGradient(option, option->rect, Qt::Vertical)); + + painter->drawRect(option->rect.adjusted(0, 2, -1, 0)); + //draw shadow behind: + QColor shade = Qt::black; + shade.setAlpha(50); + painter->setBrush(shade); + painter->setPen(Qt::transparent); + QRect shadowRect(option->rect.topRight() + QPoint(0, 4), option->rect.bottomRight() + QPoint(1,0)); + painter->drawRect(shadowRect); + } + else { + painter->setPen(d->highlightOutlineColor(option)); + painter->setBrush(d->highlightBrush(option, false)); + painter->drawRect(option->rect.adjusted(0, 2, -2, -2)); + } + } + QStyleOptionMenuItem mbiCopy = *mbi; + QPalette pal = mbi->palette; + pal.setBrush(QPalette::All, QPalette::ButtonText, mbi->palette.text()); + mbiCopy.palette = pal; + QCommonStyle::drawControl(element, &mbiCopy, painter, widget); + } + break; + case CE_MenuBarEmptyArea: + if (widget->window()) + drawPrimitive(PE_Widget, option, painter, widget); + break; + case CE_DockWidgetTitle: + if (const QDockWidget *dockWidget = qobject_cast(widget)) { + painter->save(); + if (d->internalPalette == DotNetStylePrivate::System) { + painter->setBrush(option->palette.dark().color().light(130)); + painter->setPen(option->palette.dark().color()); + } else if (d->internalPalette == DotNetStylePrivate::Classic) { + painter->setBrush(option->palette.background().color().dark(108)); + painter->setPen(option->palette.dark().color()); + } else { + painter->setBrush(d->toolbarGradient(option, option->rect, Qt::Horizontal)); + QColor color = d->gradientDarkColor(option).darker(120); + painter->setPen(color); + } + painter->drawRect(rect.adjusted(0, 2, -1, -3)); + + if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast(option)) { + QRect titleRect = option->rect.adjusted(6, 2, 0, 0); + int buttonMargin = 4; + int mw = pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget); + if (dwOpt->closable) { + QPixmap pm = standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt, widget).pixmap(10, 10); + titleRect.adjust(0, 0, -pm.size().width() - mw - buttonMargin, 0); + } + if (dwOpt->floatable) { + QPixmap pm = standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt, widget).pixmap(10, 10); + titleRect.adjust(0, 0, -pm.size().width() - mw - buttonMargin, 0); + } + titleRect = visualRect(option->direction, option->rect, titleRect); + + if (!dwOpt->title.isEmpty()) { + QString titleText = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width()); + drawItemText(painter, titleRect, + Qt::AlignLeft | Qt::AlignVCenter, dwOpt->palette, + dwOpt->state & State_Enabled, titleText, + QPalette::WindowText); + } + painter->restore(); + } + break; + } + case CE_ToolBar: + if (const QStyleOptionToolBar *toolbar = qstyleoption_cast(option)) { + painter->save(); + rect.adjust(1, 0, 0, 0); + + if (const QToolBar *tb = qobject_cast(widget)) { + if (option->direction == Qt::LeftToRight) + rect.setRight(tb->childrenRect().right() + 2); + else + rect.setLeft(tb->childrenRect().left() - 2); + } + Qt::Orientation gradientOrientation =(toolbar->toolBarArea == Qt::RightToolBarArea || + toolbar->toolBarArea == Qt::LeftToolBarArea) ? Qt::Vertical : Qt::Horizontal; + QLinearGradient gradient = d->toolbarGradient(toolbar, rect, gradientOrientation); + painter->setBrush(gradient); + painter->setPen(Qt::NoPen); + + bool roundEdges = true; + if (widget && widget->parentWidget()) { + if (const QToolBar *tb = qobject_cast(widget)) { + if (!(tb->childrenRect().width() + 32 < widget->parentWidget()->geometry().width())) { + roundEdges = false; + rect.adjust(-1, 0, 0, 0); + } + } + } + if (roundEdges) { + rect = rect.adjusted(1, 1, -1, 0); + QRegion region = rect; + region -= QRect(rect.left(), rect.bottom(), 2, 1); + region -= QRect(rect.right() - 1, rect.bottom(), 2, 1); + region -= QRect(rect.left(), rect.bottom() - 1, 1, 1); + region -= QRect(rect.right(), rect.bottom() - 1, 1, 1); + region -= QRect(rect.left(), rect.top(), 2, 1); + region -= QRect(rect.right() - 1, rect.top(), 2, 1); + region -= QRect(rect.left(), rect.top() + 1, 1, 1); + region -= QRect(rect.right(), rect.top() + 1, 1, 1); + painter->setClipRegion(region); + + painter->fillRect(rect, gradient); + + painter->setPen(QPen(shadow, 0)); + painter->drawLine(rect.bottomLeft() + QPoint(3,0), rect.bottomRight() - QPoint(2,0)); + painter->drawPoint(rect.bottomRight() - QPoint(1, 1)); + QColor alphashadow = shadow; + alphashadow.setAlpha(128); + painter->setPen(QPen(alphashadow, 0)); + painter->drawLine(rect.topRight() + QPoint(0, 2), rect.bottomRight() - QPoint(0, 2)); + } else { + painter->fillRect(rect, gradient); + } + painter->restore(); + } + break; + default: + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::drawControl(element, option, painter, widget); + else + QWindowsXPStyle::drawControl(element, option, painter, widget); + break; + } +} + +/*! + \reimp + */ +void DotNetStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, + QPainter *painter, const QWidget *widget) const +{ + switch (control) { + case CC_ComboBox: + if (widget && qobject_cast(widget->parentWidget())) { + QColor highlightedOutlineColor = d->highlightOutlineColor(option); + if (const QStyleOptionComboBox *cmb = qstyleoption_cast(option)) + { + bool active = cmb->state & State_Active && + ((cmb->state & State_MouseOver) + || (cmb->state & State_On) + || (cmb->state & State_HasFocus)); + QRect editRect = QWindowsStyle::subControlRect(CC_ComboBox, cmb, SC_ComboBoxEditField, widget).adjusted(0, 0, 3, 1); + QRect rect = option->rect.adjusted(1, 1, -3, -2); + editRect.setLeft(rect.left()); + + if (cmb->subControls & SC_ComboBoxEditField) { + painter->save(); + QBrush editBrush = cmb->palette.brush(QPalette::Base); + painter->setPen(QPen(editBrush.color())); + painter->drawRect(rect); + painter->fillRect(editRect, editBrush); + + if (active) { + QColor highlight = highlightedOutlineColor; + painter->setPen(highlight); + painter->drawRect(rect); + } + painter->restore(); + } + + if (cmb->subControls & SC_ComboBoxArrow) { + State flags = State_None; + + QRect ar = QWindowsStyle::subControlRect(CC_ComboBox, cmb, SC_ComboBoxArrow, widget).adjusted(1, 0, -1, 0); + if (active) { + painter->save(); + painter->fillRect(ar, d->highlightBrush(option, cmb->state & State_Sunken)); + painter->setPen(highlightedOutlineColor); + painter->drawLine(ar.topLeft(), ar.bottomLeft()); + painter->restore(); + } + ar.adjust(5, 5, -2, -2); + if (option->state & State_Enabled) + flags |= State_Enabled; + QStyleOption arrowOpt(0); + arrowOpt.rect = ar; + arrowOpt.palette = cmb->palette; + arrowOpt.state = flags; + QWindowsStyle::drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget); + } + } + } else { + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::drawComplexControl(control, option, painter, widget); + else + QWindowsXPStyle::drawComplexControl(control, option, painter, widget); + } + break; + + case CC_ToolButton: + if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast(option)) + { + QRect button; + button = subControlRect(control, toolbutton, SC_ToolButton, widget); + if ((widget && qobject_cast(widget->parentWidget())) && + ((toolbutton->state & State_MouseOver && toolbutton->state & State_Enabled) + || toolbutton->state & State_On)) { + QLinearGradient menubargradient2(button.topLeft(), button.bottomLeft()); + + bool act = (toolbutton->state & State_Sunken) || (toolbutton->state & State_On); + painter->setPen(d->highlightOutlineColor(option, act)); + painter->setBrush(d->highlightBrush(option, act)); + painter->drawRect(button.adjusted(0, 0, -2, -1)); + + QStyleOptionComplex comp; + comp.init(widget); + comp.rect = button; + QStyleOptionToolButton label = *toolbutton; + int fw = pixelMetric(PM_DefaultFrameWidth, option, widget); + label.rect = button.adjusted(fw, fw, -fw, -fw); + label.features &= ~QStyleOptionToolButton::Arrow; + drawControl(CE_ToolButtonLabel, &label, painter, widget); + + if (toolbutton->subControls & SC_ToolButtonMenu) { + QStyleOption tool = *toolbutton; + tool.rect = QWindowsStyle::subControlRect(control, toolbutton, SC_ToolButtonMenu, widget); + painter->setPen(d->highlightOutlineColor(option, act)); + painter->setBrush(d->highlightBrush(option, toolbutton->activeSubControls & SC_ToolButtonMenu)); + painter->drawRect(tool.rect.adjusted(-2, 0, -1, -1)); + tool.rect.adjust(2, 3, -2, -2); + drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget); + } + } else + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::drawComplexControl(control, option, painter, widget); + else + QWindowsXPStyle::drawComplexControl(control, option, painter, widget); + } + break; + + default: + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::drawComplexControl(control, option, painter, widget); + else + QWindowsXPStyle::drawComplexControl(control, option, painter, widget); + break; + } +} + +/*! + \reimp + */ +QSize DotNetStyle::sizeFromContents(ContentsType type, const QStyleOption *option, + const QSize &size, const QWidget *widget) const +{ + QSize newSize; + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + newSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget); + else + newSize = QWindowsXPStyle::sizeFromContents(type, option, size, widget); + + switch (type) { + case CT_LineEdit: + if (widget && qobject_cast(widget->parentWidget())) { + newSize = QWindowsStyle::sizeFromContents(type, option, size, widget); + newSize += QSize(0, 2); + } + break; + case CT_ComboBox: + if (widget && qobject_cast(widget->parentWidget())) { + newSize = QWindowsStyle::sizeFromContents(type, option, size, widget); + newSize += QSize(0, 2); + } + break; + case CT_MenuBarItem: + newSize += QSize(0, 1); + break; + case CT_MenuItem: + if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast(option)) { + newSize = QWindowsStyle::sizeFromContents(type, option, size, widget); + if (menuitem->menuItemType == QStyleOptionMenuItem::Separator){ + newSize.setHeight(2); + } else { + newSize.rwidth() += 10; + //ensure menu items have uniform height + if (newSize.height() < 22) + newSize.setHeight(22); + } + } + break; + case CT_Menu: + //work around for a menu frame issue (same as xp style) + newSize = size; + newSize -= QSize(1,2); + break; + default: + break; + } + return newSize; +} + +/*! + \reimp + */ +QRect DotNetStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + QRect rect; + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + rect = QWindowsVistaStyle::subElementRect(element, option, widget); + else + rect = QWindowsXPStyle::subElementRect(element, option, widget); + if (element == SE_DockWidgetCloseButton || element == SE_DockWidgetFloatButton) + rect.translate(0, 1); + return rect; +} + +/*! + \reimp + */ +QRect DotNetStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, + SubControl subControl, const QWidget *widget) const +{ + QRect rect; + if (control == CC_ComboBox && widget && qobject_cast(widget->parentWidget())) + rect = QWindowsStyle::subControlRect(control, option, subControl, widget); + else if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + rect = QWindowsVistaStyle::subControlRect(control, option, subControl, widget); + else + rect = QWindowsXPStyle::subControlRect(control, option, subControl, widget); + + return rect; +} + +/*! + \reimp + */ +QStyle::SubControl DotNetStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, + const QPoint &pos, const QWidget *widget) const +{ + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + return QWindowsVistaStyle::hitTestComplexControl(control, option, pos, widget); + else + return QWindowsXPStyle::hitTestComplexControl(control, option, pos, widget); +} + +/*! + \reimp + */ +int DotNetStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + int retval = 0; + + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + retval = QWindowsVistaStyle::pixelMetric(metric, option, widget); + else + retval = QWindowsXPStyle::pixelMetric(metric, option, widget); + + switch (metric) { + case PM_ToolBarItemSpacing: + retval = 2; + break; + case PM_ToolBarIconSize: + retval = 16; + break; + case PM_MenuHMargin: + retval = 1; + break; + case PM_MenuVMargin: + retval = 1; + break; + case PM_MenuBarPanelWidth: + retval = 0; + break; + case PM_MenuPanelWidth: + retval = 1; + break; + case PM_DockWidgetTitleBarButtonMargin: + retval = 6; + break; + case PM_DefaultFrameWidth: + case PM_SpinBoxFrameWidth: + if (widget && qobject_cast(widget->parentWidget())) + retval = 2; + break; + case PM_ButtonShiftVertical: + case PM_ButtonShiftHorizontal: + if (widget && qobject_cast(widget->parentWidget())) + retval = 0; + break; + default: + break; + } + return retval; +} + +/*! + \reimp + */ +QPalette DotNetStyle::standardPalette() const +{ + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + return QWindowsVistaStyle::standardPalette(); + else + return QWindowsXPStyle::standardPalette(); +} + + +void DotNetStylePrivate::updatePalette() +{ + //Detect color palette + const int maxlength = 256; + WCHAR themeFileName[maxlength]; + WCHAR themeColor[maxlength]; + internalPalette = Classic; + if (pIsAppThemed && pIsAppThemed() && pGetCurrentThemeName(themeFileName, maxlength, themeColor, maxlength, NULL, 0) == S_OK) { + QString name = QString::fromUtf16((ushort *)themeFileName); + QString color = QString::fromUtf16((ushort *)themeColor); + if (theme == DotNetStyle::Standard) { + if (name.endsWith("Luna.msstyles")) { + if (color == "Metallic") + internalPalette = Silver; + else + internalPalette = System; + } + } else { //Office style + if (name.endsWith("Luna.msstyles")) { + if (color == "HomeStead") + internalPalette = Olive; + else if (color == "Metallic") + internalPalette = Silver; + else + internalPalette = Blue; + } else if (name.endsWith("Aero.msstyles")) { + internalPalette = Blue; + } + } + } + + switch (internalPalette) { + case Blue: + menuSeparatorColor = QColor(106, 140, 203); + menuBackgroundColor = QColor(246, 246, 246); + menuFrameColor = QColor(0, 45, 150); + break; + case Silver: + menuSeparatorColor = QColor(110, 109, 143); + menuBackgroundColor = QColor(254, 250, 255); + menuFrameColor = QColor(124, 124, 148); + break; + case Olive: + menuSeparatorColor = QColor(96, 128, 88); + menuBackgroundColor = QColor(244, 244, 238); + menuFrameColor = QColor(117, 141, 94); + break; + default: + menuFrameColor = currentPal.dark().color().lighter(108); + menuSeparatorColor = currentPal.background().color().darker(110); + menuBackgroundColor = currentPal.light().color(); + menuBackgroundColor.setHsv( + menuBackgroundColor.hue(), + 3 * menuBackgroundColor.saturation()/8 , + 250); + break; + } +} + +/*! + \reimp + */ +void DotNetStyle::polish(QApplication *app) +{ + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::polish(app); + else + QWindowsXPStyle::polish(app); + d->currentPal = app->palette(); + d->updatePalette(); +} + +/*! + \reimp + */ +void DotNetStyle::unpolish(QApplication *app) +{ + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::unpolish(app); + else + QWindowsXPStyle::unpolish(app); +} + +/*! + \reimp + */ +void DotNetStyle::polish(QWidget *widget) +{ + if (qobject_cast(widget)) + widget->setAttribute(Qt::WA_StyledBackground); + else if (qobject_cast(widget)) + widget->setAttribute(Qt::WA_Hover); + else if (qobject_cast(widget)) + widget->setAttribute(Qt::WA_Hover); + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::polish(widget); + else + QWindowsXPStyle::polish(widget); +} + +/*! + \reimp + */ +void DotNetStyle::unpolish(QWidget *widget) +{ + if (qobject_cast(widget)) + widget->setAttribute(Qt::WA_StyledBackground, false); + else if (qobject_cast(widget)) + widget->setAttribute(Qt::WA_Hover, false); + else if (qobject_cast(widget)) + widget->setAttribute(Qt::WA_Hover, false); + + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::unpolish(widget); + else + QWindowsXPStyle::unpolish(widget); +} + +/*! + \reimp + */ +void DotNetStyle::polish(QPalette &pal) +{ + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + QWindowsVistaStyle::polish(pal); + else + QWindowsXPStyle::polish(pal); +} + +/*! + \reimp + */ +QPixmap DotNetStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, + const QWidget *widget) const +{ + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + return QWindowsVistaStyle::standardPixmap(standardPixmap, opt, widget); + else + return QWindowsXPStyle::standardPixmap(standardPixmap, opt, widget); +} + +/*! + \reimp +*/ +int DotNetStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, + QStyleHintReturn *returnData) const +{ + int ret = 0; + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + ret = QWindowsVistaStyle::styleHint(hint, option, widget, returnData); + else + ret = QWindowsXPStyle::styleHint(hint, option, widget, returnData); + return ret; +} + +#endif //USE_DOTNET_STYLE diff --git a/src/fqterm/3rdparty/dotnetstyle.h b/src/fqterm/3rdparty/dotnetstyle.h new file mode 100644 index 0000000..16326b6 --- /dev/null +++ b/src/fqterm/3rdparty/dotnetstyle.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2007-2007 Trolltech ASA. All rights reserved. +** +** This file is part of the DotNetStyle project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + + +#ifndef QTDOTNETSTYLE_H +#define QTDOTNETSTYLE_H +#ifdef USE_DOTNET_STYLE +#include + +class QLinearGradient; +class QBrush; + +class DotNetStylePrivate; +class DotNetStyle : public QWindowsVistaStyle +{ +public: + enum ColorTheme { + Standard, + Office + }; + DotNetStyle(); + + DotNetStyle(ColorTheme palette); + + ~DotNetStyle(); + + void drawPrimitive(PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget = 0) const; + void drawControl(ControlElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const; + void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, + QPainter *painter, const QWidget *widget) const; + QSize sizeFromContents(ContentsType type, const QStyleOption *option, + const QSize &size, const QWidget *widget) const; + + QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const; + QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, + SubControl sc, const QWidget *widget) const; + + SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, + const QPoint &pos, const QWidget *widget = 0) const; + + QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, + const QWidget *widget = 0) const; + int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, + QStyleHintReturn *returnData = 0) const; + int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const; + void polish(QWidget *widget); + void unpolish(QWidget *widget); + void polish(QPalette &pal); + void polish(QApplication *app); + void unpolish(QApplication *app); + QPalette standardPalette() const; + DotNetStylePrivate *d; +}; +#endif //USE_DOTNET_STYLE +#endif diff --git a/src/fqterm/3rdparty/qxtglobal.h b/src/fqterm/3rdparty/qxtglobal.h new file mode 100644 index 0000000..575372d --- /dev/null +++ b/src/fqterm/3rdparty/qxtglobal.h @@ -0,0 +1,207 @@ +/**************************************************************************** + ** + ** Copyright (C) Qxt Foundation. Some rights reserved. + ** + ** This file is part of the QxtCore module of the Qxt library. + ** + ** This library is free software; you can redistribute it and/or modify it + ** under the terms of the Common Public License, version 1.0, as published + ** by IBM, and/or under the terms of the GNU Lesser General Public License, + ** version 2.1, as published by the Free Software Foundation. + ** + ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY + ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + ** FITNESS FOR A PARTICULAR PURPOSE. + ** + ** You should have received a copy of the CPL and the LGPL along with this + ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files + ** included with the source distribution for more information. + ** If you did not receive a copy of the licenses, contact the Qxt Foundation. + ** + ** + ** + ****************************************************************************/ + +#ifndef QXTGLOBAL_H +#define QXTGLOBAL_H + +#include + +#define QXT_VERSION 0x000600 +#define QXT_VERSION_STR "0.6.0" + +//--------------------------global macros------------------------------ + +#ifndef QXT_NO_MACROS + +#endif // QXT_NO_MACROS + +//--------------------------export macros------------------------------ + +#define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE + +#if !defined(QXT_STATIC) +# if defined(BUILD_QXT_CORE) +# define QXT_CORE_EXPORT Q_DECL_EXPORT +# else +# define QXT_CORE_EXPORT Q_DECL_IMPORT +# endif +#else +# define QXT_CORE_EXPORT +#endif // BUILD_QXT_CORE + +#if !defined(QXT_STATIC) +# if defined(BUILD_QXT_GUI) +# define QXT_GUI_EXPORT Q_DECL_EXPORT +# else +# define QXT_GUI_EXPORT Q_DECL_IMPORT +# endif +#else +# define QXT_GUI_EXPORT +#endif // BUILD_QXT_GUI + +#if !defined(QXT_STATIC) +# if defined(BUILD_QXT_NETWORK) +# define QXT_NETWORK_EXPORT Q_DECL_EXPORT +# else +# define QXT_NETWORK_EXPORT Q_DECL_IMPORT +# endif +#else +# define QXT_NETWORK_EXPORT +#endif // BUILD_QXT_NETWORK + +#if !defined(QXT_STATIC) +# if defined(BUILD_QXT_SQL) +# define QXT_SQL_EXPORT Q_DECL_EXPORT +# else +# define QXT_SQL_EXPORT Q_DECL_IMPORT +# endif +#else +# define QXT_SQL_EXPORT +#endif // BUILD_QXT_SQL + +#if !defined(QXT_STATIC) +# if defined(BUILD_QXT_WEB) +# define QXT_WEB_EXPORT Q_DECL_EXPORT +# else +# define QXT_WEB_EXPORT Q_DECL_IMPORT +# endif +#else +# define QXT_WEB_EXPORT +#endif // BUILD_QXT_WEB + +#if !defined(QXT_STATIC) +# if defined(BUILD_QXT_BERKELEY) +# define QXT_BERKELEY_EXPORT Q_DECL_EXPORT +# else +# define QXT_BERKELEY_EXPORT Q_DECL_IMPORT +# endif +#else +# define QXT_BERKELEY_EXPORT +#endif // BUILD_QXT_BERKELEY + +#if !defined(QXT_STATIC) +# if defined(BUILD_QXT_ZEROCONF) +# define QXT_ZEROCONF_EXPORT Q_DECL_EXPORT +# else +# define QXT_ZEROCONF_EXPORT Q_DECL_IMPORT +# endif +#else +# define QXT_ZEROCONF_EXPORT +#endif // QXT_ZEROCONF_EXPORT + +#if defined BUILD_QXT_CORE || defined BUILD_QXT_GUI || defined BUILD_QXT_SQL || defined BUILD_QXT_NETWORK || defined BUILD_QXT_WEB || defined BUILD_QXT_BERKELEY || defined BUILD_QXT_ZEROCONF +# define BUILD_QXT +#endif + +QXT_CORE_EXPORT const char* qxtVersion(); + +#ifndef QT_BEGIN_NAMESPACE +#define QT_BEGIN_NAMESPACE +#endif + +#ifndef QT_END_NAMESPACE +#define QT_END_NAMESPACE +#endif + +#ifndef QT_FORWARD_DECLARE_CLASS +#define QT_FORWARD_DECLARE_CLASS(Class) class Class; +#endif + +/**************************************************************************** +** This file is derived from code bearing the following notice: +** The sole author of this file, Adam Higerd, has explicitly disclaimed all +** copyright interest and protection for the content within. This file has +** been placed in the public domain according to United States copyright +** statute and case law. In jurisdictions where this public domain dedication +** is not legally recognized, anyone who receives a copy of this file is +** permitted to use, modify, duplicate, and redistribute this file, in whole +** or in part, with no restrictions or conditions. In these jurisdictions, +** this file shall be copyright (C) 2006-2008 by Adam Higerd. +****************************************************************************/ + +#define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface qxt_d; +#define QXT_DECLARE_PUBLIC(PUB) friend class PUB; +#define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this); +#define QXT_D(PUB) PUB##Private& d = qxt_d() +#define QXT_P(PUB) PUB& p = qxt_p() + +template +class QxtPrivate +{ +public: + virtual ~QxtPrivate() + {} + inline void QXT_setPublic(PUB* pub) + { + qxt_p_ptr = pub; + } + +protected: + inline PUB& qxt_p() + { + return *qxt_p_ptr; + } + inline const PUB& qxt_p() const + { + return *qxt_p_ptr; + } + +private: + PUB* qxt_p_ptr; +}; + +template +class QxtPrivateInterface +{ + friend class QxtPrivate; +public: + QxtPrivateInterface() + { + pvt = new PVT; + } + ~QxtPrivateInterface() + { + delete pvt; + } + + inline void setPublic(PUB* pub) + { + pvt->QXT_setPublic(pub); + } + inline PVT& operator()() + { + return *static_cast(pvt); + } + inline const PVT& operator()() const + { + return *static_cast(pvt); + } +private: + QxtPrivateInterface(const QxtPrivateInterface&) { } + QxtPrivateInterface& operator=(const QxtPrivateInterface&) { } + QxtPrivate* pvt; +}; + +#endif // QXT_GLOBAL diff --git a/src/fqterm/3rdparty/qxtglobalshortcut.cpp b/src/fqterm/3rdparty/qxtglobalshortcut.cpp new file mode 100644 index 0000000..0d8f557 --- /dev/null +++ b/src/fqterm/3rdparty/qxtglobalshortcut.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** + ** + ** Copyright (C) Qxt Foundation. Some rights reserved. + ** + ** This file is part of the QxtGui module of the Qxt library. + ** + ** This library is free software; you can redistribute it and/or modify it + ** under the terms of the Common Public License, version 1.0, as published + ** by IBM, and/or under the terms of the GNU Lesser General Public License, + ** version 2.1, as published by the Free Software Foundation. + ** + ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY + ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + ** FITNESS FOR A PARTICULAR PURPOSE. + ** + ** You should have received a copy of the CPL and the LGPL along with this + ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files + ** included with the source distribution for more information. + ** If you did not receive a copy of the licenses, contact the Qxt Foundation. + ** + ** + ** + ****************************************************************************/ +#include "qxtglobalshortcut.h" +#include "qxtglobalshortcut_p.h" +#include +#include + +bool QxtGlobalShortcutPrivate::error = false; +int QxtGlobalShortcutPrivate::ref = 0; +QAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0; +QHash, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts; + +QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier) +{ + if (!ref++) + prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter); +} + +QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate() +{ + if (!--ref) + QAbstractEventDispatcher::instance()->setEventFilter(prevEventFilter); +} + +bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut) +{ + Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier; + key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]); + mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods); + const quint32 nativeKey = nativeKeycode(key); + const quint32 nativeMods = nativeModifiers(mods); + const bool res = registerShortcut(nativeKey, nativeMods); + shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p()); + if (!res) + qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString(); + return res; +} + +bool QxtGlobalShortcutPrivate::unsetShortcut() +{ + const quint32 nativeKey = nativeKeycode(key); + const quint32 nativeMods = nativeModifiers(mods); + const bool res = unregisterShortcut(nativeKey, nativeMods); + shortcuts.remove(qMakePair(nativeKey, nativeMods)); + if (!res) + qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString(); + key = Qt::Key(0); + mods = Qt::KeyboardModifiers(0); + return res; +} + +void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods) +{ + QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods)); + if (shortcut && shortcut->isEnabled()) + emit shortcut->activated(); +} + +/*! + \class QxtGlobalShortcut + \inmodule QxtGui + \brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey". + + A global shortcut triggers even if the application is not active. This + makes it easy to implement applications that react to certain shortcuts + still if some other application is active or if the application is for + example minimized to the system tray. + + Example usage: + \code + QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window); + connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility())); + shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12")); + \endcode + + \bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication. + */ + +/*! + \fn QxtGlobalShortcut::activated() + + This signal is emitted when the user types the shortcut's key sequence. + + \sa shortcut + */ + +/*! + Constructs a new QxtGlobalShortcut with \a parent. + */ +QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent) + : QObject(parent) +{ + QXT_INIT_PRIVATE(QxtGlobalShortcut); +} + +/*! + Constructs a new QxtGlobalShortcut with \a shortcut and \a parent. + */ +QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent) + : QObject(parent) +{ + QXT_INIT_PRIVATE(QxtGlobalShortcut); + setShortcut(shortcut); +} + +/*! + Destructs the QxtGlobalShortcut. + */ +QxtGlobalShortcut::~QxtGlobalShortcut() +{ + if (qxt_d().key != 0) + qxt_d().unsetShortcut(); +} + +/*! + \property QxtGlobalShortcut::shortcut + \brief the shortcut key sequence + + \bold {Note:} Notice that corresponding key press and release events are not + delivered for registered global shortcuts even if they are disabled. + Also, comma separated key sequences are not supported. + Only the first part is used: + + \code + qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B")); + Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A")); + \endcode + */ +QKeySequence QxtGlobalShortcut::shortcut() const +{ + return QKeySequence(qxt_d().key | qxt_d().mods); +} + +bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut) +{ + if (qxt_d().key != 0) + qxt_d().unsetShortcut(); + return qxt_d().setShortcut(shortcut); +} + +/*! + \property QxtGlobalShortcut::enabled + \brief whether the shortcut is enabled + + A disabled shortcut does not get activated. + + The default value is \c true. + + \sa setDisabled() + */ +bool QxtGlobalShortcut::isEnabled() const +{ + return qxt_d().enabled; +} + +void QxtGlobalShortcut::setEnabled(bool enabled) +{ + qxt_d().enabled = enabled; +} + +/*! + Sets the shortcut \a disabled. + + \sa enabled + */ +void QxtGlobalShortcut::setDisabled(bool disabled) +{ + qxt_d().enabled = !disabled; +} + +#include "qxtglobalshortcut.moc" \ No newline at end of file diff --git a/src/fqterm/3rdparty/qxtglobalshortcut.h b/src/fqterm/3rdparty/qxtglobalshortcut.h new file mode 100644 index 0000000..8a352b8 --- /dev/null +++ b/src/fqterm/3rdparty/qxtglobalshortcut.h @@ -0,0 +1,58 @@ +/**************************************************************************** + ** + ** Copyright (C) Qxt Foundation. Some rights reserved. + ** + ** This file is part of the QxtGui module of the Qxt library. + ** + ** This library is free software; you can redistribute it and/or modify it + ** under the terms of the Common Public License, version 1.0, as published + ** by IBM, and/or under the terms of the GNU Lesser General Public License, + ** version 2.1, as published by the Free Software Foundation. + ** + ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY + ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + ** FITNESS FOR A PARTICULAR PURPOSE. + ** + ** You should have received a copy of the CPL and the LGPL along with this + ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files + ** included with the source distribution for more information. + ** If you did not receive a copy of the licenses, contact the Qxt Foundation. + ** + ** + ** + ****************************************************************************/ +#ifndef QXTGLOBALSHORTCUT_H +#define QXTGLOBALSHORTCUT_H + +#include "qxtglobal.h" +#include +#include +class QxtGlobalShortcutPrivate; + +class QxtGlobalShortcut : public QObject +{ + Q_OBJECT + QXT_DECLARE_PRIVATE(QxtGlobalShortcut) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) + Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut) + +public: + explicit QxtGlobalShortcut(QObject* parent = 0); + explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = 0); + virtual ~QxtGlobalShortcut(); + + QKeySequence shortcut() const; + bool setShortcut(const QKeySequence& shortcut); + + bool isEnabled() const; + +public Q_SLOTS: + void setEnabled(bool enabled = true); + void setDisabled(bool disabled = true); + +Q_SIGNALS: + void activated(); +}; + +#endif // QXTGLOBALSHORTCUT_H diff --git a/src/fqterm/3rdparty/qxtglobalshortcut_mac.cpp b/src/fqterm/3rdparty/qxtglobalshortcut_mac.cpp new file mode 100644 index 0000000..7bfbf00 --- /dev/null +++ b/src/fqterm/3rdparty/qxtglobalshortcut_mac.cpp @@ -0,0 +1,262 @@ +/**************************************************************************** + ** + ** Copyright (C) Qxt Foundation. Some rights reserved. + ** + ** This file is part of the QxtGui module of the Qxt library. + ** + ** This library is free software; you can redistribute it and/or modify it + ** under the terms of the Common Public License, version 1.0, as published + ** by IBM, and/or under the terms of the GNU Lesser General Public License, + ** version 2.1, as published by the Free Software Foundation. + ** + ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY + ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + ** FITNESS FOR A PARTICULAR PURPOSE. + ** + ** You should have received a copy of the CPL and the LGPL along with this + ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files + ** included with the source distribution for more information. + ** If you did not receive a copy of the licenses, contact the Qxt Foundation. + ** + ** + ** + ****************************************************************************/ +#include +#include "qxtglobalshortcut_p.h" +#include +#include +#include +#include + +typedef QPair Identifier; +static QMap keyRefs; +static QHash keyIDs; +static quint32 hotKeySerial = 0; +static bool qxt_mac_handler_installed = false; + +OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data) +{ + // pass event to the app event filter + Q_UNUSED(data); + qApp->macEventFilter(nextHandler, event); + return noErr; +} + +bool QxtGlobalShortcutPrivate::eventFilter(void* message) +//bool QxtGlobalShortcutPrivate::macEventFilter(EventHandlerCallRef caller, EventRef event) +{ + EventRef event = (EventRef) message; + if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed) + { + EventHotKeyID keyID; + GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID); + Identifier id = keyIDs.key(keyID.id); + activateShortcut(id.second, id.first); + } + return false; +} + +quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) +{ + quint32 native = 0; + if (modifiers & Qt::ShiftModifier) + native |= shiftKeyBit; + if (modifiers & Qt::ControlModifier) + native |= cmdKey; + if (modifiers & Qt::AltModifier) + native |= optionKey; + if (modifiers & Qt::MetaModifier) + native |= controlKey; + if (modifiers & Qt::KeypadModifier) + native |= kEventKeyModifierNumLockMask; + return native; +} + +quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) +{ + UTF16Char ch; + // Constants found in NSEvent.h from AppKit.framework + switch (key) + { + case Qt::Key_Return: + return kVK_Return; + case Qt::Key_Enter: + return kVK_ANSI_KeypadEnter; + case Qt::Key_Tab: + return kVK_Tab; + case Qt::Key_Space: + return kVK_Space; + case Qt::Key_Backspace: + return kVK_Delete; + case Qt::Key_Control: + return kVK_Command; + case Qt::Key_Shift: + return kVK_Shift; + case Qt::Key_CapsLock: + return kVK_CapsLock; + case Qt::Key_Option: + return kVK_Option; + case Qt::Key_Meta: + return kVK_Control; + case Qt::Key_F17: + return kVK_F17; + case Qt::Key_VolumeUp: + return kVK_VolumeUp; + case Qt::Key_VolumeDown: + return kVK_VolumeDown; + case Qt::Key_F18: + return kVK_F18; + case Qt::Key_F19: + return kVK_F19; + case Qt::Key_F20: + return kVK_F20; + case Qt::Key_F5: + return kVK_F5; + case Qt::Key_F6: + return kVK_F6; + case Qt::Key_F7: + return kVK_F7; + case Qt::Key_F3: + return kVK_F3; + case Qt::Key_F8: + return kVK_F8; + case Qt::Key_F9: + return kVK_F9; + case Qt::Key_F11: + return kVK_F11; + case Qt::Key_F13: + return kVK_F13; + case Qt::Key_F16: + return kVK_F16; + case Qt::Key_F14: + return kVK_F14; + case Qt::Key_F10: + return kVK_F10; + case Qt::Key_F12: + return kVK_F12; + case Qt::Key_F15: + return kVK_F15; + case Qt::Key_Help: + return kVK_Help; + case Qt::Key_Home: + return kVK_Home; + case Qt::Key_PageUp: + return kVK_PageUp; + case Qt::Key_Delete: + return kVK_ForwardDelete; + case Qt::Key_F4: + return kVK_F4; + case Qt::Key_End: + return kVK_End; + case Qt::Key_F2: + return kVK_F2; + case Qt::Key_PageDown: + return kVK_PageDown; + case Qt::Key_F1: + return kVK_F1; + case Qt::Key_Left: + return kVK_LeftArrow; + case Qt::Key_Right: + return kVK_RightArrow; + case Qt::Key_Down: + return kVK_DownArrow; + case Qt::Key_Up: + return kVK_UpArrow; + default: + ; + } + + if (key == Qt::Key_Escape) ch = 27; + else if (key == Qt::Key_Return) ch = 13; + else if (key == Qt::Key_Enter) ch = 3; + else if (key == Qt::Key_Tab) ch = 9; + else ch = key; + + CFDataRef currentLayoutData; + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); + + if (currentKeyboard == NULL) + return 0; + + currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); + CFRelease(currentKeyboard); + if (currentLayoutData == NULL) + return 0; + + UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData); + UCKeyboardTypeHeader* table = header->keyboardTypeList; + + uint8_t *data = (uint8_t*)header; + // God, would a little documentation for this shit kill you... + for (quint32 i=0; i < header->keyboardTypeCount; i++) + { + UCKeyStateRecordsIndex* stateRec = 0; + if (table[i].keyStateRecordsIndexOffset != 0) + { + stateRec = reinterpret_cast(data + table[i].keyStateRecordsIndexOffset); + if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0; + } + + UCKeyToCharTableIndex* charTable = reinterpret_cast(data + table[i].keyToCharTableIndexOffset); + if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue; + + for (quint32 j=0; j < charTable->keyToCharTableCount; j++) + { + UCKeyOutput* keyToChar = reinterpret_cast(data + charTable->keyToCharTableOffsets[j]); + for (quint32 k=0; k < charTable->keyToCharTableSize; k++) + { + if (keyToChar[k] & kUCKeyOutputTestForIndexMask) + { + long idx = keyToChar[k] & kUCKeyOutputGetIndexMask; + if (stateRec && idx < stateRec->keyStateRecordCount) + { + UCKeyStateRecord* rec = reinterpret_cast(data + stateRec->keyStateRecordOffsets[idx]); + if (rec->stateZeroCharData == ch) return k; + } + } + else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE) + { + if (keyToChar[k] == ch) return k; + } + } // for k + } // for j + } // for i + + return 0; +} + +bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) +{ + if (!qxt_mac_handler_installed) + { + EventTypeSpec t; + t.eventClass = kEventClassKeyboard; + t.eventKind = kEventHotKeyPressed; + InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL); + } + + EventHotKeyID keyID; + keyID.signature = 'cute'; + keyID.id = ++hotKeySerial; + + EventHotKeyRef ref = 0; + bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref); + if (rv) + { + keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id); + keyRefs.insert(keyID.id, ref); + } + qDebug() << ref; + return rv; +} + +bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) +{ + Identifier id(nativeMods, nativeKey); + if (!keyIDs.contains(id)) return false; + + EventHotKeyRef ref = keyRefs.take(keyIDs[id]); + keyIDs.remove(id); + return !UnregisterEventHotKey(ref); +} diff --git a/src/fqterm/3rdparty/qxtglobalshortcut_p.h b/src/fqterm/3rdparty/qxtglobalshortcut_p.h new file mode 100644 index 0000000..4570396 --- /dev/null +++ b/src/fqterm/3rdparty/qxtglobalshortcut_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** + ** + ** Copyright (C) Qxt Foundation. Some rights reserved. + ** + ** This file is part of the QxtGui module of the Qxt library. + ** + ** This library is free software; you can redistribute it and/or modify it + ** under the terms of the Common Public License, version 1.0, as published + ** by IBM, and/or under the terms of the GNU Lesser General Public License, + ** version 2.1, as published by the Free Software Foundation. + ** + ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY + ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + ** FITNESS FOR A PARTICULAR PURPOSE. + ** + ** You should have received a copy of the CPL and the LGPL along with this + ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files + ** included with the source distribution for more information. + ** If you did not receive a copy of the licenses, contact the Qxt Foundation. + ** + ** + ** + ****************************************************************************/ +#ifndef QXTGLOBALSHORTCUT_P_H +#define QXTGLOBALSHORTCUT_P_H + +#include "qxtglobalshortcut.h" +#include +#include +#include + +class QxtGlobalShortcutPrivate : public QxtPrivate +{ +public: + QXT_DECLARE_PUBLIC(QxtGlobalShortcut) + QxtGlobalShortcutPrivate(); + ~QxtGlobalShortcutPrivate(); + + bool enabled; + Qt::Key key; + Qt::KeyboardModifiers mods; + + bool setShortcut(const QKeySequence& shortcut); + bool unsetShortcut(); + + static bool error; + static int ref; + static QAbstractEventDispatcher::EventFilter prevEventFilter; + static bool eventFilter(void* message); + +private: + static quint32 nativeKeycode(Qt::Key keycode); + static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers); + + static bool registerShortcut(quint32 nativeKey, quint32 nativeMods); + static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods); + static void activateShortcut(quint32 nativeKey, quint32 nativeMods); + + static QHash, QxtGlobalShortcut*> shortcuts; +}; + +#endif // QXTGLOBALSHORTCUT_P_H diff --git a/src/fqterm/3rdparty/qxtglobalshortcut_win.cpp b/src/fqterm/3rdparty/qxtglobalshortcut_win.cpp new file mode 100644 index 0000000..4099989 --- /dev/null +++ b/src/fqterm/3rdparty/qxtglobalshortcut_win.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** + ** + ** Copyright (C) Qxt Foundation. Some rights reserved. + ** + ** This file is part of the QxtGui module of the Qxt library. + ** + ** This library is free software; you can redistribute it and/or modify it + ** under the terms of the Common Public License, version 1.0, as published + ** by IBM, and/or under the terms of the GNU Lesser General Public License, + ** version 2.1, as published by the Free Software Foundation. + ** + ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY + ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + ** FITNESS FOR A PARTICULAR PURPOSE. + ** + ** You should have received a copy of the CPL and the LGPL along with this + ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files + ** included with the source distribution for more information. + ** If you did not receive a copy of the licenses, contact the Qxt Foundation. + ** + ** + ** + ****************************************************************************/ +#include "qxtglobalshortcut_p.h" +#include + +bool QxtGlobalShortcutPrivate::eventFilter(void* message) +{ + MSG* msg = static_cast(message); + if (msg->message == WM_HOTKEY) + { + const quint32 keycode = HIWORD(msg->lParam); + const quint32 modifiers = LOWORD(msg->lParam); + activateShortcut(keycode, modifiers); + } + return false; +} + +quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) +{ + // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN + quint32 native = 0; + if (modifiers & Qt::ShiftModifier) + native |= MOD_SHIFT; + if (modifiers & Qt::ControlModifier) + native |= MOD_CONTROL; + if (modifiers & Qt::AltModifier) + native |= MOD_ALT; + if (modifiers & Qt::MetaModifier) + native |= MOD_WIN; + // TODO: resolve these? + //if (modifiers & Qt::KeypadModifier) + //if (modifiers & Qt::GroupSwitchModifier) + return native; +} + +quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) +{ + switch (key) + { + case Qt::Key_Escape: + return VK_ESCAPE; + case Qt::Key_Tab: + case Qt::Key_Backtab: + return VK_TAB; + case Qt::Key_Backspace: + return VK_BACK; + case Qt::Key_Return: + case Qt::Key_Enter: + return VK_RETURN; + case Qt::Key_Insert: + return VK_INSERT; + case Qt::Key_Delete: + return VK_DELETE; + case Qt::Key_Pause: + return VK_PAUSE; + case Qt::Key_Print: + return VK_PRINT; + case Qt::Key_Clear: + return VK_CLEAR; + case Qt::Key_Home: + return VK_HOME; + case Qt::Key_End: + return VK_END; + case Qt::Key_Left: + return VK_LEFT; + case Qt::Key_Up: + return VK_UP; + case Qt::Key_Right: + return VK_RIGHT; + case Qt::Key_Down: + return VK_DOWN; + case Qt::Key_PageUp: + return VK_PRIOR; + case Qt::Key_PageDown: + return VK_NEXT; + case Qt::Key_F1: + return VK_F1; + case Qt::Key_F2: + return VK_F2; + case Qt::Key_F3: + return VK_F3; + case Qt::Key_F4: + return VK_F4; + case Qt::Key_F5: + return VK_F5; + case Qt::Key_F6: + return VK_F6; + case Qt::Key_F7: + return VK_F7; + case Qt::Key_F8: + return VK_F8; + case Qt::Key_F9: + return VK_F9; + case Qt::Key_F10: + return VK_F10; + case Qt::Key_F11: + return VK_F11; + case Qt::Key_F12: + return VK_F12; + case Qt::Key_F13: + return VK_F13; + case Qt::Key_F14: + return VK_F14; + case Qt::Key_F15: + return VK_F15; + case Qt::Key_F16: + return VK_F16; + case Qt::Key_F17: + return VK_F17; + case Qt::Key_F18: + return VK_F18; + case Qt::Key_F19: + return VK_F19; + case Qt::Key_F20: + return VK_F20; + case Qt::Key_F21: + return VK_F21; + case Qt::Key_F22: + return VK_F22; + case Qt::Key_F23: + return VK_F23; + case Qt::Key_F24: + return VK_F24; + case Qt::Key_Space: + return VK_SPACE; + case Qt::Key_Asterisk: + return VK_MULTIPLY; + case Qt::Key_Plus: + return VK_ADD; + case Qt::Key_Comma: + return VK_SEPARATOR; + case Qt::Key_Minus: + return VK_SUBTRACT; + case Qt::Key_Slash: + return VK_DIVIDE; + + // numbers + case Qt::Key_0: + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + case Qt::Key_7: + case Qt::Key_8: + case Qt::Key_9: + return key; + + // letters + case Qt::Key_A: + case Qt::Key_B: + case Qt::Key_C: + case Qt::Key_D: + case Qt::Key_E: + case Qt::Key_F: + case Qt::Key_G: + case Qt::Key_H: + case Qt::Key_I: + case Qt::Key_J: + case Qt::Key_K: + case Qt::Key_L: + case Qt::Key_M: + case Qt::Key_N: + case Qt::Key_O: + case Qt::Key_P: + case Qt::Key_Q: + case Qt::Key_R: + case Qt::Key_S: + case Qt::Key_T: + case Qt::Key_U: + case Qt::Key_V: + case Qt::Key_W: + case Qt::Key_X: + case Qt::Key_Y: + case Qt::Key_Z: + return key; + + default: + return 0; + } +} + +bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) +{ + return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey); +} + +bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) +{ + return UnregisterHotKey(0, nativeMods ^ nativeKey); +} diff --git a/src/fqterm/3rdparty/qxtglobalshortcut_x11.cpp b/src/fqterm/3rdparty/qxtglobalshortcut_x11.cpp new file mode 100644 index 0000000..2b2e6b7 --- /dev/null +++ b/src/fqterm/3rdparty/qxtglobalshortcut_x11.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** + ** + ** Copyright (C) Qxt Foundation. Some rights reserved. + ** + ** This file is part of the QxtGui module of the Qxt library. + ** + ** This library is free software; you can redistribute it and/or modify it + ** under the terms of the Common Public License, version 1.0, as published + ** by IBM, and/or under the terms of the GNU Lesser General Public License, + ** version 2.1, as published by the Free Software Foundation. + ** + ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY + ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + ** FITNESS FOR A PARTICULAR PURPOSE. + ** + ** You should have received a copy of the CPL and the LGPL along with this + ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files + ** included with the source distribution for more information. + ** If you did not receive a copy of the licenses, contact the Qxt Foundation. + ** + ** + ** + ****************************************************************************/ +#include "qxtglobalshortcut_p.h" +#include +#include + +static int (*original_x_errhandler)(Display* display, XErrorEvent* event); + +static int qxt_x_errhandler(Display* display, XErrorEvent *event) +{ + Q_UNUSED(display); + switch (event->error_code) + { + case BadAccess: + case BadValue: + case BadWindow: + if (event->request_code == 33 /* X_GrabKey */ || + event->request_code == 34 /* X_UngrabKey */) + { + QxtGlobalShortcutPrivate::error = true; + //TODO: + //char errstr[256]; + //XGetErrorText(dpy, err->error_code, errstr, 256); + } + default: + return 0; + } +} + +bool QxtGlobalShortcutPrivate::eventFilter(void* message) +{ + XEvent* event = static_cast(message); + if (event->type == KeyPress) + { + XKeyEvent* key = (XKeyEvent*) event; + activateShortcut(key->keycode, + // Mod1Mask == Alt, Mod4Mask == Meta + key->state & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask)); + } + return false; +} + +quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) +{ + // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask + quint32 native = 0; + if (modifiers & Qt::ShiftModifier) + native |= ShiftMask; + if (modifiers & Qt::ControlModifier) + native |= ControlMask; + if (modifiers & Qt::AltModifier) + native |= Mod1Mask; + // TODO: resolve these? + //if (modifiers & Qt::MetaModifier) + //if (modifiers & Qt::KeypadModifier) + //if (modifiers & Qt::GroupSwitchModifier) + return native; +} + +quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) +{ + Display* display = QX11Info::display(); + return XKeysymToKeycode(display, XStringToKeysym(QKeySequence(key).toString().toLatin1().data())); +} + +bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) +{ + Display* display = QX11Info::display(); + Window window = QX11Info::appRootWindow(); + Bool owner = True; + int pointer = GrabModeAsync; + int keyboard = GrabModeAsync; + error = false; + original_x_errhandler = XSetErrorHandler(qxt_x_errhandler); + XGrabKey(display, nativeKey, nativeMods, window, owner, pointer, keyboard); + XGrabKey(display, nativeKey, nativeMods | Mod2Mask, window, owner, pointer, keyboard); // allow numlock + XSync(display, False); + XSetErrorHandler(original_x_errhandler); + return !error; +} + +bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) +{ + Display* display = QX11Info::display(); + Window window = QX11Info::appRootWindow(); + error = false; + original_x_errhandler = XSetErrorHandler(qxt_x_errhandler); + XUngrabKey(display, nativeKey, nativeMods, window); + XUngrabKey(display, nativeKey, nativeMods | Mod2Mask, window); // allow numlock + XSync(display, False); + XSetErrorHandler(original_x_errhandler); + return !error; +} diff --git a/src/fqterm/3rdparty/uaocodec.cpp b/src/fqterm/3rdparty/uaocodec.cpp new file mode 100644 index 0000000..2e70b78 --- /dev/null +++ b/src/fqterm/3rdparty/uaocodec.cpp @@ -0,0 +1,15761 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "uaocodec.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_TEXTCODEC + +#define InRange(c, lower, upper) (((c) >= (lower)) && ((c) <= (upper))) +#define IsLatin(c) ((c) < 0x80) +#define IsFirstByte(c) (InRange((c), 0x81, 0xFE)) +#define IsSecondByteRange1(c) (InRange((c), 0x40, 0x7E)) +#define IsSecondByteRange2(c) (InRange((c), 0xA1, 0xFE)) +#define IsSecondByte(c) (IsSecondByteRange1(c) || IsSecondByteRange2(c)) + +#define QValidChar(u) ((u) ? QChar((ushort)(u)) : QChar(QChar::ReplacementCharacter)) + + +int UAOCodec::_mibEnum() +{ + return 0; +} + +QByteArray UAOCodec::_name() +{ + return "UAO"; +} + +/* + * ucs4 to big5hkscs convert routing + */ + +typedef struct { + ushort index; /* index into big table */ + ushort used; /* bitmask of used entries */ +} Summary16; + +static const ushort big5_to_ucs[] = +{ +19991, 20002, 20012, 20053, 20066, 20106, 20144, 20203, 20205, 20220, +20252, 20362, 20479, 20546, 20560, 20600, 20696, 20702, 20724, 20758, +20810, 20817, 20836, 20842, 20869, 20880, 20893, 20902, 20904, 20905, +20935, 20950, 20955, 20972, 20988, 21003, 21012, 21013, 21024, 21035, +21049, 21071, 21105, 21136, 21138, 21140, 21148, 21167, 21173, 21200, +21248, 21255, 21284, 21318, 21343, 21395, 21424, 21469, 21539, 21584, +21585, 21642, 21661, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 21667, 21684, 21712, +21795, 21823, 21836, 21843, 21853, 21868, 21918, 21929, 21996, 22005, +22051, 22096, 22140, 22154, 22164, 22176, 22191, 22232, 22272, 22361, +22373, 22399, 22405, 22409, 22433, 22444, 22452, 22464, 22472, 22483, +22511, 22596, 22636, 22674, 22682, 22706, 22712, 22757, 22779, 22786, +22795, 22800, 22808, 22811, 29836, 29837, 29849, 29851, 29860, 29876, +29881, 29896, 29900, 29904, 29907, 30018, 30037, 30062, 30093, 30110, +30172, 30252, 30287, 30289, 30323, 30324, 30373, 30425, 30478, 30479, +30552, 30578, 30583, 30584, 30586, 30587, 30616, 30639, 30654, 30659, +30661, 30667, 30685, 30694, 30708, 30750, 30781, 30786, 30788, 30795, +30801, 21782, 22775, 38964, 33883, 28948, 33398, 35158, 40236, 40206, +36527, 24674, 26214, 34510, 25785, 37772, 22107, 28485, 35532, 29001, +24012, 34633, 39464, 31658, 36107, 39255, 23597, 32331, 38938, 20518, +25458, 40568, 30783, 40633, 40634, 36046, 35715, 61305, 33931, 37284, +31331, 25776, 24061, 24214, 32865, 26965, 31466, 28710, 26812, 31095, +28060, 36841, 31074, 22178, 34687, 21093, 31108, 28300, 37271, 31622, +38956, 26717, 20397, 34222, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 31725, 34635, +20534, 26893, 27542, 24910, 20855, 30495, 20516, 32622, 30452, 27097, +24803, 25334, 21599, 38788, 22092, 20677, 22040, 34398, 22834, 22875, +22877, 22883, 22892, 22939, 22999, 23019, 23066, 23210, 23248, 23281, +23350, 23497, 23539, 23571, 23580, 23582, 23635, 23705, 23708, 23738, +23739, 23745, 23797, 23802, 23829, 23832, 23870, 23891, 23900, 23917, +23923, 23924, 23948, 23952, 23993, 24016, 24019, 24135, 24164, 24271, +24272, 24298, 24304, 24329, 24332, 24337, 24353, 24372, 24385, 24389, +24401, 24412, 24422, 24451, 24560, 24650, 24672, 24715, 24742, 24798, +24849, 24864, 24865, 24892, 24893, 24984, 25015, 25076, 25107, 25117, +25118, 25143, 24186, 27664, 21454, 20267, 20302, 21556, 22257, 22766, +22841, 22918, 23596, 20915, 20914, 28798, 35265, 35282, 36125, 36710, +20122, 26469, 20177, 20004, 21327, 23626, 20872, 24213, 25269, 19996, +20105, 29366, 31868, 32416, 21351, 36711, 37048, 38271, 38376, 20384, +20387, 20822, 21017, 21170, 21364, 22850, 24069, 26594, 27769, 20026, +32419, 32418, 32426, 32427, 32421, 32422, 32417, 32989, 33486, 35745, +35746, 35747, 36126, 36127, 20891, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 36712, +38377, 38886, 39029, 39118, 39134, 20457, 20204, 20261, 20010, 20262, +20179, 20923, 21018, 21093, 21592, 23089, 23385, 23777, 23707, 23704, +24072, 24211, 24452, 25375, 26102, 26187, 20070, 27902, 27971, 20044, +29421, 29384, 20137, 30757, 31210, 32442, 32433, 32441, 32431, 32445, +32432, 32423, 32429, 32435, 32440, 32439, 32961, 33033, 21005, 35760, +35750, 35752, 35751, 35754, 35759, 35757, 35755, 23682, 36130, 36129, +36713, 36715, 38025, 38024, 38026, 38027, 38378, 38453, 38485, 38473, +39269, 39532, 39592, 20266, 20255, 20390, 20391, 21153, 21160, 21306, +21442, 21713, 38382, 34900, 22269, 22362, 22441, 25191, 22815, 23044, +22919, 19987, 23558, 23625, 23781, 23703, 24102, 24080, 24352, 24378, +20174, 24469, 20932, 24581, 25195, 25346, 25194, 25249, 25379, 36133, +21551, 26011, 26025, 26172, 21206, 24323, 26465, 26541, 26432, 27682, +20937, 27973, 28170, 27882, 27814, 20928, 29301, 29424, 29616, 20135, +27605, 24322, 20247, 32458, 32479, 32461, 32459, 32460, 32454, 32453, +32452, 32456, 32449, 32450, 38069, 20064, 33626, 33550, 33682, 24196, +33483, 22788, 26415, 34926, 35269, 35268, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +35775, 35766, 35776, 35767, 35768, 35774, 35772, 35769, 36137, 36131, +36143, 36135, 36138, 36139, 36717, 36719, 36825, 36830, 36851, 38039, +38035, 38031, 38034, 38381, 38472, 38470, 38452, 39030, 39031, 40060, +40479, 21348, 40614, 22791, 20263, 20254, 20975, 21056, 21019, 21171, +21195, 20007, 21333, 21727, 21796, 20052, 22260, 23591, 22330, 25253, +22490, 22774, 23090, 23547, 23706, 24103, 24079, 21397, 21417, 24694, +38391, 24812, 24699, 24700, 25315, 25381, 25442, 25196, 26531, 26635, +26632, 38054, 27531, 22771, 27695, 27689, 28044, 20945, 28270, 28065, +27748, 27979, 27985, 28067, 26080, 29369, 33487, 30011, 30153, 21457, +30423, 30746, 31174, 31383, 31508, 31499, 32478, 32467, 32466, 32477, +19997, 32476, 32473, 32474, 32470, 32475, 32899, 32958, 32960, 21326, +33713, 33484, 34394, 35270, 35780, 35789, 35777, 35778, 35791, 35781, +35784, 35787, 35785, 35786, 35779, 36142, 36148, 36144, 36155, 36146, +36153, 36154, 36149, 20080, 36140, 36152, 36151, 36722, 36724, 36726, +36827, 37038, 20065, 38046, 38062, 38041, 38048, 38055, 38045, 38052, +38051, 38389, 38384, 24320, 38386, 38388, 38387, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 38431, 38454, 38451, 38887, 39033, 39034, 39035, 39274, 39277, +39272, 39278, 39276, 20911, 39533, 20081, 20538, 20256, 20165, 20542, +20260, 20588, 38130, 21183, 31215, 27719, 21527, 21596, 21595, 22253, +22278, 28034, 22359, 22366, 22488, 33556, 22885, 22920, 29233, 24574, +24582, 24698, 25439, 25250, 25443, 26500, 26198, 26197, 26104, 20250, +19994, 26497, 26472, 26722, 26539, 23681, 27807, 28781, 28287, 28369, +27815, 28902, 28860, 28800, 28949, 29239, 29422, 29502, 29682, 24403, +30415, 30544, 30529, 38606, 30860, 33410, 31509, 31908, 32463, 32482, +32465, 32485, 32486, 20041, 32673, 22307, 32928, 33050, 32959, 33041, +33636, 33479, 21494, 33716, 34398, 34383, 21495, 34568, 34476, 34917, +35013, 35815, 35813, 35814, 35797, 35799, 35800, 35801, 35811, 35802, +35805, 35803, 35809, 35810, 35808, 35807, 36156, 36164, 36158, 36159, +36160, 36161, 36162, 36165, 36739, 36733, 36732, 36734, 20892, 36816, +36798, 36829, 36807, 37049, 38068, 38067, 38073, 38072, 38078, 38080, +38085, 38057, 38082, 38083, 38089, 38091, 38044, 38093, 38079, 38086, +38392, 38504, 38589, 30005, 39044, 39037, 39039, 39036, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 39041, 39042, 39282, 39284, 39281, 39280, 39536, 39534, +39535, 40480, 20389, 20392, 21294, 21388, 23581, 21589, 21497, 21949, +21863, 21716, 22242, 22270, 23576, 22443, 22545, 23551, 26790, 22842, +22849, 22954, 23454, 23517, 23545, 23649, 23853, 23702, 24065, 24124, +24443, 24577, 24815, 24696, 24813, 24808, 25602, 25524, 25530, 30021, +33635, 26538, 28378, 28173, 27721, 28385, 28382, 28176, 28072, 28063, +27818, 28180, 28183, 28068, 33639, 23572, 33638, 29425, 29712, 29595, +30111, 30113, 30127, 30186, 23613, 30417, 30805, 31087, 31096, 31181, +31216, 27964, 31389, 31546, 31581, 32509, 32510, 32508, 32496, 32491, +32511, 32039, 32512, 32434, 32494, 32504, 32501, 32438, 32500, 32490, +32513, 32502, 32602, 38395, 33669, 30422, 33642, 33485, 34432, 35829, +35821, 35820, 35748, 35819, 35823, 35828, 35824, 35826, 35825, 35827, +35822, 23486, 36168, 36170, 36213, 36214, 36741, 36740, 36731, 36828, +36874, 36882, 38128, 38134, 38108, 38125, 38114, 38124, 38120, 38133, +38115, 38402, 38394, 38397, 38401, 38400, 38469, 39047, 39046, 39122, +39290, 39292, 39285, 39287, 39539, 32942, 39600, 40483, 40482, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 20964, 40784, 20159, 20202, 20215, 20396, 20393, +20461, 21095, 21016, 21073, 21053, 21385, 21792, 22068, 21719, 22040, +21943, 21880, 21501, 22687, 22367, 22368, 22549, 23092, 23157, 22953, +23047, 23046, 23485, 23457, 20889, 23618, 23956, 24092, 24223, 21416, +24217, 21422, 24191, 24377, 24198, 34385, 24551, 24578, 24751, 24814, +24868, 24579, 25370, 25169, 25438, 25320, 25376, 25242, 25528, 25599, +25932, 25968, 26242, 26165, 26679, 26729, 26530, 26631, 27004, 26728, +20048, 26526, 27431, 27527, 27572, 27974, 27900, 27905, 27975, 28291, +28070, 28071, 27988, 28909, 22870, 33721, 30126, 30353, 30385, 30424, +30830, 30721, 31377, 31351, 32532, 32451, 32428, 32516, 32517, 32521, +32534, 32536, 32447, 32526, 32531, 32525, 32514, 32520, 32519, 39554, +32610, 33014, 32932, 33714, 33643, 33931, 34430, 34583, 21355, 35850, +35845, 35848, 35846, 35806, 35831, 35832, 35838, 35839, 35844, 35843, +35841, 35770, 35812, 35847, 35837, 35840, 31446, 36180, 36175, 36171, +36145, 36134, 36172, 36132, 21334, 36176, 36136, 36179, 36341, 36745, +36742, 36749, 36744, 36743, 36718, 36750, 36747, 36746, 36866, 36801, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37051, 37073, 37011, 38156, 38161, 38144, +38138, 38096, 38148, 38109, 38160, 38153, 38155, 38049, 38146, 38398, +38405, 24041, 39049, 39052, 20859, 39295, 39297, 39548, 39547, 39543, +39542, 39549, 39550, 39545, 39544, 39607, 38393, 40063, 40065, 40489, +40486, 40632, 40831, 20454, 20647, 20394, 24130, 21058, 21544, 21725, +22003, 22438, 22363, 22859, 34949, 23398, 23548, 23466, 20973, 24811, +25044, 24518, 25112, 25317, 25377, 25374, 25454, 25523, 25321, 25441, +25285, 25373, 21382, 26195, 26196, 26137, 26726, 27178, 26641, 26925, +26725, 26426, 26721, 28096, 27987, 27901, 27978, 27811, 28582, 28177, +28861, 28903, 28783, 28907, 28950, 29420, 29585, 29935, 30232, 21346, +30610, 30742, 30875, 31215, 39062, 31267, 31397, 31491, 31579, 32546, +32547, 33830, 32538, 21439, 32543, 32540, 32537, 32457, 33147, 20852, +33329, 33633, 33831, 33436, 34434, 33828, 35044, 20146, 35278, 35867, +35866, 35855, 35763, 35851, 35853, 35856, 35864, 35834, 35858, 35859, +35773, 35861, 35865, 35852, 35862, 36182, 36752, 36753, 36755, 36751, +21150, 36873, 36831, 36797, 36951, 37050, 38189, 38191, 38192, 38169, +38065, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 38050, 38177, 24405, 38126, 38181, +38182, 38175, 38178, 38193, 38414, 38543, 38505, 38745, 33148, 39050, +39048, 39057, 39060, 22836, 39059, 39056, 39302, 39279, 39300, 39301, +39559, 39560, 39558, 39608, 39612, 40077, 40501, 40490, 40495, 40493, +40499, 40857, 40863, 20248, 20607, 20648, 21169, 21659, 21523, 21387, +22489, 23156, 23252, 23351, 23604, 23654, 23679, 23896, 24110, 24357, +24212, 24691, 25103, 20987, 25380, 25319, 25311, 25601, 25947, 27609, +26279, 26723, 26816, 26727, 26633, 27183, 27539, 27617, 27870, 28392, +27982, 28059, 28389, 28073, 28493, 33829, 28799, 28891, 28905, 22681, +29406, 33719, 29615, 29815, 30184, 30103, 30699, 30970, 30710, 31699, +31914, 38214, 31937, 32553, 32489, 32554, 32533, 32551, 32503, 32541, +24635, 32437, 32555, 32420, 32549, 32358, 32550, 22768, 32874, 32852, +32824, 33043, 32966, 33080, 33037, 20020, 20030, 33392, 34103, 34015, +20111, 34684, 34632, 20149, 35099, 35274, 35868, 35876, 35878, 35762, +35854, 35875, 35874, 35466, 35879, 36186, 36187, 36141, 36185, 36235, +36758, 36759, 27586, 36757, 33286, 36824, 36808, 37213, 38208, 38209, +38170, 38190, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 38194, 38149, 38180, 38202, +38201, 38203, 38206, 38199, 38420, 38421, 38417, 38385, 38544, 38582, +34429, 38889, 39063, 39123, 39563, 39567, 40092, 40091, 40084, 40081, +40511, 40509, 28857, 25995, 19995, 22108, 22329, 22418, 23158, 25041, +25193, 25527, 25200, 25781, 25670, 25822, 25783, 26029, 27103, 26588, +27099, 26592, 27428, 24402, 27553, 27899, 28182, 28388, 28174, 28293, +27983, 28908, 28952, 29367, 29454, 29934, 30112, 30545, 30784, 31036, +31313, 31229, 31388, 31373, 31659, 31783, 31658, 31697, 31616, 31918, +32455, 32558, 32469, 32557, 32483, 32559, 32728, 32844, 32834, 33040, +33169, 26087, 33832, 34013, 33632, 34546, 34633, 35280, 35294, 35871, +35880, 35884, 35882, 36184, 36434, 36857, 36344, 36527, 36716, 36761, +36841, 21307, 37233, 38225, 38145, 38056, 38221, 38215, 38224, 38226, +38217, 38422, 38383, 38423, 38425, 26434, 21452, 38607, 40481, 39069, +39068, 39064, 39066, 39067, 39311, 39306, 39304, 39569, 39617, 40104, +40100, 40107, 40103, 40515, 40517, 40516, 22404, 22364, 23456, 24222, +24208, 24809, 24576, 25042, 25314, 26103, 27249, 26911, 27016, 27257, +28487, 28625, 27813, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 28626, 27896, 28865, +29261, 29322, 20861, 29549, 29626, 29756, 30068, 30250, 30861, 31095, +31283, 31614, 33575, 32462, 32499, 32472, 32599, 32564, 33211, 33402, +34222, 33647, 34433, 34631, 35014, 34948, 35889, 35782, 35885, 35890, +35749, 35887, 36192, 36190, 36343, 36762, 36735, 36766, 36793, 38236, +38237, 38238, 38142, 38231, 38232, 38230, 38233, 38197, 38210, 38143, +37694, 20851, 38471, 38590, 38654, 38892, 38901, 31867, 39072, 39125, +39314, 39313, 39579, 39575, 40120, 40115, 40109, 40119, 40529, 40521, +40522, 40524, 40527, 20029, 40628, 21149, 21657, 22052, 20005, 23453, +24748, 24527, 25318, 25600, 32999, 27015, 28572, 28491, 28809, 29649, +30719, 30778, 30718, 30782, 31398, 31454, 31609, 31726, 36779, 32548, +32487, 32578, 33002, 33328, 34108, 34106, 33446, 33529, 34164, 34461, +35124, 35273, 35302, 35758, 35793, 35893, 36194, 36193, 36280, 37322, +38047, 38105, 38152, 38416, 39128, 39286, 39269, 39582, 33150, 39578, +40131, 40133, 20826, 40835, 40836, 20458, 21995, 21869, 22179, 23646, +24807, 24913, 25668, 25658, 26003, 27185, 26639, 26818, 27516, 28866, +29306, 38262, 29838, 30302, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 32544, 32493, +20848, 34259, 34510, 35272, 35892, 25252, 35465, 36163, 36364, 36291, +36347, 36720, 36777, 38256, 38253, 38081, 38107, 38094, 38255, 38220, +21709, 39038, 39074, 39144, 39537, 39584, 34022, 39585, 39621, 40141, +40143, 33722, 40548, 40542, 40839, 40840, 21870, 20456, 20645, 21587, +23402, 24005, 23782, 24367, 25674, 26435, 27426, 28393, 29473, 21472, +30270, 30307, 31548, 31809, 32843, 33039, 34989, 34924, 35835, 36174, +36189, 36399, 36396, 36756, 37094, 38136, 37492, 38657, 38801, 32366, +39076, 39556, 39553, 40150, 40098, 40148, 40151, 40551, 40485, 40761, +40841, 40842, 40858, 24651, 25371, 25605, 29906, 31363, 32552, 33250, +33821, 34506, 21464, 36902, 36923, 38259, 38084, 38757, 26174, 39181, +24778, 39551, 39564, 39635, 39633, 40157, 40158, 40156, 40502, 22065, +22365, 25597, 30251, 30315, 32641, 34453, 35753, 35863, 35894, 33395, +36195, 37247, 38643, 28789, 38701, 39078, 39588, 39699, 39751, 40078, +40560, 40557, 30839, 30416, 40140, 40844, 40843, 21381, 27012, 28286, +31729, 31657, 34542, 35266, 36433, 34885, 38053, 39045, 39307, 39627, +40649, 28390, 30633, 38218, 38831, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 39540, +39589, 32518, 35872, 36495, 37245, 38075, 37550, 38179, 40132, 40072, +40681, 20991, 40550, 39562, 40563, 40510, 38074, 20162, 34381, 27538, +22439, 22395, 25099, 20451, 21037, 21389, 21593, 21370, 32424, 33543, +38023, 38022, 21591, 24362, 31059, 32446, 37071, 38028, 21072, 21286, +22261, 22445, 23045, 23741, 23811, 28062, 28172, 28867, 30502, 32448, +32464, 33003, 38030, 38032, 38037, 38029, 38379, 22955, 23899, 24701, +26720, 26536, 27817, 27976, 30066, 30743, 32471, 33757, 35271, 35765, +35790, 35794, 36150, 36147, 36730, 36725, 36728, 36911, 37075, 37124, +38059, 38060, 38043, 38063, 38061, 38058, 38390, 38503, 39032, 39275, +40697, 20251, 20603, 20325, 21794, 22450, 24047, 24493, 28828, 33557, +29426, 29614, 32488, 32480, 32481, 32671, 33645, 34545, 35795, 35798, +35817, 35796, 35804, 36241, 36738, 36737, 37036, 38090, 38088, 38064, +38066, 38070, 38157, 38092, 38077, 38076, 39043, 39040, 20971, 40702, +20606, 21787, 23901, 24123, 24747, 24749, 24580, 25132, 25111, 25247, +25248, 25532, 26724, 26473, 33637, 27986, 27812, 28829, 30386, 30720, +32507, 32498, 32495, 32506, 33715, 35275, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +35830, 36167, 38129, 38098, 38097, 38101, 38111, 38123, 38127, 38122, +38135, 38102, 38117, 39121, 21055, 21154, 21715, 21586, 23810, 23780, +24209, 24870, 25378, 26912, 27637, 39053, 28061, 28514, 28064, 28375, +29711, 29825, 30231, 32515, 32535, 32524, 32527, 32529, 33628, 33932, +33553, 33473, 35833, 35836, 35842, 36181, 37112, 38162, 38103, 38141, +38163, 38154, 38116, 38150, 38151, 38164, 38406, 38403, 38739, 39055, +39293, 39541, 39552, 40066, 40488, 21714, 21717, 21721, 23250, 23748, +24639, 27546, 27981, 28904, 29443, 29423, 30876, 31405, 32279, 32539, +33927, 33640, 33929, 33630, 33720, 33431, 34547, 35816, 35857, 35860, +35869, 37072, 38185, 38188, 38166, 38167, 38140, 38171, 38165, 38174, +38036, 38415, 38408, 38409, 38410, 38412, 38413, 40498, 40497, 21724, +24113, 24697, 25672, 58305, 27894, 29461, 29971, 30213, 30187, 30807, +31654, 31578, 31976, 32545, 32807, 33631, 33718, 34544, 35042, 35279, +35873, 35788, 35877, 36292, 38200, 38196, 38113, 38198, 38418, 39271, +40082, 40085, 40504, 40505, 40506, 40832, 24636, 25669, 25784, 27898, +30102, 32523, 32873, 33641, 34789, 34414, 35764, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 35881, 36188, 36157, 36760, 37021, 38227, 38112, 38204, 38223, +34021, 38890, 39273, 39568, 39570, 39571, 38411, 40105, 40096, 40520, +40513, 40518, 21411, 21590, 22406, 27104, 26638, 27655, 27895, 28486, +31074, 32562, 32563, 32628, 33315, 34511, 34431, 35043, 35281, 35311, +35886, 38235, 38239, 38250, 38214, 38121, 38891, 39073, 39312, 39618, +40117, 40118, 40123, 40113, 40526, 40491, 40700, 21950, 25732, 26634, +26533, 26636, 32561, 32845, 33551, 33480, 34162, 34548, 34686, 38132, +38246, 38248, 38241, 38243, 38212, 38251, 38119, 38244, 38137, 38426, +39071, 39316, 39546, 39581, 39583, 39576, 40535, 40538, 40540, 40838, +40837, 20649, 23743, 30152, 25786, 27017, 28384, 30779, 31901, 32425, +32556, 34105, 36166, 38257, 38396, 39129, 39586, 39574, 39580, 40101, +40142, 40144, 40547, 40536, 40574, 20865, 23048, 28757, 25874, 30271, +31656, 31860, 33339, 35276, 36345, 36318, 36729, 38228, 38252, 39587, +39557, 40149, 40099, 40102, 40552, 40503, 40859, 26686, 26916, 34016, +38624, 36723, 40159, 40095, 40553, 40556, 40554, 40555, 40519, 28751, +31766, 35888, 39628, 31550, 31900, 32565, 33044, 36479, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38247, 40090, 36273, 36508, 37246, 35891, 39070, 39079, +39591, 40492, 25094, 38404, 40097, 40514, 31160, 25300, 36299, 29648, +23467, 25296, 27585, 20943, 31108, 21525, 28508, 34972, 37095, 20857, +25144, 25243, 25383, 25531, 25566, 25594, 25745, 25792, 25825, 25846, +25861, 25909, 25934, 25963, 25992, 26073, 26142, 26171, 26175, 26180, +26199, 26217, 26227, 26243, 26300, 26303, 26305, 26357, 26362, 26363, +26382, 26390, 26423, 26468, 26470, 26534, 26535, 26537, 26619, 26621, +26624, 26625, 26629, 26654, 26698, 26706, 26709, 26713, 26765, 26809, +26831, 20616, 38184, 40087, 26914, 26918, 220, 58591, 58592, 252, +58594, 58595, 220, 252, 26934, 26977, 33477, 33482, 33496, 33560, +33562, 33571, 33606, 33627, 33634, 33644, 33646, 33692, 33695, 33717, +33724, 33783, 33834, 33864, 33884, 33890, 33924, 33928, 34012, 34019, +34104, 34138, 34199, 34219, 34241, 34323, 34326, 8715, 34581, 34672, +34685, 34699, 34728, 34759, 34768, 34823, 34830, 34855, 34990, 8712, +34997, 35007, 35045, 35061, 35100, 35101, 35191, 35303, 35383, 35500, +35546, 35675, 35697, 35883, 35898, 35964, 35982, 36014, 36114, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 36169, 36173, 36209, 36360, 36410, 36464, 36505, +36528, 36529, 36549, 36550, 36558, 36579, 36620, 36721, 36727, 36775, +36847, 36878, 36921, 36965, 37001, 37086, 37141, 37334, 37339, 37342, +37345, 37349, 37366, 37372, 37417, 37420, 65287, 37465, 37495, 37613, +37690, 58701, 58702, 29227, 20866, 20886, 20023, 20843, 20799, 58709, +58710, 26409, 27706, 21378, 30098, 32896, 34916, 19974, 58718, 58719, +58720, 11927, 21241, 21269, 8225, 58725, 13316, 58727, 58728, 58729, +58730, 58731, 20981, 58733, 23662, 58735, 22231, 20128, 20907, 11904, +27079, 58741, 9550, 9688, 9689, 9794, 9654, 9668, 8597, 8252, + 182, 8704, 8616, 8596, 8962, 58755, 58756, 20124, 24746, 22311, +22258, 21307, 22769, 36920, 38560, 26628, 21942, 39365, 35585, 20870, +32257, 24540, 27431, 27572, 26716, 22885, 31311, 20206, 20385, 30011, +28784, 20250, 24724, 28023, 32117, 22730, 25040, 25313, 27579, 35226, +23398, 27005, 21917, 28167, 58794, 24059, 38501, 21223, 23515, 28450, +38306, 27475, 35251, 27671, 24112, 25135, 29344, 34384, 26087, 24613, +25312, 25369, 34394, 23777, 25375, 29421, 37111, 38911, 26241, 21220, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 35641, 21306, 39366, 21234, 58824, 24452, +33550, 24693, 25522, 28179, 32076, 34509, 36605, 32153, 40335, 25731, +30476, 20537, 21091, 38522, 22287, 26908, 27177, 38997, 39443, 21427, +21577, 23087, 35492, 24195, 28207, 37489, 21495, 22269, 40658, 31296, +30741, 28168, 25998, 27507, 21092, 38609, 21442, 26719, 24808, 36059, +27531, 27503, 20816, 36766, 28287, 23455, 20889, 33294, 25448, 37320, +23551, 21454, 34886, 24467, 28171, 29539, 32294, 31899, 20966, 23558, +31216, 28169, 28988, 22888, 26465, 29366, 20055, 27972, 21104, 30067, +32260, 22732, 23330, 35698, 37304, 35302, 22065, 23517, 23613, 22259, +31883, 37204, 31298, 38543, 39620, 26530, 25968, 25454, 28716, 22768, +25993, 38745, 31363, 25666, 32118, 23554, 27973, 25126, 36341, 37549, +28508, 36983, 36984, 32330, 31109, 30094, 22766, 20105, 33624, 25436, +25407, 24035, 31379, 35013, 20711, 23652, 32207, 39442, 22679, 24974, +34101, 36104, 33235, 23646, 32154, 22549, 23550, 24111, 28382, 28381, +25246, 27810, 28655, 21336, 22022, 22243, 26029, 24382, 36933, 26172, +37619, 24193, 24500, 32884, 25074, 22618, 36883, 37444, 28857, 36578, +20253, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 38651, 28783, 24403, 20826, 30423, +31282, 38360, 24499, 27602, 29420, 35501, 23626, 38627, 24336, 24745, +33075, 25309, 24259, 22770, 26757, 21338, 34180, 40614, 32283, 30330, +39658, 25244, 27996, 27996, 25935, 25975, 20398, 25173, 20175, 36794, +22793, 27497, 33303, 31807, 21253, 23453, 25265, 27873, 32990, 30770, +35914, 39165, 22696, 27598, 28288, 33032, 40665, 35379, 34220, 36493, +19982, 35465, 25671, 27096, 35617, 26332, 26469, 38972, 20081, 35239, +31452, 38534, 26053, 20001, 29471, 32209, 28057, 22593, 31036, 21169, +25147, 38666, 40802, 26278, 27508, 24651, 32244, 37676, 28809, 21172, +27004, 37682, 28286, 24357, 20096, 26365, 22985, 23437, 23947, 27179, +26907, 21936, 31874, 36796, 27018, 21682, 40235, 38635, 26905, 25539, +39364, 20967, 26626, 36795, 20685, 23776, 26627, 20970, 21250, 30834, +30033, 30048, 22138, 37618, 22592, 26622, 20451, 26466, 31870, 21249, +20452, 20453, 20969, 21498, 21720, 22222, 22310, 22327, 22328, 22408, +22451, 22442, 22448, 22486, 22640, 22713, 22743, 23670, 23740, 23749, +23742, 23926, 24342, 24634, 25525, 26433, 26467, 26529, 26810, 26917, +26920, 27258, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 26915, 26913, 27006, 27009, +27101, 27182, 27250, 27423, 27615, 28181, 29077, 29927, 29938, 29936, +29937, 29944, 29957, 30057, 30314, 30836, 31437, 31439, 31445, 31443, +31457, 31472, 31490, 31763, 31767, 31888, 31917, 31936, 31960, 32155, +32261, 32359, 32387, 32400, 33188, 33373, 33826, 34009, 34352, 34475, +34543, 34992, 35011, 35012, 35076, 59183, 36542, 36552, 36684, 36791, +36826, 36903, 36950, 37685, 37691, 37817, 38282, 38294, 38777, 38790, +38800, 39082, 39830, 39831, 39860, 39887, 39889, 39890, 39922, 39921, +39984, 40007, 40026, 40176, 40262, 40292, 40363, 20036, 21583, 25368, +39857, 40041, 40263, 40293, 39983, 40639, 20916, 21610, 26528, 39822, +37032, 20914, 13869, 25285, 21189, 26545, 21709, 24658, 21441, 28913, +22531, 21855, 37390, 30528, 29756, 29002, 28377, 21472, 29486, 35023, +30861, 32675, 32171, 36394, 37979, 25452, 24487, 23557, 32827, 23791, +14776, 29009, 36045, 38894, 22642, 23139, 32632, 23895, 24943, 27032, +32137, 31918, 32179, 28545, 23290, 22715, 29269, 30286, 36653, 37561, +40286, 40623, 32583, 40388, 36120, 20915, 34412, 21668, 21414, 21030, +26422, 20001, 21364, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 24313, 21177, 21647, +24312, 22956, 24625, 29248, 33047, 30267, 24333, 26187, 26280, 24932, +25423, 28895, 27940, 31911, 31945, 21465, 25933, 22338, 29647, 32966, +13649, 27445, 30849, 21452, 29483, 29482, 29641, 30026, 23033, 29124, +29966, 32220, 39393, 35241, 28662, 14935, 25834, 15341, 27809, 28284, +30055, 22633, 22633, 20996, 59338, 24967, 25658, 33263, 59342, 20917, +20945, 27769, 22815, 36857, 39153, 25911, 33033, 34996, 14890, 36525, +32663, 39440, 32037, 27336, 20876, 21031, 59360, 33050, 21408, 21410, +27738, 27703, 33304, 21894, 24315, 20937, 30897, 37474, 21357, 20931, +59374, 33905, 35207, 38765, 35728, 38563, 24316, 38583, 20814, 39952, +26160, 37461, 30728, 37701, 37491, 37737, 59390, 59391, 59392, 59393, +37343, 37338, 30804, 30822, 30856, 30902, 30919, 30930, 30935, 8491, + 8651, 30948, 30958, 30960, 30961, 30965, 31026, 31027, 31030, 31064, +12307, 31065, 31089, 31102, 31107, 31110, 31111, 31121, 31129, 31135, +31141, 31202, 31217, 31220, 31274, 31290, 31301, 31333, 31420, 31426, +31433, 31451, 31465, 31486, 31500, 31527, 31529, 31554, 31555, 31573, +31599, 31666, 27102, 27129, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 37238, 33114, +33527, 21579, 33074, 32957, 33816, 37214, 37232, 37260, 33096, 59459, +17462, 33113, 32927, 59463, 21833, 21537, 21722, 21554, 21945, 21652, +59470, 30802, 30789, 30796, 59474, 33981, 33820, 33476, 59478, 33915, +35629, 59481, 22347, 59483, 59484, 22341, 34766, 22112, 21994, 22139, +32956, 59491, 30904, 27148, 21708, 31696, 31724, 31738, 31765, 31771, +31797, 31812, 31853, 31886, 31928, 31939, 31974, 31981, 31987, 31989, +31993, 59511, 31996, 32139, 32151, 32164, 32168, 32205, 32208, 32211, +32229, 32253, 27154, 27170, 27184, 27190, 27237, 59527, 59528, 59529, +59530, 59531, 59532, 59533, 59534, 27251, 27256, 59537, 59538, 27260, +27305, 27306, 9450, 9312, 9313, 9314, 9315, 9316, 9317, 9318, + 9319, 9320, 9321, 9322, 9323, 9324, 9325, 9326, 9327, 9328, + 9329, 9330, 9331, 37700, 37805, 37830, 37861, 37914, 37921, 37950, +37953, 37971, 37978, 38042, 38071, 38104, 38110, 38131, 38147, 38158, +38159, 38168, 38173, 38186, 38187, 38207, 38213, 38222, 38242, 38245, +38249, 38258, 38279, 38297, 38304, 38322, 38502, 38557, 38575, 38578, +38707, 38715, 38733, 38735, 38737, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 38741, +38756, 38763, 38769, 38802, 38834, 38898, 38973, 38996, 39077, 39107, +39130, 39150, 39197, 39200, 39267, 39296, 39303, 39309, 39315, 39317, +39356, 39368, 39410, 39606, 39641, 39646, 39695, 39753, 39794, 39811, +39839, 39867, 39907, 39925, 39936, 39940, 39963, 9398, 9399, 9400, + 9401, 9402, 9403, 9404, 9405, 9406, 9407, 9408, 9409, 9410, + 9411, 9412, 9413, 9414, 9415, 9416, 9417, 9418, 9419, 9420, + 9421, 9422, 9423, 9424, 9425, 9426, 9427, 9428, 9429, 9430, + 9431, 9432, 9433, 9434, 9435, 9436, 9437, 9438, 9439, 9440, + 9441, 9442, 9443, 9444, 9445, 9446, 9447, 9448, 9449, 174, + 8482, 59697, 59698, 40054, 10102, 10103, 10104, 10105, 10106, 10107, +10108, 10109, 10110, 10111, 40069, 40070, 40071, 40075, 40080, 40094, +40110, 40112, 40114, 40116, 40122, 40124, 40125, 40134, 40135, 40138, +40139, 40147, 40152, 40153, 40162, 40171, 40172, 40234, 40264, 40272, +40314, 40390, 40523, 40533, 40539, 40561, 40618, 40637, 40644, 40674, +40682, 40712, 40715, 40717, 40737, 40772, 40785, 40861, 64014, 64015, +64017, 64019, 64020, 64024, 64031, 64032, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +64033, 64035, 64036, 64039, 64040, 64041, 19972, 20015, 20097, 20103, +20131, 20151, 20156, 20216, 20264, 20265, 20279, 20290, 20293, 20299, +20338, 20386, 20400, 20413, 20424, 20428, 20464, 20466, 20473, 20483, +20488, 20532, 20539, 20568, 20582, 20609, 20624, 20668, 20688, 20703, +20705, 20732, 20749, 20779, 20832, 20910, 20920, 20946, 20962, 20997, +21044, 21052, 21081, 21096, 21113, 21156, 21196, 21287, 21314, 21341, +21373, 21374, 21445, 21456, 21458, 21502, 21613, 21637, 21651, 21662, +21689, 21731, 21743, 21773, 21784, 21797, 21800, 21803, 21831, 21881, +21904, 21940, 21953, 21975, 21976, 22011, 20404, 22049, 8707, 22098, +59852, 9787, 59854, 59855, 22109, 9332, 9333, 9334, 9335, 9336, + 9337, 9338, 9339, 9340, 9341, 9342, 9343, 9344, 9345, 9346, + 9347, 9348, 9349, 9350, 9351, 22113, 22153, 22155, 22174, 22177, +22193, 22201, 22207, 22230, 22255, 22293, 22301, 22322, 22333, 22335, +22339, 8660, 22398, 22410, 22413, 22416, 22428, 22459, 22462, 22468, +22494, 22526, 22546, 22562, 22599, 22620, 22623, 22643, 22695, 22698, +22704, 22709, 22710, 22731, 22736, 22752, 22789, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 22801, 22921, 22932, 22938, 22943, 22960, 22968, 22980, 23023, +23024, 23032, 23042, 23051, 23053, 23058, 23073, 23076, 23079, 23082, +23083, 23084, 23101, 23109, 23124, 23129, 23137, 23144, 23147, 23150, +23153, 23161, 23166, 23169, 23170, 23174, 23176, 23185, 23193, 23200, +23201, 23211, 23235, 23246, 23247, 23251, 23268, 23280, 23294, 23309, +23313, 23317, 23327, 23339, 23361, 23364, 23366, 23370, 23375, 23400, +23412, 23414, 23420, 23426, 23440, 9372, 9373, 9374, 9375, 9376, + 9377, 9378, 9379, 9380, 9381, 9382, 9383, 9384, 9385, 9386, + 9387, 9388, 9389, 9390, 9391, 9392, 9393, 9394, 9395, 9396, + 9397, 60009, 12850, 12849, 27307, 23446, 9352, 9353, 9354, 9355, + 9356, 9357, 9358, 9359, 9360, 9361, 9362, 9363, 9364, 9365, + 9366, 9367, 9368, 9369, 9370, 9371, 23509, 23511, 23587, 23685, +23710, 23746, 23824, 23852, 23855, 23880, 23894, 23920, 23931, 23941, +23972, 23979, 23990, 24001, 24023, 24073, 24136, 24210, 24253, 24334, +24434, 24497, 24514, 24539, 24543, 24611, 24702, 24791, 24839, 24844, +24857, 24866, 24912, 24928, 24961, 24981, 25017, 25024, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 25039, 25043, 25050, 25232, 25393, 8835, 25399, 25465, +25483, 25537, 25570, 25574, 25595, 25598, 25607, 25650, 25656, 25659, +25690, 25713, 25724, 25741, 25775, 25780, 25782, 25821, 25829, 25866, +25873, 25887, 25951, 25965, 25990, 26037, 26046, 26065, 26068, 26083, +26111, 26136, 26147, 26211, 26219, 26237, 26245, 26258, 26266, 26276, +26285, 26291, 26294, 26317, 26318, 26370, 26380, 26393, 26436, 26475, +26511, 26532, 26559, 26582, 26583, 8834, 26637, 26640, 26651, 26678, +26695, 26710, 26756, 26760, 26813, 26819, 26821, 26882, 26883, 26889, +26904, 26947, 26950, 26980, 26983, 26994, 27013, 27039, 27042, 27089, +27093, 27094, 39457, 39462, 39471, 27329, 22975, 27105, 27139, 27162, +27164, 27180, 27181, 27187, 27203, 27205, 27212, 27219, 27223, 27235, +27252, 27266, 27274, 27279, 27289, 27303, 27313, 27317, 27326, 27337, +27348, 27352, 27382, 27479, 27514, 27612, 27676, 27697, 27736, 27758, +27765, 27775, 27823, 27851, 27871, 27903, 27906, 27909, 27910, 27942, +27991, 27995, 28017, 28033, 28047, 28069, 28081, 28158, 28162, 28164, +28175, 28184, 28202, 28240, 28249, 28314, 28341, 28344, 28379, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 28410, 28420, 28427, 28428, 28438, 28439, 28468, +28477, 28502, 28537, 28554, 28573, 28575, 28603, 28606, 28627, 28633, +28664, 28675, 28747, 28749, 28752, 28756, 28764, 28775, 28791, 28793, +28811, 28815, 28832, 28835, 28837, 28838, 28839, 28868, 28876, 28880, +28886, 618, 603, 230, 652, 593, 596, 650, 605, 601, + 602, 604, 609, 7747, 7753, 330, 7739, 629, 240, 643, + 658, 679, 676, 227, 60294, 60295, 623, 632, 647, 60299, + 199, 339, 594, 65351, 715, 719, 65345, 65346, 65348, 65349, +65350, 65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359, 65360, +65362, 65363, 65364, 65365, 65366, 65367, 65370, 28917, 12832, 12833, +12834, 12835, 12836, 12837, 12838, 12839, 12840, 12841, 28926, 28933, +28957, 28969, 28971, 28972, 28979, 28981, 28987, 28990, 28992, 29007, +29035, 29045, 29047, 29052, 29054, 29068, 29070, 29073, 29078, 29090, +29091, 29101, 29108, 29111, 29114, 29137, 29149, 29163, 29184, 29193, +29198, 29199, 29206, 29207, 29220, 23204, 29230, 8838, 29271, 29276, +29332, 29444, 29456, 29505, 29556, 29580, 29583, 29592, 29596, 29598, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 29607, 29610, 29653, 29665, 29666, 29668, +29670, 29679, 29683, 8839, 29689, 29691, 29698, 29713, 29714, 29716, +29717, 29719, 29721, 29724, 29726, 29727, 29751, 29752, 29753, 29763, +29765, 29767, 29768, 29769, 29779, 29782, 29797, 29803, 29804, 29812, +29818, 29826, 21378, 24191, 20008, 24186, 20886, 23424, 21353, 11911, +60436, 21251, 9746, 33401, 17553, 11916, 11914, 20022, 60444, 21274, +60446, 60447, 11925, 60449, 60450, 9492, 20058, 36790, 24308, 20872, +20101, 60457, 20031, 60459, 60460, 20059, 21430, 36710, 32415, 35744, +36125, 40479, 38376, 38021, 38429, 25164, 27701, 20155, 24516, 28780, +11950, 21475, 27362, 39483, 39484, 39512, 39516, 39523, 9742, 8594, + 8592, 8593, 8595, 8680, 8678, 8679, 8681, 8680, 8678, 8679, + 8681, 9758, 9756, 9755, 9759, 12310, 12311, 9675, 10005, 10003, +22267, 9789, 22813, 26189, 29221, 10025, 10017, 9786, 9785, 60515, +60516, 60517, 60518, 60519, 23672, 9836, 9834, 23249, 23479, 23804, +60526, 9993, 9986, 60529, 60530, 60531, 60532, 23765, 26478, 29793, +29853, 32595, 34195, 10063, 60540, 60541, 23928, 24379, 60544, 9473, + 9475, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 60547, 60548, 60549, 60550, 60551, +60552, 60553, 60554, 60555, 60556, 60557, 60558, 60559, 60560, 60561, +39602, 39648, 39700, 39732, 39737, 39744, 39760, 39807, 9788, 32149, + 9729, 38708, 9730, 60575, 60576, 60577, 9992, 60579, 60580, 60581, +60582, 60583, 60584, 60585, 8507, 8481, 26343, 28247, 60590, 29015, +31178, 8470, 33132, 35577, 38998, 60597, 60598, 9760, 60600, 9828, + 9824, 9831, 9827, 9826, 9830, 9825, 9829, 60609, 60610, 27364, + 8478, 13250, 13272, 13217, 60616, 13221, 60618, 60619, 60620, 60621, +60622, 9745, 39809, 39819, 39821, 39901, 39913, 39917, 39924, 39967, +39968, 39974, 40019, 40029, 40059, 40204, 40214, 8626, 27397, 36073, +36082, 36099, 36113, 36124, 36218, 36265, 36288, 36353, 36366, 36422, +36456, 36465, 36478, 36480, 36534, 36537, 36540, 36547, 36580, 36589, +36594, 36656, 36673, 36682, 36773, 36787, 36792, 36810, 36815, 36872, +36915, 36919, 36964, 36972, 37289, 37302, 37316, 37370, 37384, 37395, +37409, 37416, 37419, 37429, 37436, 37441, 37464, 37469, 37471, 37483, +37486, 37505, 37508, 37513, 37519, 37553, 37562, 37567, 37588, 37595, +37603, 37605, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37611, 37612, 37620, 37622, +37629, 37635, 37639, 37680, 37681, 37696, 37698, 37699, 37727, 37730, +37734, 37736, 37747, 37748, 37752, 37757, 37761, 37764, 37766, 37767, +37776, 37788, 37792, 37816, 37819, 37821, 37823, 37835, 37843, 37851, +37856, 37872, 37873, 37875, 37876, 37889, 37892, 37896, 37911, 37915, +37917, 37924, 37925, 37926, 37933, 37954, 37955, 37965, 37972, 37976, +37989, 37991, 37996, 38009, 38011, 38264, 38277, 38310, 38314, 38486, +38523, 38565, 38644, 38683, 38710, 38720, 38721, 38743, 38791, 38793, +38811, 38833, 38845, 38848, 38850, 38866, 38880, 38932, 38933, 38947, +38963, 39016, 39095, 39097, 39111, 39114, 39136, 39137, 39148, 39157, +40225, 40244, 40249, 40265, 40270, 40301, 8759, 40302, 40316, 40323, +40339, 40357, 8748, 40381, 27521, 27569, 40015, 40592, 40384, 60817, +60818, 9775, 9776, 9783, 9779, 9780, 9781, 9778, 9782, 9777, +40393, 40404, 40444, 40458, 40460, 40462, 40472, 40571, 40581, 40610, +40620, 40625, 40641, 40646, 40647, 40689, 40696, 40743, 39182, 39193, +39196, 39223, 39261, 39266, 39323, 39332, 39338, 39352, 39392, 39398, +39413, 39455, 32254, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 32263, 32347, 32357, +32364, 32567, 32576, 32577, 32585, 32594, 32655, 32659, 32692, 32733, +32743, 32762, 32770, 32776, 32814, 32815, 32828, 32935, 33036, 33066, +33076, 33090, 33110, 33156, 33189, 33252, 33364, 33381, 33403, 33415, +33471, 33506, 33518, 33528, 33532, 33535, 33547, 33565, 33597, 33623, +33681, 33708, 33741, 33773, 33797, 33812, 33814, 33825, 33838, 33854, +33866, 33875, 33877, 33880, 33892, 33906, 33919, 33920, 33938, 33939, +33942, 33955, 33982, 34014, 34017, 34018, 34020, 34040, 34051, 34053, +34064, 34099, 8208, 34114, 34124, 34130, 34143, 34159, 34160, 34163, +34262, 34272, 34286, 34300, 34317, 34319, 34324, 34344, 34370, 34373, +34418, 34972, 23405, 33079, 60958, 39224, 21874, 21867, 60962, 13774, +21873, 21946, 22001, 13778, 22000, 22021, 22050, 22061, 22083, 22046, +22162, 31949, 21530, 21523, 21655, 26353, 30004, 21581, 22180, 22175, +25811, 25390, 25592, 25886, 20088, 27626, 27698, 27709, 27746, 27826, +28152, 28201, 28278, 28290, 28294, 28347, 28383, 28386, 28433, 28452, +28532, 28561, 28597, 28659, 28661, 28859, 28864, 28943, 8706, 29013, +29043, 29050, 61016, 21027, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 61018, 13393, +61020, 36812, 61022, 61023, 192, 200, 204, 210, 217, 193, + 205, 211, 218, 257, 275, 299, 333, 363, 470, 196, + 203, 207, 214, 220, 198, 199, 209, 195, 213, 225, + 233, 237, 243, 250, 472, 228, 235, 239, 246, 252, + 230, 231, 241, 227, 245, 462, 283, 464, 466, 468, + 474, 197, 201, 29064, 216, 208, 7922, 222, 223, 170, + 161, 224, 232, 236, 242, 249, 476, 229, 29080, 29143, + 248, 240, 7923, 254, 255, 186, 191, 226, 234, 238, + 244, 251, 29173, 194, 202, 206, 212, 219, 184, 164, +61110, 402, 12288, 65292, 12289, 12290, 65294, 8231, 65307, 65306, +65311, 65281, 65072, 8230, 8229, 65104, 65105, 65106, 183, 65108, +65109, 65110, 65111, 65372, 8211, 65073, 8212, 65075, 9588, 65076, +65103, 65288, 65289, 65077, 65078, 65371, 65373, 65079, 65080, 12308, +12309, 65081, 65082, 12304, 12305, 65083, 65084, 12298, 12299, 65085, +65086, 12296, 12297, 65087, 65088, 12300, 12301, 65089, 65090, 12302, +12303, 65091, 65092, 65113, 65114, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 65115, +65116, 65117, 65118, 8216, 8217, 8220, 8221, 12317, 12318, 8245, + 8242, 65283, 65286, 65290, 8251, 167, 12291, 9675, 9679, 9651, + 9650, 9678, 9734, 9733, 9671, 9670, 9633, 9632, 9661, 9660, +12963, 8453, 175, 65507, 65343, 717, 65097, 65098, 65101, 65102, +65099, 65100, 65119, 65120, 65121, 65291, 65293, 215, 247, 177, + 8730, 65308, 65310, 65309, 8806, 8807, 8800, 8734, 8786, 8801, +65122, 65123, 65124, 65125, 65126, 65374, 8745, 8746, 8869, 8736, + 8735, 8895, 13266, 13265, 8747, 8750, 8757, 8756, 9792, 9794, + 8853, 8857, 8593, 8595, 8592, 8594, 8598, 8599, 8601, 8600, + 8741, 8739, 65295, 65340, 8725, 65128, 65284, 65509, 12306, 65504, +65505, 65285, 65312, 8451, 8457, 65129, 65130, 65131, 13269, 13212, +13213, 13214, 13262, 13217, 13198, 13199, 13252, 176, 20825, 20827, +20830, 20829, 20833, 20835, 21991, 29929, 31950, 9601, 9602, 9603, + 9604, 9605, 9606, 9607, 9608, 9615, 9614, 9613, 9612, 9611, + 9610, 9609, 9532, 9524, 9516, 9508, 9500, 9620, 9472, 9474, + 9621, 9484, 9488, 9492, 9496, 9581, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9582, 9584, 9583, 9552, 9566, 9578, 9569, 9698, 9699, 9701, + 9700, 9585, 9586, 9587, 65296, 65297, 65298, 65299, 65300, 65301, +65302, 65303, 65304, 65305, 8544, 8545, 8546, 8547, 8548, 8549, + 8550, 8551, 8552, 8553, 12321, 12322, 12323, 12324, 12325, 12326, +12327, 12328, 12329, 21313, 21316, 21317, 65313, 65314, 65315, 65316, +65317, 65318, 65319, 65320, 65321, 65322, 65323, 65324, 65325, 65326, +65327, 65328, 65329, 65330, 65331, 65332, 65333, 65334, 65335, 65336, +65337, 65338, 65345, 65346, 65347, 65348, 65349, 65350, 65351, 65352, +65353, 65354, 65355, 65356, 65357, 65358, 65359, 65360, 65361, 65362, +65363, 65364, 65365, 65366, 65367, 65368, 65369, 65370, 913, 914, + 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, + 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, + 936, 937, 945, 946, 947, 948, 949, 950, 951, 952, + 953, 954, 955, 956, 957, 958, 959, 960, 961, 963, + 964, 965, 966, 967, 968, 969, 12549, 12550, 12551, 12552, +12553, 12554, 12555, 12556, 12557, 12558, 12559, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 12560, 12561, 12562, 12563, 12564, 12565, 12566, 12567, 12568, +12569, 12570, 12571, 12572, 12573, 12574, 12575, 12576, 12577, 12578, +12579, 12580, 12581, 12582, 12583, 12584, 12585, 729, 713, 714, + 711, 715, 9216, 9217, 9218, 9219, 9220, 9221, 9222, 9223, + 9224, 9225, 9226, 9227, 9228, 9229, 9230, 9231, 9232, 9233, + 9234, 9235, 9236, 9237, 9238, 9239, 9240, 9241, 9242, 9243, + 9244, 9245, 9246, 9247, 9249, 8364, 63561, 63562, 63563, 63564, +63565, 63566, 63567, 63568, 63569, 63570, 63571, 63572, 63573, 63574, +63575, 63576, 63577, 63578, 63579, 63580, 63581, 63582, 63583, 63584, +63585, 63586, 63587, 63588, 63589, 19968, 20057, 19969, 19971, 20035, +20061, 20102, 20108, 20154, 20799, 20837, 20843, 20960, 20992, 20993, +21147, 21269, 21313, 21340, 21448, 19977, 19979, 19976, 19978, 20011, +20024, 20961, 20037, 20040, 20063, 20062, 20110, 20129, 20800, 20995, +21242, 21315, 21449, 21475, 22303, 22763, 22805, 22823, 22899, 23376, +23377, 23379, 23544, 23567, 23586, 23608, 23665, 24029, 24037, 24049, +24050, 24051, 24062, 24178, 24318, 24331, 24339, 25165, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 19985, 19984, 19981, 20013, 20016, 20025, 20043, 23609, +20104, 20113, 20117, 20114, 20116, 20130, 20161, 20160, 20163, 20166, +20167, 20173, 20170, 20171, 20164, 20803, 20801, 20839, 20845, 20846, +20844, 20887, 20982, 20998, 20999, 21000, 21243, 21246, 21247, 21270, +21305, 21320, 21319, 21317, 21342, 21380, 21451, 21450, 21453, 22764, +22825, 22827, 22826, 22829, 23380, 23569, 23588, 23610, 23663, 24052, +24187, 24319, 24340, 24341, 24515, 25096, 25142, 25163, 25166, 25903, +25991, 26007, 26020, 26041, 26085, 26352, 26376, 26408, 27424, 27490, +27513, 27595, 27604, 27611, 27663, 27700, 28779, 29226, 29238, 29243, +29255, 29273, 29275, 29356, 29579, 19993, 19990, 19989, 19988, 19992, +20027, 20045, 20047, 20046, 20197, 20184, 20180, 20181, 20182, 20183, +20195, 20196, 20185, 20190, 20805, 20804, 20873, 20874, 20908, 20985, +20986, 20984, 21002, 21152, 21151, 21253, 21254, 21271, 21277, 20191, +21322, 21321, 21345, 21344, 21359, 21358, 21435, 21487, 21476, 21491, +21484, 21486, 21481, 21480, 21500, 21496, 21493, 21483, 21478, 21482, +21490, 21489, 21488, 21477, 21485, 21499, 22235, 22234, 22806, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 22830, 22833, 22900, 22902, 23381, 23427, 23612, +24040, 24039, 24038, 24066, 24067, 24179, 24188, 24321, 24344, 24343, +24517, 25098, 25171, 25172, 25170, 25169, 26021, 26086, 26414, 26412, +26410, 26411, 26413, 27491, 27597, 27665, 27664, 27704, 27713, 27712, +27710, 29359, 29572, 29577, 29916, 29926, 29976, 29983, 29992, 29993, +30000, 30001, 30002, 30003, 30091, 30333, 30382, 30399, 30446, 30683, +30690, 30707, 31034, 31166, 31348, 31435, 19998, 19999, 20050, 20051, +20073, 20121, 20132, 20134, 20133, 20223, 20233, 20249, 20234, 20245, +20237, 20240, 20241, 20239, 20210, 20214, 20219, 20208, 20211, 20221, +20225, 20235, 20809, 20807, 20806, 20808, 20840, 20849, 20877, 20912, +21015, 21009, 21010, 21006, 21014, 21155, 21256, 21281, 21280, 21360, +21361, 21513, 21519, 21516, 21514, 21520, 21505, 21515, 21508, 21521, +21517, 21512, 21507, 21518, 21510, 21522, 22240, 22238, 22237, 22323, +22320, 22312, 22317, 22316, 22319, 22313, 22809, 22810, 22839, 22840, +22916, 22904, 22915, 22909, 22905, 22914, 22913, 23383, 23384, 23431, +23432, 23429, 23433, 23546, 23574, 23673, 24030, 24070, 24182, 24180, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 24335, 24347, 24537, 24534, 25102, 25100, +25101, 25104, 25187, 25179, 25176, 25910, 26089, 26088, 26092, 26093, +26354, 26355, 26377, 26429, 26420, 26417, 26421, 27425, 27492, 27515, +27670, 27741, 27735, 27737, 27743, 27744, 27728, 27733, 27745, 27739, +27725, 27726, 28784, 29279, 29277, 30334, 31481, 31859, 31992, 32566, +32650, 32701, 32769, 32771, 32780, 32786, 32819, 32895, 32905, 32907, +32908, 33251, 33258, 33267, 33276, 33292, 33307, 33311, 33390, 33394, +33406, 34411, 34880, 34892, 34915, 35199, 38433, 20018, 20136, 20301, +20303, 20295, 20311, 20318, 20276, 20315, 20309, 20272, 20304, 20305, +20285, 20282, 20280, 20291, 20308, 20284, 20294, 20323, 20316, 20320, +20271, 20302, 20278, 20313, 20317, 20296, 20314, 20812, 20811, 20813, +20853, 20918, 20919, 21029, 21028, 21033, 21034, 21032, 21163, 21161, +21162, 21164, 21283, 21363, 21365, 21533, 21549, 21534, 21566, 21542, +21582, 21543, 21574, 21571, 21555, 21576, 21570, 21531, 21545, 21578, +21561, 21563, 21560, 21550, 21557, 21558, 21536, 21564, 21568, 21553, +21547, 21535, 21548, 22250, 22256, 22244, 22251, 22346, 22353, 22336, +22349, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 22343, 22350, 22334, 22352, 22351, +22331, 22767, 22846, 22941, 22930, 22952, 22942, 22947, 22937, 22934, +22925, 22948, 22931, 22922, 22949, 23389, 23388, 23386, 23387, 23436, +23435, 23439, 23596, 23616, 23617, 23615, 23614, 23696, 23697, 23700, +23692, 24043, 24076, 24207, 24199, 24202, 24311, 24324, 24351, 24420, +24418, 24439, 24441, 24536, 24524, 24535, 24525, 24561, 24555, 24568, +24554, 25106, 25105, 25220, 25239, 25238, 25216, 25206, 25225, 25197, +25226, 25212, 25214, 25209, 25203, 25234, 25199, 25240, 25198, 25237, +25235, 25233, 25222, 25913, 25915, 25912, 26097, 26356, 26463, 26446, +26447, 26448, 26449, 26460, 26454, 26462, 26441, 26438, 26464, 26451, +26455, 27493, 27599, 27714, 27742, 27801, 27777, 27784, 27785, 27781, +27803, 27754, 27770, 27792, 27760, 27788, 27752, 27798, 27794, 27773, +27779, 27762, 27774, 27764, 27782, 27766, 27789, 27796, 27800, 27778, +28790, 28796, 28797, 28792, 29282, 29281, 29280, 29380, 29378, 29590, +29996, 29995, 30007, 30008, 30338, 30447, 30691, 31169, 31168, 31167, +31350, 31995, 32597, 32918, 32915, 32925, 32920, 32923, 32922, 32946, +33391, 33426, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 33419, 33421, 35211, 35282, +35328, 35895, 35910, 35925, 35997, 36196, 36208, 36275, 36523, 36554, +36763, 36784, 36802, 36806, 36805, 36804, 24033, 37009, 37026, 37034, +37030, 37027, 37193, 37318, 37324, 38450, 38446, 38449, 38442, 38444, +20006, 20054, 20083, 20107, 20123, 20126, 20139, 20140, 20335, 20381, +20365, 20339, 20351, 20332, 20379, 20363, 20358, 20355, 20336, 20341, +20360, 20329, 20347, 20374, 20350, 20367, 20369, 20346, 20820, 20818, +20821, 20841, 20855, 20854, 20856, 20925, 20989, 21051, 21048, 21047, +21050, 21040, 21038, 21046, 21057, 21182, 21179, 21330, 21332, 21331, +21329, 21350, 21367, 21368, 21369, 21462, 21460, 21463, 21619, 21621, +21654, 21624, 21653, 21632, 21627, 21623, 21636, 21650, 21638, 21628, +21648, 21617, 21622, 21644, 21658, 21602, 21608, 21643, 21629, 21646, +22266, 22403, 22391, 22378, 22377, 22369, 22374, 22372, 22396, 22812, +22857, 22855, 22856, 22852, 22868, 22974, 22971, 22996, 22969, 22958, +22993, 22982, 22992, 22989, 22987, 22995, 22986, 22959, 22963, 22994, +22981, 23391, 23396, 23395, 23447, 23450, 23448, 23452, 23449, 23451, +23578, 23624, 23621, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 23622, 23735, 23713, +23736, 23721, 23723, 23729, 23731, 24088, 24090, 24086, 24085, 24091, +24081, 24184, 24218, 24215, 24220, 24213, 24214, 24310, 24358, 24359, +24361, 24448, 24449, 24447, 24444, 24541, 24544, 24573, 24565, 24575, +24591, 24596, 24623, 24629, 24598, 24618, 24597, 24609, 24615, 24617, +24619, 24603, 25110, 25109, 25151, 25150, 25152, 25215, 25289, 25292, +25284, 25279, 25282, 25273, 25298, 25307, 25259, 25299, 25300, 25291, +25288, 25256, 25277, 25276, 25296, 25305, 25287, 25293, 25269, 25306, +25265, 25304, 25302, 25303, 25286, 25260, 25294, 25918, 26023, 26044, +26106, 26132, 26131, 26124, 26118, 26114, 26126, 26112, 26127, 26133, +26122, 26119, 26381, 26379, 26477, 26507, 26517, 26481, 26524, 26483, +26487, 26503, 26525, 26519, 26479, 26480, 26495, 26505, 26494, 26512, +26485, 26522, 26515, 26492, 26474, 26482, 27427, 27494, 27495, 27519, +27667, 27675, 27875, 27880, 27891, 27825, 27852, 27877, 27827, 27837, +27838, 27836, 27874, 27819, 27861, 27859, 27832, 27844, 27833, 27841, +27822, 27863, 27845, 27889, 27839, 27835, 27873, 27867, 27850, 27820, +27887, 27868, 27862, 27872, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 28821, 28814, +28818, 28810, 28825, 29228, 29229, 29240, 29256, 29287, 29289, 29376, +29390, 29401, 29399, 29392, 29609, 29608, 29599, 29611, 29605, 30013, +30109, 30105, 30106, 30340, 30402, 30450, 30452, 30693, 30717, 31038, +31040, 31041, 31177, 31176, 31354, 31353, 31482, 31998, 32596, 32652, +32651, 32773, 32954, 32933, 32930, 32945, 32929, 32939, 32937, 32948, +32938, 32943, 33253, 33278, 33293, 33459, 33437, 33433, 33453, 33469, +33439, 33465, 33457, 33452, 33445, 33455, 33464, 33443, 33456, 33470, +33463, 34382, 34417, 21021, 34920, 36555, 36814, 36820, 36817, 37045, +37048, 37041, 37046, 37319, 37329, 38263, 38272, 38428, 38464, 38463, +38459, 38468, 38466, 38585, 38632, 38738, 38750, 20127, 20141, 20142, +20449, 20405, 20399, 20415, 20448, 20433, 20431, 20445, 20419, 20406, +20440, 20447, 20426, 20439, 20398, 20432, 20420, 20418, 20442, 20430, +20446, 20407, 20823, 20882, 20881, 20896, 21070, 21059, 21066, 21069, +21068, 21067, 21063, 21191, 21193, 21187, 21185, 21261, 21335, 21371, +21402, 21467, 21676, 21696, 21672, 21710, 21705, 21688, 21670, 21683, +21703, 21698, 21693, 21674, 21697, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 21700, +21704, 21679, 21675, 21681, 21691, 21673, 21671, 21695, 22271, 22402, +22411, 22432, 22435, 22434, 22478, 22446, 22419, 22869, 22865, 22863, +22862, 22864, 23004, 23000, 23039, 23011, 23016, 23043, 23013, 23018, +23002, 23014, 23041, 23035, 23401, 23459, 23462, 23460, 23458, 23461, +23553, 23630, 23631, 23629, 23627, 23769, 23762, 24055, 24093, 24101, +24095, 24189, 24224, 24230, 24314, 24328, 24365, 24421, 24456, 24453, +24458, 24459, 24455, 24460, 24457, 24594, 24605, 24608, 24613, 24590, +24616, 24653, 24688, 24680, 24674, 24646, 24643, 24684, 24683, 24682, +24676, 25153, 25308, 25366, 25353, 25340, 25325, 25345, 25326, 25341, +25351, 25329, 25335, 25327, 25324, 25342, 25332, 25361, 25346, 25919, +25925, 26027, 26045, 26082, 26149, 26157, 26144, 26151, 26159, 26143, +26152, 26161, 26148, 26359, 26623, 26579, 26609, 26580, 26576, 26604, +26550, 26543, 26613, 26601, 26607, 26564, 26577, 26548, 26586, 26597, +26552, 26575, 26590, 26611, 26544, 26585, 26594, 26589, 26578, 27498, +27523, 27526, 27573, 27602, 27607, 27679, 27849, 27915, 27954, 27946, +27969, 27941, 27916, 27953, 27934, 27927, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +27963, 27965, 27966, 27958, 27931, 27893, 27961, 27943, 27960, 27945, +27950, 27957, 27918, 27947, 28843, 28858, 28851, 28844, 28847, 28845, +28856, 28846, 28836, 29232, 29298, 29295, 29300, 29417, 29408, 29409, +29623, 29642, 29627, 29618, 29645, 29632, 29619, 29978, 29997, 30031, +30028, 30030, 30027, 30123, 30116, 30117, 30114, 30115, 30328, 30342, +30343, 30344, 30408, 30406, 30403, 30405, 30465, 30457, 30456, 30473, +30475, 30462, 30460, 30471, 30684, 30722, 30740, 30732, 30733, 31046, +31049, 31048, 31047, 31161, 31162, 31185, 31186, 31179, 31359, 31361, +31487, 31485, 31869, 32002, 32005, 32000, 32009, 32007, 32004, 32006, +32568, 32654, 32703, 32772, 32784, 32781, 32785, 32822, 32982, 32997, +32986, 32963, 32964, 32972, 32993, 32987, 32974, 32990, 32996, 32989, +33268, 33314, 33511, 33539, 33541, 33507, 33499, 33510, 33540, 33509, +33538, 33545, 33490, 33495, 33521, 33537, 33500, 33492, 33489, 33502, +33491, 33503, 33519, 33542, 34384, 34425, 34427, 34426, 34893, 34923, +35201, 35284, 35336, 35330, 35331, 35998, 36000, 36212, 36211, 36276, +36557, 36556, 36848, 36838, 36834, 36842, 36837, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 36845, 36843, 36836, 36840, 37066, 37070, 37057, 37059, 37195, +37194, 37325, 38274, 38480, 38475, 38476, 38477, 38754, 38761, 38859, +38893, 38899, 38913, 39080, 39131, 39135, 39318, 39321, 20056, 20147, +20492, 20493, 20515, 20463, 20518, 20517, 20472, 20521, 20502, 20486, +20540, 20511, 20506, 20498, 20497, 20474, 20480, 20500, 20520, 20465, +20513, 20491, 20505, 20504, 20467, 20462, 20525, 20522, 20478, 20523, +20489, 20860, 20900, 20901, 20898, 20941, 20940, 20934, 20939, 21078, +21084, 21076, 21083, 21085, 21290, 21375, 21407, 21405, 21471, 21736, +21776, 21761, 21815, 21756, 21733, 21746, 21766, 21754, 21780, 21737, +21741, 21729, 21769, 21742, 21738, 21734, 21799, 21767, 21757, 21775, +22275, 22276, 22466, 22484, 22475, 22467, 22537, 22799, 22871, 22872, +22874, 23057, 23064, 23068, 23071, 23067, 23059, 23020, 23072, 23075, +23081, 23077, 23052, 23049, 23403, 23640, 23472, 23475, 23478, 23476, +23470, 23477, 23481, 23480, 23556, 23633, 23637, 23632, 23789, 23805, +23803, 23786, 23784, 23792, 23798, 23809, 23796, 24046, 24109, 24107, +24235, 24237, 24231, 24369, 24466, 24465, 24464, 24665, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 24675, 24677, 24656, 24661, 24685, 24681, 24687, 24708, +24735, 24730, 24717, 24724, 24716, 24709, 24726, 25159, 25331, 25352, +25343, 25422, 25406, 25391, 25429, 25410, 25414, 25423, 25417, 25402, +25424, 25405, 25386, 25387, 25384, 25421, 25420, 25928, 25929, 26009, +26049, 26053, 26178, 26185, 26191, 26179, 26194, 26188, 26181, 26177, +26360, 26388, 26389, 26391, 26657, 26680, 26696, 26694, 26707, 26681, +26690, 26708, 26665, 26803, 26647, 26700, 26705, 26685, 26612, 26704, +26688, 26684, 26691, 26666, 26693, 26643, 26648, 26689, 27530, 27529, +27575, 27683, 27687, 27688, 27686, 27684, 27888, 28010, 28053, 28040, +28039, 28006, 28024, 28023, 27993, 28051, 28012, 28041, 28014, 27994, +28020, 28009, 28044, 28042, 28025, 28037, 28005, 28052, 28874, 28888, +28900, 28889, 28872, 28879, 29241, 29305, 29436, 29433, 29437, 29432, +29431, 29574, 29677, 29705, 29678, 29664, 29674, 29662, 30036, 30045, +30044, 30042, 30041, 30142, 30149, 30151, 30130, 30131, 30141, 30140, +30137, 30146, 30136, 30347, 30384, 30410, 30413, 30414, 30505, 30495, +30496, 30504, 30697, 30768, 30759, 30776, 30749, 30772, 30775, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 30757, 30765, 30752, 30751, 30770, 31061, 31056, +31072, 31071, 31062, 31070, 31069, 31063, 31066, 31204, 31203, 31207, +31199, 31206, 31209, 31192, 31364, 31368, 31449, 31494, 31505, 31881, +32033, 32023, 32011, 32010, 32032, 32034, 32020, 32016, 32021, 32026, +32028, 32013, 32025, 32027, 32570, 32607, 32660, 32709, 32705, 32774, +32792, 32789, 32793, 32791, 32829, 32831, 33009, 33026, 33008, 33029, +33005, 33012, 33030, 33016, 33011, 33032, 33021, 33034, 33020, 33007, +33261, 33260, 33280, 33296, 33322, 33323, 33320, 33324, 33467, 33579, +33618, 33620, 33610, 33592, 33616, 33609, 33589, 33588, 33615, 33586, +33593, 33590, 33559, 33600, 33585, 33576, 33603, 34388, 34442, 34474, +34451, 34468, 34473, 34444, 34467, 34460, 34928, 34935, 34945, 34946, +34941, 34937, 35352, 35344, 35342, 35340, 35349, 35338, 35351, 35347, +35350, 35343, 35345, 35912, 35962, 35961, 36001, 36002, 36215, 36524, +36562, 36564, 36559, 36785, 36865, 36870, 36855, 36864, 36858, 36852, +36867, 36861, 36869, 36856, 37013, 37089, 37085, 37090, 37202, 37197, +37196, 37336, 37341, 37335, 37340, 37337, 38275, 38498, 38499, 38497, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 38491, 38493, 38500, 38488, 38494, 38587, +39138, 39340, 39592, 39640, 39717, 39730, 39740, 20094, 20602, 20605, +20572, 20551, 20547, 20556, 20570, 20553, 20581, 20598, 20558, 20565, +20597, 20596, 20599, 20559, 20495, 20591, 20589, 20828, 20885, 20976, +21098, 21103, 21202, 21209, 21208, 21205, 21264, 21263, 21273, 21311, +21312, 21310, 21443, 26364, 21830, 21866, 21862, 21828, 21854, 21857, +21827, 21834, 21809, 21846, 21839, 21845, 21807, 21860, 21816, 21806, +21852, 21804, 21859, 21811, 21825, 21847, 22280, 22283, 22281, 22495, +22533, 22538, 22534, 22496, 22500, 22522, 22530, 22581, 22519, 22521, +22816, 22882, 23094, 23105, 23113, 23142, 23146, 23104, 23100, 23138, +23130, 23110, 23114, 23408, 23495, 23493, 23492, 23490, 23487, 23494, +23561, 23560, 23559, 23648, 23644, 23645, 23815, 23814, 23822, 23835, +23830, 23842, 23825, 23849, 23828, 23833, 23844, 23847, 23831, 24034, +24120, 24118, 24115, 24119, 24247, 24248, 24246, 24245, 24254, 24373, +24375, 24407, 24428, 24425, 24427, 24471, 24473, 24478, 24472, 24481, +24480, 24476, 24703, 24739, 24713, 24736, 24744, 24779, 24756, 24806, +24765, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 24773, 24763, 24757, 24796, 24764, +24792, 24789, 24774, 24799, 24760, 24794, 24775, 25114, 25115, 25160, +25504, 25511, 25458, 25494, 25506, 25509, 25463, 25447, 25496, 25514, +25457, 25513, 25481, 25475, 25499, 25451, 25512, 25476, 25480, 25497, +25505, 25516, 25490, 25487, 25472, 25467, 25449, 25448, 25466, 25949, +25942, 25937, 25945, 25943, 21855, 25935, 25944, 25941, 25940, 26012, +26011, 26028, 26063, 26059, 26060, 26062, 26205, 26202, 26212, 26216, +26214, 26206, 26361, 21207, 26395, 26753, 26799, 26786, 26771, 26805, +26751, 26742, 26801, 26791, 26775, 26800, 26755, 26820, 26797, 26758, +26757, 26772, 26781, 26792, 26783, 26785, 26754, 27442, 27578, 27627, +27628, 27691, 28046, 28092, 28147, 28121, 28082, 28129, 28108, 28132, +28155, 28154, 28165, 28103, 28107, 28079, 28113, 28078, 28126, 28153, +28088, 28151, 28149, 28101, 28114, 28186, 28085, 28122, 28139, 28120, +28138, 28145, 28142, 28136, 28102, 28100, 28074, 28140, 28095, 28134, +28921, 28937, 28938, 28925, 28911, 29245, 29309, 29313, 29468, 29467, +29462, 29459, 29465, 29575, 29701, 29706, 29699, 29702, 29694, 29709, +29920, 29942, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 29943, 29980, 29986, 30053, +30054, 30050, 30064, 30095, 30164, 30165, 30133, 30154, 30157, 30350, +30420, 30418, 30427, 30519, 30526, 30524, 30518, 30520, 30522, 30827, +30787, 30798, 31077, 31080, 31085, 31227, 31378, 31381, 31520, 31528, +31515, 31532, 31526, 31513, 31518, 31534, 31890, 31895, 31893, 32070, +32067, 32113, 32046, 32057, 32060, 32064, 32048, 32051, 32068, 32047, +32066, 32050, 32049, 32573, 32670, 32666, 32716, 32718, 32722, 32796, +32842, 32838, 33071, 33046, 33059, 33067, 33065, 33072, 33060, 33282, +33333, 33335, 33334, 33337, 33678, 33694, 33688, 33656, 33698, 33686, +33725, 33707, 33682, 33674, 33683, 33673, 33696, 33655, 33659, 33660, +33670, 33703, 34389, 24426, 34503, 34496, 34486, 34500, 34485, 34502, +34507, 34481, 34479, 34505, 34899, 34974, 34952, 34987, 34962, 34966, +34957, 34955, 35219, 35215, 35370, 35357, 35363, 35365, 35377, 35373, +35359, 35355, 35362, 35913, 35930, 36009, 36012, 36011, 36008, 36010, +36007, 36199, 36198, 36286, 36282, 36571, 36575, 36889, 36877, 36890, +36887, 36899, 36895, 36893, 36880, 36885, 36894, 36896, 36879, 36898, +36886, 36891, 36884, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 37096, 37101, 37117, +37207, 37326, 37365, 37350, 37347, 37351, 37357, 37353, 38281, 38506, +38517, 38515, 38520, 38512, 38516, 38518, 38519, 38508, 38592, 38634, +38633, 31456, 31455, 38914, 38915, 39770, 40165, 40565, 40575, 40613, +40635, 20642, 20621, 20613, 20633, 20625, 20608, 20630, 20632, 20634, +26368, 20977, 21106, 21108, 21109, 21097, 21214, 21213, 21211, 21338, +21413, 21883, 21888, 21927, 21884, 21898, 21917, 21912, 21890, 21916, +21930, 21908, 21895, 21899, 21891, 21939, 21934, 21919, 21822, 21938, +21914, 21947, 21932, 21937, 21886, 21897, 21931, 21913, 22285, 22575, +22570, 22580, 22564, 22576, 22577, 22561, 22557, 22560, 22777, 22778, +22880, 23159, 23194, 23167, 23186, 23195, 23207, 23411, 23409, 23506, +23500, 23507, 23504, 23562, 23563, 23601, 23884, 23888, 23860, 23879, +24061, 24133, 24125, 24128, 24131, 24190, 24266, 24257, 24258, 24260, +24380, 24429, 24489, 24490, 24488, 24785, 24801, 24754, 24758, 24800, +24860, 24867, 24826, 24853, 24816, 24827, 24820, 24936, 24817, 24846, +24822, 24841, 24832, 24850, 25119, 25161, 25507, 25484, 25551, 25536, +25577, 25545, 25542, 25549, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 25554, 25571, +25552, 25569, 25558, 25581, 25582, 25462, 25588, 25578, 25563, 25682, +25562, 25593, 25950, 25958, 25954, 25955, 26001, 26000, 26031, 26222, +26224, 26228, 26230, 26223, 26257, 26234, 26238, 26231, 26366, 26367, +26399, 26397, 26874, 26837, 26848, 26840, 26839, 26885, 26847, 26869, +26862, 26855, 26873, 26834, 26866, 26851, 26827, 26829, 26893, 26898, +26894, 26825, 26842, 26990, 26875, 27454, 27450, 27453, 27544, 27542, +27580, 27631, 27694, 27695, 27692, 28207, 28216, 28244, 28193, 28210, +28263, 28234, 28192, 28197, 28195, 28187, 28251, 28248, 28196, 28246, +28270, 28205, 28198, 28271, 28212, 28237, 28218, 28204, 28227, 28189, +28222, 28363, 28297, 28185, 28238, 28259, 28228, 28274, 28265, 28255, +28953, 28954, 28966, 28976, 28961, 28982, 29038, 28956, 29260, 29316, +29312, 29494, 29477, 29492, 29481, 29754, 29738, 29747, 29730, 29733, +29749, 29750, 29748, 29743, 29723, 29734, 29736, 29989, 29990, 30059, +30058, 30178, 30171, 30179, 30169, 30168, 30174, 30176, 30331, 30332, +30358, 30355, 30388, 30428, 30543, 30701, 30813, 30828, 30831, 31245, +31240, 31243, 31237, 31232, 31384, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 31383, +31382, 31461, 31459, 31561, 31574, 31558, 31568, 31570, 31572, 31565, +31563, 31567, 31569, 31903, 31909, 32094, 32080, 32104, 32085, 32043, +32110, 32114, 32097, 32102, 32098, 32112, 32115, 21892, 32724, 32725, +32779, 32850, 32901, 33109, 33108, 33099, 33105, 33102, 33081, 33094, +33086, 33100, 33107, 33140, 33298, 33308, 33769, 33795, 33784, 33805, +33760, 33733, 33803, 33729, 33775, 33777, 33780, 33879, 33802, 33776, +33804, 33740, 33789, 33778, 33738, 33848, 33806, 33796, 33756, 33799, +33748, 33759, 34395, 34527, 34521, 34541, 34516, 34523, 34532, 34512, +34526, 34903, 35009, 35010, 34993, 35203, 35222, 35387, 35424, 35413, +35422, 35388, 35393, 35412, 35419, 35408, 35398, 35380, 35386, 35382, +35414, 35937, 35970, 36015, 36028, 36019, 36029, 36033, 36027, 36032, +36020, 36023, 36022, 36031, 36024, 36234, 36229, 36225, 36302, 36317, +36299, 36314, 36305, 36300, 36315, 36294, 36603, 36600, 36604, 36764, +36910, 36917, 36913, 36920, 36914, 36918, 37122, 37109, 37129, 37118, +37219, 37221, 37327, 37396, 37397, 37411, 37385, 37406, 37389, 37392, +37383, 37393, 38292, 38287, 38283, 38289, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +38291, 38290, 38286, 38538, 38542, 38539, 38525, 38533, 38534, 38541, +38514, 38532, 38593, 38597, 38596, 38598, 38599, 38639, 38642, 38860, +38917, 38918, 38920, 39143, 39146, 39151, 39145, 39154, 39149, 39342, +39341, 40643, 40653, 40657, 20098, 20653, 20661, 20658, 20659, 20677, +20670, 20652, 20663, 20667, 20655, 20679, 21119, 21111, 21117, 21215, +21222, 21220, 21218, 21219, 21295, 21983, 21992, 21971, 21990, 21966, +21980, 21959, 21969, 21987, 21988, 21999, 21978, 21985, 21957, 21958, +21989, 21961, 22290, 22291, 22622, 22609, 22616, 22615, 22618, 22612, +22635, 22604, 22637, 22602, 22626, 22610, 22603, 22887, 23233, 23241, +23244, 23230, 23229, 23228, 23219, 23234, 23218, 23913, 23919, 24140, +24185, 24265, 24264, 24338, 24409, 24492, 24494, 24858, 24847, 24904, +24863, 24819, 24859, 24825, 24833, 24840, 24910, 24908, 24900, 24909, +24894, 24884, 24871, 24845, 24838, 24887, 25121, 25122, 25619, 25662, +25630, 25642, 25645, 25661, 25644, 25615, 25628, 25620, 25613, 25654, +25622, 25623, 25606, 25964, 26015, 26032, 26263, 26249, 26247, 26248, +26262, 26244, 26264, 26253, 26371, 27028, 26989, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26970, 26999, 26976, 26964, 26997, 26928, 27010, 26954, 26984, +26987, 26974, 26963, 27001, 27014, 26973, 26979, 26971, 27463, 27506, +27584, 27583, 27603, 27645, 28322, 28335, 28371, 28342, 28354, 28304, +28317, 28359, 28357, 28325, 28312, 28348, 28346, 28331, 28369, 28310, +28316, 28356, 28372, 28330, 28327, 28340, 29006, 29017, 29033, 29028, +29001, 29031, 29020, 29036, 29030, 29004, 29029, 29022, 28998, 29032, +29014, 29242, 29266, 29495, 29509, 29503, 29502, 29807, 29786, 29781, +29791, 29790, 29761, 29759, 29785, 29787, 29788, 30070, 30072, 30208, +30192, 30209, 30194, 30193, 30202, 30207, 30196, 30195, 30430, 30431, +30555, 30571, 30566, 30558, 30563, 30585, 30570, 30572, 30556, 30565, +30568, 30562, 30702, 30862, 30896, 30871, 30872, 30860, 30857, 30844, +30865, 30867, 30847, 31098, 31103, 31105, 33836, 31165, 31260, 31258, +31264, 31252, 31263, 31262, 31391, 31392, 31607, 31680, 31584, 31598, +31591, 31921, 31923, 31925, 32147, 32121, 32145, 32129, 32143, 32091, +32622, 32617, 32618, 32626, 32681, 32680, 32676, 32854, 32856, 32902, +32900, 33137, 33136, 33144, 33125, 33134, 33139, 33131, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 33145, 33146, 33126, 33285, 33351, 33922, 33911, 33853, +33841, 33909, 33894, 33899, 33865, 33900, 33883, 33852, 33845, 33889, +33891, 33897, 33901, 33862, 34398, 34396, 34399, 34553, 34579, 34568, +34567, 34560, 34558, 34555, 34562, 34563, 34566, 34570, 34905, 35039, +35028, 35033, 35036, 35032, 35037, 35041, 35018, 35029, 35026, 35228, +35299, 35435, 35442, 35443, 35430, 35433, 35440, 35463, 35452, 35427, +35488, 35441, 35461, 35437, 35426, 35438, 35436, 35449, 35451, 35390, +35432, 35938, 35978, 35977, 36042, 36039, 36040, 36036, 36018, 36035, +36034, 36037, 36321, 36319, 36328, 36335, 36339, 36346, 36330, 36324, +36326, 36530, 36611, 36617, 36606, 36618, 36767, 36786, 36939, 36938, +36947, 36930, 36948, 36924, 36949, 36944, 36935, 36943, 36942, 36941, +36945, 36926, 36929, 37138, 37143, 37228, 37226, 37225, 37321, 37431, +37463, 37432, 37437, 37440, 37438, 37467, 37451, 37476, 37457, 37428, +37449, 37453, 37445, 37433, 37439, 37466, 38296, 38552, 38548, 38549, +38605, 38603, 38601, 38602, 38647, 38651, 38649, 38646, 38742, 38772, +38774, 38928, 38929, 38931, 38922, 38930, 38924, 39164, 39156, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 39165, 39166, 39347, 39345, 39348, 39649, 40169, +40578, 40718, 40723, 40736, 20711, 20718, 20709, 20694, 20717, 20698, +20693, 20687, 20689, 20721, 20686, 20713, 20834, 20979, 21123, 21122, +21297, 21421, 22014, 22016, 22043, 22039, 22013, 22036, 22022, 22025, +22029, 22030, 22007, 22038, 22047, 22024, 22032, 22006, 22296, 22294, +22645, 22654, 22659, 22675, 22666, 22649, 22661, 22653, 22781, 22821, +22818, 22820, 22890, 22889, 23265, 23270, 23273, 23255, 23254, 23256, +23267, 23413, 23518, 23527, 23521, 23525, 23526, 23528, 23522, 23524, +23519, 23565, 23650, 23940, 23943, 24155, 24163, 24149, 24151, 24148, +24275, 24278, 24330, 24390, 24432, 24505, 24903, 24895, 24907, 24951, +24930, 24931, 24927, 24922, 24920, 24949, 25130, 25735, 25688, 25684, +25764, 25720, 25695, 25722, 25681, 25703, 25652, 25709, 25723, 25970, +26017, 26071, 26070, 26274, 26280, 26269, 27036, 27048, 27029, 27073, +27054, 27091, 27083, 27035, 27063, 27067, 27051, 27060, 27088, 27085, +27053, 27084, 27046, 27075, 27043, 27465, 27468, 27699, 28467, 28436, +28414, 28435, 28404, 28457, 28478, 28448, 28460, 28431, 28418, 28450, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 28415, 28399, 28422, 28465, 28472, 28466, +28451, 28437, 28459, 28463, 28552, 28458, 28396, 28417, 28402, 28364, +28407, 29076, 29081, 29053, 29066, 29060, 29074, 29246, 29330, 29334, +29508, 29520, 29796, 29795, 29802, 29808, 29805, 29956, 30097, 30247, +30221, 30219, 30217, 30227, 30433, 30435, 30596, 30589, 30591, 30561, +30913, 30879, 30887, 30899, 30889, 30883, 31118, 31119, 31117, 31278, +31281, 31402, 31401, 31469, 31471, 31649, 31637, 31627, 31605, 31639, +31645, 31636, 31631, 31672, 31623, 31620, 31929, 31933, 31934, 32187, +32176, 32156, 32189, 32190, 32160, 32202, 32180, 32178, 32177, 32186, +32162, 32191, 32181, 32184, 32173, 32210, 32199, 32172, 32624, 32736, +32737, 32735, 32862, 32858, 32903, 33104, 33152, 33167, 33160, 33162, +33151, 33154, 33255, 33274, 33287, 33300, 33310, 33355, 33993, 33983, +33990, 33988, 33945, 33950, 33970, 33948, 33995, 33976, 33984, 34003, +33936, 33980, 34001, 33994, 34623, 34588, 34619, 34594, 34597, 34612, +34584, 34645, 34615, 34601, 35059, 35074, 35060, 35065, 35064, 35069, +35048, 35098, 35055, 35494, 35468, 35486, 35491, 35469, 35489, 35475, +35492, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 35498, 35493, 35496, 35480, 35473, +35482, 35495, 35946, 35981, 35980, 36051, 36049, 36050, 36203, 36249, +36245, 36348, 36628, 36626, 36629, 36627, 36771, 36960, 36952, 36956, +36963, 36953, 36958, 36962, 36957, 36955, 37145, 37144, 37150, 37237, +37240, 37239, 37236, 37496, 37504, 37509, 37528, 37526, 37499, 37523, +37532, 37544, 37500, 37521, 38305, 38312, 38313, 38307, 38309, 38308, +38553, 38556, 38555, 38604, 38610, 38656, 38780, 38789, 38902, 38935, +38936, 39087, 39089, 39171, 39173, 39180, 39177, 39361, 39599, 39600, +39654, 39745, 39746, 40180, 40182, 40179, 40636, 40763, 40778, 20740, +20736, 20731, 20725, 20729, 20738, 20744, 20745, 20741, 20956, 21127, +21128, 21129, 21133, 21130, 21232, 21426, 22062, 22075, 22073, 22066, +22079, 22068, 22057, 22099, 22094, 22103, 22132, 22070, 22063, 22064, +22656, 22687, 22686, 22707, 22684, 22702, 22697, 22694, 22893, 23305, +23291, 23307, 23285, 23308, 23304, 23534, 23532, 23529, 23531, 23652, +23653, 23965, 23956, 24162, 24159, 24161, 24290, 24282, 24287, 24285, +24291, 24288, 24392, 24433, 24503, 24501, 24950, 24935, 24942, 24925, +24917, 24962, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 24956, 24944, 24939, 24958, +24999, 24976, 25003, 24974, 25004, 24986, 24996, 24980, 25006, 25134, +25705, 25711, 25721, 25758, 25778, 25736, 25744, 25776, 25765, 25747, +25749, 25769, 25746, 25774, 25773, 25771, 25754, 25772, 25753, 25762, +25779, 25973, 25975, 25976, 26286, 26283, 26292, 26289, 27171, 27167, +27112, 27137, 27166, 27161, 27133, 27169, 27155, 27146, 27123, 27138, +27141, 27117, 27153, 27472, 27470, 27556, 27589, 27590, 28479, 28540, +28548, 28497, 28518, 28500, 28550, 28525, 28507, 28536, 28526, 28558, +28538, 28528, 28516, 28567, 28504, 28373, 28527, 28512, 28511, 29087, +29100, 29105, 29096, 29270, 29339, 29518, 29527, 29801, 29835, 29827, +29822, 29824, 30079, 30240, 30249, 30239, 30244, 30246, 30241, 30242, +30362, 30394, 30436, 30606, 30599, 30604, 30609, 30603, 30923, 30917, +30906, 30922, 30910, 30933, 30908, 30928, 31295, 31292, 31296, 31293, +31287, 31291, 31407, 31406, 31661, 31665, 31684, 31668, 31686, 31687, +31681, 31648, 31692, 31946, 32224, 32244, 32239, 32251, 32216, 32236, +32221, 32232, 32227, 32218, 32222, 32233, 32158, 32217, 32242, 32249, +32629, 32631, 32687, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 32745, 32806, 33179, +33180, 33181, 33184, 33178, 33176, 34071, 34109, 34074, 34030, 34092, +34093, 34067, 34065, 34083, 34081, 34068, 34028, 34085, 34047, 34054, +34690, 34676, 34678, 34656, 34662, 34680, 34664, 34649, 34647, 34636, +34643, 34907, 34909, 35088, 35079, 35090, 35091, 35093, 35082, 35516, +35538, 35527, 35524, 35477, 35531, 35576, 35506, 35529, 35522, 35519, +35504, 35542, 35533, 35510, 35513, 35547, 35916, 35918, 35948, 36064, +36062, 36070, 36068, 36076, 36077, 36066, 36067, 36060, 36074, 36065, +36205, 36255, 36259, 36395, 36368, 36381, 36386, 36367, 36393, 36383, +36385, 36382, 36538, 36637, 36635, 36639, 36649, 36646, 36650, 36636, +36638, 36645, 36969, 36974, 36968, 36973, 36983, 37168, 37165, 37159, +37169, 37255, 37257, 37259, 37251, 37573, 37563, 37559, 37610, 37548, +37604, 37569, 37555, 37564, 37586, 37575, 37616, 37554, 38317, 38321, +38660, 38662, 38663, 38665, 38752, 38797, 38795, 38799, 38945, 38955, +38940, 39091, 39178, 39187, 39186, 39192, 39389, 39376, 39391, 39387, +39377, 39381, 39378, 39385, 39607, 39662, 39663, 39719, 39749, 39748, +39799, 39791, 40198, 40201, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 40195, 40617, +40638, 40654, 22696, 40786, 20754, 20760, 20756, 20752, 20757, 20864, +20906, 20957, 21137, 21139, 21235, 22105, 22123, 22137, 22121, 22116, +22136, 22122, 22120, 22117, 22129, 22127, 22124, 22114, 22134, 22721, +22718, 22727, 22725, 22894, 23325, 23348, 23416, 23536, 23566, 24394, +25010, 24977, 25001, 24970, 25037, 25014, 25022, 25034, 25032, 25136, +25797, 25793, 25803, 25787, 25788, 25818, 25796, 25799, 25794, 25805, +25791, 25810, 25812, 25790, 25972, 26310, 26313, 26297, 26308, 26311, +26296, 27197, 27192, 27194, 27225, 27243, 27224, 27193, 27204, 27234, +27233, 27211, 27207, 27189, 27231, 27208, 27481, 27511, 27653, 28610, +28593, 28577, 28611, 28580, 28609, 28583, 28595, 28608, 28601, 28598, +28582, 28576, 28596, 29118, 29129, 29136, 29138, 29128, 29141, 29113, +29134, 29145, 29148, 29123, 29124, 29544, 29852, 29859, 29848, 29855, +29854, 29922, 29964, 29965, 30260, 30264, 30266, 30439, 30437, 30624, +30622, 30623, 30629, 30952, 30938, 30956, 30951, 31142, 31309, 31310, +31302, 31308, 31307, 31418, 31705, 31761, 31689, 31716, 31707, 31713, +31721, 31718, 31957, 31958, 32266, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 32273, +32264, 32283, 32291, 32286, 32285, 32265, 32272, 32633, 32690, 32752, +32753, 32750, 32808, 33203, 33193, 33192, 33275, 33288, 33368, 33369, +34122, 34137, 34120, 34152, 34153, 34115, 34121, 34157, 34154, 34142, +34691, 34719, 34718, 34722, 34701, 34913, 35114, 35122, 35109, 35115, +35105, 35242, 35238, 35558, 35578, 35563, 35569, 35584, 35548, 35559, +35566, 35582, 35585, 35586, 35575, 35565, 35571, 35574, 35580, 35947, +35949, 35987, 36084, 36420, 36401, 36404, 36418, 36409, 36405, 36667, +36655, 36664, 36659, 36776, 36774, 36981, 36980, 36984, 36978, 36988, +36986, 37172, 37266, 37664, 37686, 37624, 37683, 37679, 37666, 37628, +37675, 37636, 37658, 37648, 37670, 37665, 37653, 37678, 37657, 38331, +38567, 38568, 38570, 38613, 38670, 38673, 38678, 38669, 38675, 38671, +38747, 38748, 38758, 38808, 38960, 38968, 38971, 38967, 38957, 38969, +38948, 39184, 39208, 39198, 39195, 39201, 39194, 39405, 39394, 39409, +39608, 39612, 39675, 39661, 39720, 39825, 40213, 40227, 40230, 40232, +40210, 40219, 40664, 40660, 40845, 40860, 20778, 20767, 20769, 20786, +21237, 22158, 22144, 22160, 22149, 22151, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +22159, 22741, 22739, 22737, 22734, 23344, 23338, 23332, 23418, 23607, +23656, 23996, 23994, 23997, 23992, 24171, 24396, 24509, 25033, 25026, +25031, 25062, 25035, 25138, 25140, 25806, 25802, 25816, 25824, 25840, +25830, 25836, 25841, 25826, 25837, 25986, 25987, 26329, 26326, 27264, +27284, 27268, 27298, 27292, 27355, 27299, 27262, 27287, 27280, 27296, +27484, 27566, 27610, 27656, 28632, 28657, 28639, 28640, 28635, 28644, +28651, 28655, 28544, 28652, 28641, 28649, 28629, 28654, 28656, 29159, +29151, 29166, 29158, 29157, 29165, 29164, 29172, 29152, 29237, 29254, +29552, 29554, 29865, 29872, 29862, 29864, 30278, 30274, 30284, 30442, +30643, 30634, 30640, 30636, 30631, 30637, 30703, 30967, 30970, 30964, +30959, 30977, 31143, 31146, 31319, 31423, 31751, 31757, 31742, 31735, +31756, 31712, 31968, 31964, 31966, 31970, 31967, 31961, 31965, 32302, +32318, 32326, 32311, 32306, 32323, 32299, 32317, 32305, 32325, 32321, +32308, 32313, 32328, 32309, 32319, 32303, 32580, 32755, 32764, 32881, +32882, 32880, 32879, 32883, 33222, 33219, 33210, 33218, 33216, 33215, +33213, 33225, 33214, 33256, 33289, 33393, 34218, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 34180, 34174, 34204, 34193, 34196, 34223, 34203, 34183, 34216, +34186, 34407, 34752, 34769, 34739, 34770, 34758, 34731, 34747, 34746, +34760, 34763, 35131, 35126, 35140, 35128, 35133, 35244, 35598, 35607, +35609, 35611, 35594, 35616, 35613, 35588, 35600, 35905, 35903, 35955, +36090, 36093, 36092, 36088, 36091, 36264, 36425, 36427, 36424, 36426, +36676, 36670, 36674, 36677, 36671, 36991, 36989, 36996, 36993, 36994, +36992, 37177, 37283, 37278, 37276, 37709, 37762, 37672, 37749, 37706, +37733, 37707, 37656, 37758, 37740, 37723, 37744, 37722, 37716, 38346, +38347, 38348, 38344, 38342, 38577, 38584, 38614, 38684, 38686, 38816, +38867, 38982, 39094, 39221, 39425, 39423, 39854, 39851, 39850, 39853, +40251, 40255, 40587, 40655, 40670, 40668, 40669, 40667, 40766, 40779, +21474, 22165, 22190, 22745, 22744, 23352, 24413, 25059, 25139, 25844, +25842, 25854, 25862, 25850, 25851, 25847, 26039, 26332, 26406, 27315, +27308, 27331, 27323, 27320, 27330, 27310, 27311, 27487, 27512, 27567, +28681, 28683, 28670, 28678, 28666, 28689, 28687, 29179, 29180, 29182, +29176, 29559, 29557, 29863, 29887, 29973, 30294, 30296, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 30290, 30653, 30655, 30651, 30652, 30990, 31150, 31329, +31330, 31328, 31428, 31429, 31787, 31783, 31786, 31774, 31779, 31777, +31975, 32340, 32341, 32350, 32346, 32353, 32338, 32345, 32584, 32761, +32763, 32887, 32886, 33229, 33231, 33290, 34255, 34217, 34253, 34256, +34249, 34224, 34234, 34233, 34214, 34799, 34796, 34802, 34784, 35206, +35250, 35316, 35624, 35641, 35628, 35627, 35920, 36101, 36441, 36451, +36454, 36452, 36447, 36437, 36544, 36681, 36685, 36999, 36995, 37000, +37291, 37292, 37328, 37780, 37770, 37782, 37794, 37811, 37806, 37804, +37808, 37784, 37786, 37783, 38356, 38358, 38352, 38357, 38626, 38620, +38617, 38619, 38622, 38692, 38819, 38822, 38829, 38905, 38989, 38991, +38988, 38990, 38995, 39098, 39230, 39231, 39229, 39214, 39333, 39438, +39617, 39683, 39686, 39759, 39758, 39757, 39882, 39881, 39933, 39880, +39872, 40273, 40285, 40288, 40672, 40725, 40748, 20787, 22181, 22750, +22751, 22754, 23541, 40848, 24300, 25074, 25079, 25078, 25077, 25856, +25871, 26336, 26333, 27365, 27357, 27354, 27347, 28699, 28703, 28712, +28698, 28701, 28693, 28696, 29190, 29197, 29272, 29346, 29560, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 29562, 29885, 29898, 29923, 30087, 30086, 30303, +30305, 30663, 31001, 31153, 31339, 31337, 31806, 31807, 31800, 31805, +31799, 31808, 32363, 32365, 32377, 32361, 32362, 32645, 32371, 32694, +32697, 32696, 33240, 34281, 34269, 34282, 34261, 34276, 34277, 34295, +34811, 34821, 34829, 34809, 34814, 35168, 35167, 35158, 35166, 35649, +35676, 35672, 35657, 35674, 35662, 35663, 35654, 35673, 36104, 36106, +36476, 36466, 36487, 36470, 36460, 36474, 36468, 36692, 36686, 36781, +37002, 37003, 37297, 37294, 37857, 37841, 37855, 37827, 37832, 37852, +37853, 37846, 37858, 37837, 37848, 37860, 37847, 37864, 38364, 38580, +38627, 38698, 38695, 38753, 38876, 38907, 39006, 39000, 39003, 39100, +39237, 39241, 39446, 39449, 39693, 39912, 39911, 39894, 39899, 40329, +40289, 40306, 40298, 40300, 40594, 40599, 40595, 40628, 21240, 22184, +22199, 22198, 22196, 22204, 22756, 23360, 23363, 23421, 23542, 24009, +25080, 25082, 25880, 25876, 25881, 26342, 26407, 27372, 28734, 28720, +28722, 29200, 29563, 29903, 30306, 30309, 31014, 31018, 31020, 31019, +31431, 31478, 31820, 31811, 31821, 31983, 31984, 36782, 32381, 32380, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32386, 32588, 32768, 33242, 33382, 34299, +34297, 34321, 34298, 34310, 34315, 34311, 34314, 34836, 34837, 35172, +35258, 35320, 35696, 35692, 35686, 35695, 35679, 35691, 36111, 36109, +36489, 36481, 36485, 36482, 37300, 37323, 37912, 37891, 37885, 38369, +38704, 39108, 39250, 39249, 39336, 39467, 39472, 39479, 39477, 39955, +39949, 40569, 40629, 40680, 40751, 40799, 40803, 40801, 20791, 20792, +22209, 22208, 22210, 22804, 23660, 24013, 25084, 25086, 25885, 25884, +26005, 26345, 27387, 27396, 27386, 27570, 28748, 29211, 29351, 29910, +29908, 30313, 30675, 31824, 32399, 32396, 32700, 34327, 34349, 34330, +34851, 34850, 34849, 34847, 35178, 35180, 35261, 35700, 35703, 35709, +36115, 36490, 36493, 36491, 36703, 36783, 37306, 37934, 37939, 37941, +37946, 37944, 37938, 37931, 38370, 38712, 38713, 38706, 38911, 39015, +39013, 39255, 39493, 39491, 39488, 39486, 39631, 39764, 39761, 39981, +39973, 40367, 40372, 40386, 40376, 40605, 40687, 40729, 40796, 40806, +40807, 20796, 20795, 22216, 22218, 22217, 23423, 24020, 24018, 24398, +25087, 25892, 27402, 27489, 28753, 28760, 29568, 29924, 30090, 30318, +30316, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 31155, 31840, 31839, 32894, 32893, +33247, 35186, 35183, 35324, 35712, 36118, 36119, 36497, 36499, 36705, +37192, 37956, 37969, 37970, 38717, 38718, 38851, 38849, 39019, 39253, +39509, 39501, 39634, 39706, 40009, 39985, 39998, 39995, 40403, 40407, +40756, 40812, 40810, 40852, 22220, 24022, 25088, 25891, 25899, 25898, +26348, 27408, 29914, 31434, 31844, 31843, 31845, 32403, 32406, 32404, +33250, 34360, 34367, 34865, 35722, 37008, 37007, 37987, 37984, 37988, +38760, 39023, 39260, 39514, 39515, 39511, 39635, 39636, 39633, 40020, +40023, 40022, 40421, 40607, 40692, 22225, 22761, 25900, 28766, 30321, +30322, 30679, 32592, 32648, 34870, 34873, 34914, 35731, 35730, 35734, +33399, 36123, 37312, 37994, 38722, 38728, 38724, 38854, 39024, 39519, +39714, 39768, 40031, 40441, 40442, 40572, 40573, 40711, 40823, 40818, +24307, 27414, 28771, 31852, 31854, 34875, 35264, 36513, 37313, 38002, +38000, 39025, 39262, 39638, 39715, 40652, 28772, 30682, 35738, 38007, +38857, 39522, 39525, 32412, 35740, 36522, 37317, 38013, 38014, 38012, +40055, 40056, 40695, 35924, 38015, 40474, 29224, 39530, 39729, 40475, +40478, 31858, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9312, 9313, 9314, 9315, + 9316, 9317, 9318, 9319, 9320, 9321, 9332, 9333, 9334, 9335, + 9336, 9337, 9338, 9339, 9340, 9341, 8560, 8561, 8562, 8563, + 8564, 8565, 8566, 8567, 8568, 8569, 20022, 20031, 20101, 20128, +20866, 20886, 20907, 21241, 21304, 21353, 21430, 22794, 23424, 24027, +24186, 24191, 24308, 24400, 24417, 25908, 26080, 30098, 30326, 36789, +38582, 168, 710, 12541, 12542, 12445, 12446, 12291, 20189, 12293, +12294, 12295, 12540, 65339, 65341, 10045, 12353, 12354, 12355, 12356, +12357, 12358, 12359, 12360, 12361, 12362, 12363, 12364, 12365, 12366, +12367, 12368, 12369, 12370, 12371, 12372, 12373, 12374, 12375, 12376, +12377, 12378, 12379, 12380, 12381, 12382, 12383, 12384, 12385, 12386, +12387, 12388, 12389, 12390, 12391, 12392, 12393, 12394, 12395, 12396, +12397, 12398, 12399, 12400, 12401, 12402, 12403, 12404, 12405, 12406, +12407, 12408, 12409, 12410, 12411, 12412, 12413, 12414, 12415, 12416, +12417, 12418, 12419, 12420, 12421, 12422, 12423, 12424, 12425, 12426, +12427, 12428, 12429, 12430, 12431, 12432, 12433, 12434, 12435, 12449, +12450, 12451, 12452, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12453, 12454, 12455, +12456, 12457, 12458, 12459, 12460, 12461, 12462, 12463, 12464, 12465, +12466, 12467, 12468, 12469, 12470, 12471, 12472, 12473, 12474, 12475, +12476, 12477, 12478, 12479, 12480, 12481, 12482, 12483, 12484, 12485, +12486, 12487, 12488, 12489, 12490, 12491, 12492, 12493, 12494, 12495, +12496, 12497, 12498, 12499, 12500, 12501, 12502, 12503, 12504, 12505, +12506, 12507, 12508, 12509, 12510, 12511, 12512, 12513, 12514, 12515, +12516, 12517, 12518, 12519, 12520, 12521, 12522, 12523, 12524, 12525, +12526, 12527, 12528, 12529, 12530, 12531, 12532, 12533, 12534, 1040, + 1041, 1042, 1043, 1044, 1045, 1025, 1046, 1047, 1048, 1049, + 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, + 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, + 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1105, 1078, + 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, + 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, + 1099, 1100, 1101, 1102, 1103, 8679, 8632, 8633, 12751, 63462, +20058, 63464, 20994, 17553, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 40880, 20872, +40881, 63470, 63471, 63472, 63473, 63474, 63475, 63476, 63477, 63478, +63479, 63480, 63481, 63482, 12443, 12444, 12436, 12535, 12536, 12537, +12538, 12539, 65377, 65378, 65379, 65380, 65381, 65382, 65383, 65384, +65385, 65386, 65387, 65388, 65389, 65390, 65391, 65392, 65393, 65394, +65395, 65396, 65506, 65508, 65287, 65282, 12849, 8470, 8481, 65397, +65398, 65399, 65400, 65401, 65402, 65403, 65404, 65405, 65406, 65407, +65408, 65409, 65410, 65411, 65412, 65413, 65414, 65415, 65416, 65417, +65418, 65419, 65420, 65421, 65422, 65423, 65424, 65425, 65426, 65427, +65428, 65429, 65430, 65431, 65432, 65433, 65434, 65435, 65436, 65437, +65438, 65439, 20034, 20060, 20981, 21274, 21378, 19975, 19980, 20039, +20109, 22231, 64012, 23662, 24435, 19983, 20871, 19982, 20014, 20115, +20162, 20169, 20168, 20888, 21244, 21356, 21433, 22304, 22787, 22828, +23568, 24063, 26081, 27571, 27596, 27668, 29247, 20017, 20028, 20200, +20188, 20201, 20193, 20189, 20186, 21004, 21276, 21324, 22306, 22307, +22807, 22831, 23425, 23428, 23570, 23611, 23668, 23667, 24068, 24192, +24194, 24521, 25097, 25168, 27669, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 27702, +27715, 27711, 27707, 29358, 29360, 29578, 31160, 32906, 38430, 20238, +20248, 20268, 20213, 20244, 20209, 20224, 20215, 20232, 20253, 20226, +20229, 20258, 20243, 20228, 20212, 20242, 20913, 21011, 21001, 21008, +21158, 21282, 21279, 21325, 21386, 21511, 22241, 22239, 22318, 22314, +22324, 22844, 22912, 22908, 22917, 22907, 22910, 22903, 22911, 23382, +23573, 23589, 23676, 23674, 23675, 23678, 24031, 24181, 24196, 24322, +24346, 24436, 24533, 24532, 24527, 25180, 25182, 25188, 25185, 25190, +25186, 25177, 25184, 25178, 25189, 26095, 26094, 26430, 26425, 26424, +26427, 26426, 26431, 26428, 26419, 27672, 27718, 27730, 27740, 27727, +27722, 27732, 27723, 27724, 28785, 29278, 29364, 29365, 29582, 29994, +30335, 31349, 32593, 33400, 33404, 33408, 33405, 33407, 34381, 35198, +37017, 37015, 37016, 37019, 37012, 38434, 38436, 38432, 38435, 20310, +20283, 20322, 20297, 20307, 20324, 20286, 20327, 20306, 20319, 20289, +20312, 20269, 20275, 20287, 20321, 20879, 20921, 21020, 21022, 21025, +21165, 21166, 21257, 21347, 21362, 21390, 21391, 21552, 21559, 21546, +21588, 21573, 21529, 21532, 21541, 21528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +21565, 21583, 21569, 21544, 21540, 21575, 22254, 22247, 22245, 22337, +22341, 22348, 22345, 22347, 22354, 22790, 22848, 22950, 22936, 22944, +22935, 22926, 22946, 22928, 22927, 22951, 22945, 23438, 23442, 23592, +23594, 23693, 23695, 23688, 23691, 23689, 23698, 23690, 23686, 23699, +23701, 24032, 24074, 24078, 24203, 24201, 24204, 24200, 24205, 24325, +24349, 24440, 24438, 24530, 24529, 24528, 24557, 24552, 24558, 24563, +24545, 24548, 24547, 24570, 24559, 24567, 24571, 24576, 24564, 25146, +25219, 25228, 25230, 25231, 25236, 25223, 25201, 25211, 25210, 25200, +25217, 25224, 25207, 25213, 25202, 25204, 25911, 26096, 26100, 26099, +26098, 26101, 26437, 26439, 26457, 26453, 26444, 26440, 26461, 26445, +26458, 26443, 27600, 27673, 27674, 27768, 27751, 27755, 27780, 27787, +27791, 27761, 27759, 27753, 27802, 27757, 27783, 27797, 27804, 27750, +27763, 27749, 27771, 27790, 28788, 28794, 29283, 29375, 29373, 29379, +29382, 29377, 29370, 29381, 29589, 29591, 29587, 29588, 29586, 30010, +30009, 30100, 30101, 30337, 31037, 32820, 32917, 32921, 32912, 32914, +32924, 33424, 33423, 33413, 33422, 33425, 33427, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 33418, 33411, 33412, 35960, 36809, 36799, 37023, 37025, 37029, +37022, 37031, 37024, 38448, 38440, 38447, 38445, 20019, 20376, 20348, +20357, 20349, 20352, 20359, 20342, 20340, 20361, 20356, 20343, 20300, +20375, 20330, 20378, 20345, 20353, 20344, 20368, 20380, 20372, 20382, +20370, 20354, 20373, 20331, 20334, 20894, 20924, 20926, 21045, 21042, +21043, 21062, 21041, 21180, 21258, 21259, 21308, 21394, 21396, 21639, +21631, 21633, 21649, 21634, 21640, 21611, 21626, 21630, 21605, 21612, +21620, 21606, 21645, 21615, 21601, 21600, 21656, 21603, 21607, 21604, +22263, 22265, 22383, 22386, 22381, 22379, 22385, 22384, 22390, 22400, +22389, 22395, 22387, 22388, 22370, 22376, 22397, 22796, 22853, 22965, +22970, 22991, 22990, 22962, 22988, 22977, 22966, 22972, 22979, 22998, +22961, 22973, 22976, 22984, 22964, 22983, 23394, 23397, 23443, 23445, +23620, 23623, 23726, 23716, 23712, 23733, 23727, 23720, 23724, 23711, +23715, 23725, 23714, 23722, 23719, 23709, 23717, 23734, 23728, 23718, +24087, 24084, 24089, 24360, 24354, 24355, 24356, 24404, 24450, 24446, +24445, 24542, 24549, 24621, 24614, 24601, 24626, 24587, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 24628, 24586, 24599, 24627, 24602, 24606, 24620, 24610, +24589, 24592, 24622, 24595, 24593, 24588, 24585, 24604, 25108, 25149, +25261, 25268, 25297, 25278, 25258, 25270, 25290, 25262, 25267, 25263, +25275, 25257, 25264, 25272, 25917, 26024, 26043, 26121, 26108, 26116, +26130, 26120, 26107, 26115, 26123, 26125, 26117, 26109, 26129, 26128, +26358, 26378, 26501, 26476, 26510, 26514, 26486, 26491, 26520, 26502, +26500, 26484, 26509, 26508, 26490, 26527, 26513, 26521, 26499, 26493, +26497, 26488, 26489, 26516, 27429, 27520, 27518, 27614, 27677, 27795, +27884, 27883, 27886, 27865, 27830, 27860, 27821, 27879, 27831, 27856, +27842, 27834, 27843, 27846, 27885, 27890, 27858, 27869, 27828, 27786, +27805, 27776, 27870, 27840, 27952, 27853, 27847, 27824, 27897, 27855, +27881, 27857, 28820, 28824, 28805, 28819, 28806, 28804, 28817, 28822, +28802, 28826, 28803, 29290, 29398, 29387, 29400, 29385, 29404, 29394, +29396, 29402, 29388, 29393, 29604, 29601, 29613, 29606, 29602, 29600, +29612, 29597, 29917, 29928, 30015, 30016, 30014, 30092, 30104, 30383, +30451, 30449, 30448, 30453, 30712, 30716, 30713, 30715, 30714, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 30711, 31042, 31039, 31173, 31352, 31355, 31483, +31861, 31997, 32821, 32911, 32942, 32931, 32952, 32949, 32941, 33312, +33440, 33472, 33451, 33434, 33432, 33435, 33461, 33447, 33454, 33468, +33438, 33466, 33460, 33448, 33441, 33449, 33474, 33444, 33475, 33462, +33442, 34416, 34415, 34413, 34414, 35926, 36818, 36811, 36819, 36813, +36822, 36821, 36823, 37042, 37044, 37039, 37043, 37040, 38457, 38461, +38460, 38458, 38467, 20429, 20421, 20435, 20402, 20425, 20427, 20417, +20436, 20444, 20441, 20411, 20403, 20443, 20423, 20438, 20410, 20416, +20409, 20460, 21060, 21065, 21184, 21186, 21309, 21372, 21399, 21398, +21401, 21400, 21690, 21665, 21677, 21669, 21711, 21699, 33549, 21687, +21678, 21718, 21686, 21701, 21702, 21664, 21616, 21692, 21666, 21694, +21618, 21726, 21680, 22453, 22430, 22431, 22436, 22412, 22423, 22429, +22427, 22420, 22424, 22415, 22425, 22437, 22426, 22421, 22772, 22797, +22867, 23009, 23006, 23022, 23040, 23025, 23005, 23034, 23037, 23036, +23030, 23012, 23026, 23031, 23003, 23017, 23027, 23029, 23008, 23038, +23028, 23021, 23464, 23628, 23760, 23768, 23756, 23767, 23755, 23771, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 23774, 23770, 23753, 23751, 23754, 23766, +23763, 23764, 23759, 23752, 23750, 23758, 23775, 23800, 24057, 24097, +24098, 24099, 24096, 24100, 24240, 24228, 24226, 24219, 24227, 24229, +24327, 24366, 24406, 24454, 24631, 24633, 24660, 24690, 24670, 24645, +24659, 24647, 24649, 24667, 24652, 24640, 24642, 24671, 24612, 24644, +24664, 24678, 24686, 25154, 25155, 25295, 25357, 25355, 25333, 25358, +25347, 25323, 25337, 25359, 25356, 25336, 25334, 25344, 25363, 25364, +25338, 25365, 25339, 25328, 25921, 25923, 26026, 26047, 26166, 26145, +26162, 26165, 26140, 26150, 26146, 26163, 26155, 26170, 26141, 26164, +26169, 26158, 26383, 26384, 26561, 26610, 26568, 26554, 26588, 26555, +26616, 26584, 26560, 26551, 26565, 26603, 26596, 26591, 26549, 26573, +26547, 26615, 26614, 26606, 26595, 26562, 26553, 26574, 26599, 26608, +26546, 26620, 26566, 26605, 26572, 26542, 26598, 26587, 26618, 26569, +26570, 26563, 26602, 26571, 27432, 27522, 27524, 27574, 27606, 27608, +27616, 27680, 27681, 27944, 27956, 27949, 27935, 27964, 27967, 27922, +27914, 27866, 27955, 27908, 27929, 27962, 27930, 27921, 27904, 27933, +27970, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 27905, 27928, 27959, 27907, 27919, +27968, 27911, 27936, 27948, 27912, 27938, 27913, 27920, 28855, 28831, +28862, 28849, 28848, 28833, 28852, 28853, 28841, 29249, 29257, 29258, +29292, 29296, 29299, 29294, 29386, 29412, 29416, 29419, 29407, 29418, +29414, 29411, 29573, 29644, 29634, 29640, 29637, 29625, 29622, 29621, +29620, 29675, 29631, 29639, 29630, 29635, 29638, 29624, 29643, 29932, +29934, 29998, 30023, 30024, 30119, 30122, 30329, 30404, 30472, 30467, +30468, 30469, 30474, 30455, 30459, 30458, 30695, 30696, 30726, 30737, +30738, 30725, 30736, 30735, 30734, 30729, 30723, 30739, 31050, 31052, +31051, 31045, 31044, 31189, 31181, 31183, 31190, 31182, 31360, 31358, +31441, 31488, 31489, 31866, 31864, 31865, 31871, 31872, 31873, 32003, +32008, 32001, 32600, 32657, 32653, 32702, 32775, 32782, 32783, 32788, +32823, 32984, 32967, 32992, 32977, 32968, 32962, 32976, 32965, 32995, +32985, 32988, 32970, 32981, 32969, 32975, 32983, 32998, 32973, 33279, +33313, 33428, 33497, 33534, 33529, 33543, 33512, 33536, 33493, 33594, +33515, 33494, 33524, 33516, 33505, 33522, 33525, 33548, 33531, 33526, +33520, 33514, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 33508, 33504, 33530, 33523, +33517, 34423, 34420, 34428, 34419, 34881, 34894, 34919, 34922, 34921, +35283, 35332, 35335, 36210, 36835, 36833, 36846, 36832, 37105, 37053, +37055, 37077, 37061, 37054, 37063, 37067, 37064, 37332, 37331, 38484, +38479, 38481, 38483, 38474, 38478, 20510, 20485, 20487, 20499, 20514, +20528, 20507, 20469, 20468, 20531, 20535, 20524, 20470, 20471, 20503, +20508, 20512, 20519, 20533, 20527, 20529, 20494, 20826, 20884, 20883, +20938, 20932, 20933, 20936, 20942, 21089, 21082, 21074, 21086, 21087, +21077, 21090, 21197, 21262, 21406, 21798, 21730, 21783, 21778, 21735, +21747, 21732, 21786, 21759, 21764, 21768, 21739, 21777, 21765, 21745, +21770, 21755, 21751, 21752, 21728, 21774, 21763, 21771, 22273, 22274, +22476, 22578, 22485, 22482, 22458, 22470, 22461, 22460, 22456, 22454, +22463, 22471, 22480, 22457, 22465, 22798, 22858, 23065, 23062, 23085, +23086, 23061, 23055, 23063, 23050, 23070, 23091, 23404, 23463, 23469, +23468, 23555, 23638, 23636, 23788, 23807, 23790, 23793, 23799, 23808, +23801, 24105, 24104, 24232, 24238, 24234, 24236, 24371, 24368, 24423, +24669, 24666, 24679, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 24641, 24738, 24712, +24704, 24722, 24705, 24733, 24707, 24725, 24731, 24727, 24711, 24732, +24718, 25113, 25158, 25330, 25360, 25430, 25388, 25412, 25413, 25398, +25411, 25572, 25401, 25419, 25418, 25404, 25385, 25409, 25396, 25432, +25428, 25433, 25389, 25415, 25395, 25434, 25425, 25400, 25431, 25408, +25416, 25930, 25926, 26054, 26051, 26052, 26050, 26186, 26207, 26183, +26193, 26386, 26387, 26655, 26650, 26697, 26674, 26675, 26683, 26699, +26703, 26646, 26673, 26652, 26677, 26667, 26669, 26671, 26702, 26692, +26676, 26653, 26642, 26644, 26662, 26664, 26670, 26701, 26682, 26661, +26656, 27436, 27439, 27437, 27441, 27444, 27501, 32898, 27528, 27622, +27620, 27624, 27619, 27618, 27623, 27685, 28026, 28003, 28004, 28022, +27917, 28001, 28050, 27992, 28002, 28013, 28015, 28049, 28045, 28143, +28031, 28038, 27998, 28007, 28000, 28055, 28016, 28028, 27999, 28034, +28056, 27951, 28008, 28043, 28030, 28032, 28036, 27926, 28035, 28027, +28029, 28021, 28048, 28892, 28883, 28881, 28893, 28875, 32569, 28898, +28887, 28882, 28894, 28896, 28884, 28877, 28869, 28870, 28871, 28890, +28878, 28897, 29250, 29304, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 29303, 29302, +29440, 29434, 29428, 29438, 29430, 29427, 29435, 29441, 29651, 29657, +29669, 29654, 29628, 29671, 29667, 29673, 29660, 29650, 29659, 29652, +29661, 29658, 29655, 29656, 29672, 29918, 29919, 29940, 29941, 29985, +30043, 30047, 30128, 30145, 30139, 30148, 30144, 30143, 30134, 30138, +30346, 30409, 30493, 30491, 30480, 30483, 30482, 30499, 30481, 30485, +30489, 30490, 30498, 30503, 30755, 30764, 30754, 30773, 30767, 30760, +30766, 30763, 30753, 30761, 30771, 30762, 30769, 31060, 31067, 31055, +31068, 31059, 31058, 31057, 31211, 31212, 31200, 31214, 31213, 31210, +31196, 31198, 31197, 31366, 31369, 31365, 31371, 31372, 31370, 31367, +31448, 31504, 31492, 31507, 31493, 31503, 31496, 31498, 31502, 31497, +31506, 31876, 31889, 31882, 31884, 31880, 31885, 31877, 32030, 32029, +32017, 32014, 32024, 32022, 32019, 32031, 32018, 32015, 32012, 32604, +32609, 32606, 32608, 32605, 32603, 32662, 32658, 32707, 32706, 32704, +32790, 32830, 32825, 33018, 33010, 33017, 33013, 33025, 33019, 33024, +33281, 33327, 33317, 33587, 33581, 33604, 33561, 33617, 33573, 33622, +33599, 33601, 33574, 33564, 33570, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 33602, +33614, 33563, 33578, 33544, 33596, 33613, 33558, 33572, 33568, 33591, +33583, 33577, 33607, 33605, 33612, 33619, 33566, 33580, 33611, 33575, +33608, 34387, 34386, 34466, 34472, 34454, 34445, 34449, 34462, 34439, +34455, 34438, 34443, 34458, 34437, 34469, 34457, 34465, 34471, 34453, +34456, 34446, 34461, 34448, 34452, 34883, 34884, 34925, 34933, 34934, +34930, 34944, 34929, 34943, 34927, 34947, 34942, 34932, 34940, 35346, +35911, 35927, 35963, 36004, 36003, 36214, 36216, 36277, 36279, 36278, +36561, 36563, 36862, 36853, 36866, 36863, 36859, 36868, 36860, 36854, +37078, 37088, 37081, 37082, 37091, 37087, 37093, 37080, 37083, 37079, +37084, 37092, 37200, 37198, 37199, 37333, 37346, 37338, 38492, 38495, +38588, 39139, 39647, 39727, 20095, 20592, 20586, 20577, 20574, 20576, +20563, 20555, 20573, 20594, 20552, 20557, 20545, 20571, 20554, 20578, +20501, 20549, 20575, 20585, 20587, 20579, 20580, 20550, 20544, 20590, +20595, 20567, 20561, 20944, 21099, 21101, 21100, 21102, 21206, 21203, +21293, 21404, 21877, 21878, 21820, 21837, 21840, 21812, 21802, 21841, +21858, 21814, 21813, 21808, 21842, 21829, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +21772, 21810, 21861, 21838, 21817, 21832, 21805, 21819, 21824, 21835, +22282, 22279, 22523, 22548, 22498, 22518, 22492, 22516, 22528, 22509, +22525, 22536, 22520, 22539, 22515, 22479, 22535, 22510, 22499, 22514, +22501, 22508, 22497, 22542, 22524, 22544, 22503, 22529, 22540, 22513, +22505, 22512, 22541, 22532, 22876, 23136, 23128, 23125, 23143, 23134, +23096, 23093, 23149, 23120, 23135, 23141, 23148, 23123, 23140, 23127, +23107, 23133, 23122, 23108, 23131, 23112, 23182, 23102, 23117, 23097, +23116, 23152, 23145, 23111, 23121, 23126, 23106, 23132, 23410, 23406, +23489, 23488, 23641, 23838, 23819, 23837, 23834, 23840, 23820, 23848, +23821, 23846, 23845, 23823, 23856, 23826, 23843, 23839, 23854, 24126, +24116, 24241, 24244, 24249, 24242, 24243, 24374, 24376, 24475, 24470, +24479, 24714, 24720, 24710, 24766, 24752, 24762, 24787, 24788, 24783, +24804, 24793, 24797, 24776, 24753, 24795, 24759, 24778, 24767, 24771, +24781, 24768, 25394, 25445, 25482, 25474, 25469, 25533, 25502, 25517, +25501, 25495, 25515, 25486, 25455, 25479, 25488, 25454, 25519, 25461, +25500, 25453, 25518, 25468, 25508, 25403, 25503, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 25464, 25477, 25473, 25489, 25485, 25456, 25939, 26061, 26213, +26209, 26203, 26201, 26204, 26210, 26392, 26745, 26759, 26768, 26780, +26733, 26734, 26798, 26795, 26966, 26735, 26787, 26796, 26793, 26741, +26740, 26802, 26767, 26743, 26770, 26748, 26731, 26738, 26794, 26752, +26737, 26750, 26779, 26774, 26763, 26784, 26761, 26788, 26744, 26747, +26769, 26764, 26762, 26749, 27446, 27443, 27447, 27448, 27537, 27535, +27533, 27534, 27532, 27690, 28096, 28075, 28084, 28083, 28276, 28076, +28137, 28130, 28087, 28150, 28116, 28160, 28104, 28128, 28127, 28118, +28094, 28133, 28124, 28125, 28123, 28148, 28106, 28093, 28141, 28144, +28090, 28117, 28098, 28111, 28105, 28112, 28146, 28115, 28157, 28119, +28109, 28131, 28091, 28922, 28941, 28919, 28951, 28916, 28940, 28912, +28932, 28915, 28944, 28924, 28927, 28934, 28947, 28928, 28920, 28918, +28939, 28930, 28942, 29310, 29307, 29308, 29311, 29469, 29463, 29447, +29457, 29464, 29450, 29448, 29439, 29455, 29470, 29576, 29686, 29688, +29685, 29700, 29697, 29693, 29703, 29696, 29690, 29692, 29695, 29708, +29707, 29684, 29704, 30052, 30051, 30158, 30162, 30159, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 30155, 30156, 30161, 30160, 30351, 30345, 30419, 30521, +30511, 30509, 30513, 30514, 30516, 30515, 30525, 30501, 30523, 30517, +30792, 30802, 30793, 30797, 30794, 30796, 30758, 30789, 30800, 31076, +31079, 31081, 31082, 31075, 31083, 31073, 31163, 31226, 31224, 31222, +31223, 31375, 31380, 31376, 31541, 31559, 31540, 31525, 31536, 31522, +31524, 31539, 31512, 31530, 31517, 31537, 31531, 31533, 31535, 31538, +31544, 31514, 31523, 31892, 31896, 31894, 31907, 32053, 32061, 32056, +32054, 32058, 32069, 32044, 32041, 32065, 32071, 32062, 32063, 32074, +32059, 32040, 32611, 32661, 32668, 32669, 32667, 32714, 32715, 32717, +32720, 32721, 32711, 32719, 32713, 32799, 32798, 32795, 32839, 32835, +32840, 33048, 33061, 33049, 33051, 33069, 33055, 33068, 33054, 33057, +33045, 33063, 33053, 33058, 33297, 33336, 33331, 33338, 33332, 33330, +33396, 33680, 33699, 33704, 33677, 33658, 33651, 33700, 33652, 33679, +33665, 33685, 33689, 33653, 33684, 33705, 33661, 33667, 33676, 33693, +33691, 33706, 33675, 33662, 33701, 33711, 33672, 33687, 33712, 33663, +33702, 33671, 33710, 33654, 33690, 34393, 34390, 34495, 34487, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 34498, 34497, 34501, 34490, 34480, 34504, 34489, +34483, 34488, 34508, 34484, 34491, 34492, 34499, 34493, 34494, 34898, +34953, 34965, 34984, 34978, 34986, 34970, 34961, 34977, 34975, 34968, +34983, 34969, 34971, 34967, 34980, 34988, 34956, 34963, 34958, 35202, +35286, 35289, 35285, 35376, 35367, 35372, 35358, 35897, 35899, 35932, +35933, 35965, 36005, 36221, 36219, 36217, 36284, 36290, 36281, 36287, +36289, 36568, 36574, 36573, 36572, 36567, 36576, 36577, 36900, 36875, +36881, 36892, 36876, 36897, 37103, 37098, 37104, 37108, 37106, 37107, +37076, 37099, 37100, 37097, 37206, 37208, 37210, 37203, 37205, 37356, +37364, 37361, 37363, 37368, 37348, 37369, 37354, 37355, 37367, 37352, +37358, 38266, 38278, 38280, 38524, 38509, 38507, 38513, 38511, 38591, +38762, 38916, 39141, 39319, 20635, 20629, 20628, 20638, 20619, 20643, +20611, 20620, 20622, 20637, 20584, 20636, 20626, 20610, 20615, 20831, +20948, 21266, 21265, 21412, 21415, 21905, 21928, 21925, 21933, 21879, +22085, 21922, 21907, 21896, 21903, 21941, 21889, 21923, 21906, 21924, +21885, 21900, 21926, 21887, 21909, 21921, 21902, 22284, 22569, 22583, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 22553, 22558, 22567, 22563, 22568, 22517, +22600, 22565, 22556, 22555, 22579, 22591, 22582, 22574, 22585, 22584, +22573, 22572, 22587, 22881, 23215, 23188, 23199, 23162, 23202, 23198, +23160, 23206, 23164, 23205, 23212, 23189, 23214, 23095, 23172, 23178, +23191, 23171, 23179, 23209, 23163, 23165, 23180, 23196, 23183, 23187, +23197, 23530, 23501, 23499, 23508, 23505, 23498, 23502, 23564, 23600, +23863, 23875, 23915, 23873, 23883, 23871, 23861, 23889, 23886, 23893, +23859, 23866, 23890, 23869, 23857, 23897, 23874, 23865, 23881, 23864, +23868, 23858, 23862, 23872, 23877, 24132, 24129, 24408, 24486, 24485, +24491, 24777, 24761, 24780, 24802, 24782, 24772, 24852, 24818, 24842, +24854, 24837, 24821, 24851, 24824, 24828, 24830, 24769, 24835, 24856, +24861, 24848, 24831, 24836, 24843, 25162, 25492, 25521, 25520, 25550, +25573, 25576, 25583, 25539, 25757, 25587, 25546, 25568, 25590, 25557, +25586, 25589, 25697, 25567, 25534, 25565, 25564, 25540, 25560, 25555, +25538, 25543, 25548, 25547, 25544, 25584, 25559, 25561, 25906, 25959, +25962, 25956, 25948, 25960, 25957, 25996, 26013, 26014, 26030, 26064, +26066, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26236, 26220, 26235, 26240, 26225, +26233, 26218, 26226, 26369, 26892, 26835, 26884, 26844, 26922, 26860, +26858, 26865, 26895, 26838, 26871, 26859, 26852, 26870, 26899, 26896, +26867, 26849, 26887, 26828, 26888, 26992, 26804, 26897, 26863, 26822, +26900, 26872, 26832, 26877, 26876, 26856, 26891, 26890, 26903, 26830, +26824, 26845, 26846, 26854, 26868, 26833, 26886, 26836, 26857, 26901, +26917, 26823, 27449, 27451, 27455, 27452, 27540, 27543, 27545, 27541, +27581, 27632, 27634, 27635, 27696, 28156, 28230, 28231, 28191, 28233, +28296, 28220, 28221, 28229, 28258, 28203, 28223, 28225, 28253, 28275, +28188, 28211, 28235, 28224, 28241, 28219, 28163, 28206, 28254, 28264, +28252, 28257, 28209, 28200, 28256, 28273, 28267, 28217, 28194, 28208, +28243, 28261, 28199, 28280, 28260, 28279, 28245, 28281, 28242, 28262, +28213, 28214, 28250, 28960, 28958, 28975, 28923, 28974, 28977, 28963, +28965, 28962, 28978, 28959, 28968, 28986, 28955, 29259, 29274, 29320, +29321, 29318, 29317, 29323, 29458, 29451, 29488, 29474, 29489, 29491, +29479, 29490, 29485, 29478, 29475, 29493, 29452, 29742, 29740, 29744, +29739, 29718, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 29722, 29729, 29741, 29745, +29732, 29731, 29725, 29737, 29728, 29746, 29947, 29999, 30063, 30060, +30183, 30170, 30177, 30182, 30173, 30175, 30180, 30167, 30357, 30354, +30426, 30534, 30535, 30532, 30541, 30533, 30538, 30542, 30539, 30540, +30686, 30700, 30816, 30820, 30821, 30812, 30829, 30833, 30826, 30830, +30832, 30825, 30824, 30814, 30818, 31092, 31091, 31090, 31088, 31234, +31242, 31235, 31244, 31236, 31385, 31462, 31460, 31562, 31547, 31556, +31560, 31564, 31566, 31552, 31576, 31557, 31906, 31902, 31912, 31905, +32088, 32111, 32099, 32083, 32086, 32103, 32106, 32079, 32109, 32092, +32107, 32082, 32084, 32105, 32081, 32095, 32078, 32574, 32575, 32613, +32614, 32674, 32672, 32673, 32727, 32849, 32847, 32848, 33022, 32980, +33091, 33098, 33106, 33103, 33095, 33085, 33101, 33082, 33254, 33262, +33271, 33272, 33273, 33284, 33340, 33341, 33343, 33397, 33595, 33743, +33785, 33827, 33728, 33768, 33810, 33767, 33764, 33788, 33782, 33808, +33734, 33736, 33771, 33763, 33727, 33793, 33757, 33765, 33752, 33791, +33761, 33739, 33742, 33750, 33781, 33737, 33801, 33807, 33758, 33809, +33798, 33730, 33779, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 33749, 33786, 33735, +33745, 33770, 33811, 33731, 33772, 33774, 33732, 33787, 33751, 33762, +33819, 33755, 33790, 34520, 34530, 34534, 34515, 34531, 34522, 34538, +34525, 34539, 34524, 34540, 34537, 34519, 34536, 34513, 34888, 34902, +34901, 35002, 35031, 35001, 35000, 35008, 35006, 34998, 35004, 34999, +35005, 34994, 35073, 35017, 35221, 35224, 35223, 35293, 35290, 35291, +35406, 35405, 35385, 35417, 35392, 35415, 35416, 35396, 35397, 35410, +35400, 35409, 35402, 35404, 35407, 35935, 35969, 35968, 36026, 36030, +36016, 36025, 36021, 36228, 36224, 36233, 36312, 36307, 36301, 36295, +36310, 36316, 36303, 36309, 36313, 36296, 36311, 36293, 36591, 36599, +36602, 36601, 36582, 36590, 36581, 36597, 36583, 36584, 36598, 36587, +36593, 36588, 36596, 36585, 36909, 36916, 36911, 37126, 37164, 37124, +37119, 37116, 37128, 37113, 37115, 37121, 37120, 37127, 37125, 37123, +37217, 37220, 37215, 37218, 37216, 37377, 37386, 37413, 37379, 37402, +37414, 37391, 37388, 37376, 37394, 37375, 37373, 37382, 37380, 37415, +37378, 37404, 37412, 37401, 37399, 37381, 37398, 38267, 38285, 38284, +38288, 38535, 38526, 38536, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 38537, 38531, +38528, 38594, 38600, 38595, 38641, 38640, 38764, 38768, 38766, 38919, +39081, 39147, 40166, 40697, 20099, 20100, 20150, 20669, 20671, 20678, +20654, 20676, 20682, 20660, 20680, 20674, 20656, 20673, 20666, 20657, +20683, 20681, 20662, 20664, 20951, 21114, 21112, 21115, 21116, 21955, +21979, 21964, 21968, 21963, 21962, 21981, 21952, 21972, 21956, 21993, +21951, 21970, 21901, 21967, 21973, 21986, 21974, 21960, 22002, 21965, +21977, 21954, 22292, 22611, 22632, 22628, 22607, 22605, 22601, 22639, +22613, 22606, 22621, 22617, 22629, 22619, 22589, 22627, 22641, 22780, +23239, 23236, 23243, 23226, 23224, 23217, 23221, 23216, 23231, 23240, +23227, 23238, 23223, 23232, 23242, 23220, 23222, 23245, 23225, 23184, +23510, 23512, 23513, 23583, 23603, 23921, 23907, 23882, 23909, 23922, +23916, 23902, 23912, 23911, 23906, 24048, 24143, 24142, 24138, 24141, +24139, 24261, 24268, 24262, 24267, 24263, 24384, 24495, 24493, 24823, +24905, 24906, 24875, 24901, 24886, 24882, 24878, 24902, 24879, 24911, +24873, 24896, 25120, 37224, 25123, 25125, 25124, 25541, 25585, 25579, +25616, 25618, 25609, 25632, 25636, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 25651, +25667, 25631, 25621, 25624, 25657, 25655, 25634, 25635, 25612, 25638, +25648, 25640, 25665, 25653, 25647, 25610, 25626, 25664, 25637, 25639, +25611, 25575, 25627, 25646, 25633, 25614, 25967, 26002, 26067, 26246, +26252, 26261, 26256, 26251, 26250, 26265, 26260, 26232, 26400, 26982, +26975, 26936, 26958, 26978, 26993, 26943, 26949, 26986, 26937, 26946, +26967, 26969, 27002, 26952, 26953, 26933, 26988, 26931, 26941, 26981, +26864, 27000, 26932, 26985, 26944, 26991, 26948, 26998, 26968, 26945, +26996, 26956, 26939, 26955, 26935, 26972, 26959, 26961, 26930, 26962, +26927, 27003, 26940, 27462, 27461, 27459, 27458, 27464, 27457, 27547, +64013, 27643, 27644, 27641, 27639, 27640, 28315, 28374, 28360, 28303, +28352, 28319, 28307, 28308, 28320, 28337, 28345, 28358, 28370, 28349, +28353, 28318, 28361, 28343, 28336, 28365, 28326, 28367, 28338, 28350, +28355, 28380, 28376, 28313, 28306, 28302, 28301, 28324, 28321, 28351, +28339, 28368, 28362, 28311, 28334, 28323, 28999, 29012, 29010, 29027, +29024, 28993, 29021, 29026, 29042, 29048, 29034, 29025, 28994, 29016, +28995, 29003, 29040, 29023, 29008, 29011, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +28996, 29005, 29018, 29263, 29325, 29324, 29329, 29328, 29326, 29500, +29506, 29499, 29498, 29504, 29514, 29513, 29764, 29770, 29771, 29778, +29777, 29783, 29760, 29775, 29776, 29774, 29762, 29766, 29773, 29780, +29921, 29951, 29950, 29949, 29981, 30073, 30071, 27011, 30191, 30223, +30211, 30199, 30206, 30204, 30201, 30200, 30224, 30203, 30198, 30189, +30197, 30205, 30361, 30389, 30429, 30549, 30559, 30560, 30546, 30550, +30554, 30569, 30567, 30548, 30553, 30573, 30688, 30855, 30874, 30868, +30863, 30852, 30869, 30853, 30854, 30881, 30851, 30841, 30873, 30848, +30870, 30843, 31100, 31106, 31101, 31097, 31249, 31256, 31257, 31250, +31255, 31253, 31266, 31251, 31259, 31248, 31395, 31394, 31390, 31467, +31590, 31588, 31597, 31604, 31593, 31602, 31589, 31603, 31601, 31600, +31585, 31608, 31606, 31587, 31922, 31924, 31919, 32136, 32134, 32128, +32141, 32127, 32133, 32122, 32142, 32123, 32131, 32124, 32140, 32148, +32132, 32125, 32146, 32621, 32619, 32615, 32616, 32620, 32678, 32677, +32679, 32731, 32732, 32801, 33124, 33120, 33143, 33116, 33129, 33115, +33122, 33138, 26401, 33118, 33142, 33127, 33135, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 33092, 33121, 33309, 33353, 33348, 33344, 33346, 33349, 34033, +33855, 33878, 33910, 33913, 33935, 33933, 33893, 33873, 33856, 33926, +33895, 33840, 33869, 33917, 33882, 33881, 33908, 33907, 33885, 34055, +33886, 33847, 33850, 33844, 33914, 33859, 33912, 33842, 33861, 33833, +33753, 33867, 33839, 33858, 33837, 33887, 33904, 33849, 33870, 33868, +33874, 33903, 33989, 33934, 33851, 33863, 33846, 33843, 33896, 33918, +33860, 33835, 33888, 33876, 33902, 33872, 34571, 34564, 34551, 34572, +34554, 34518, 34549, 34637, 34552, 34574, 34569, 34561, 34550, 34573, +34565, 35030, 35019, 35021, 35022, 35038, 35035, 35034, 35020, 35024, +35205, 35227, 35295, 35301, 35300, 35297, 35296, 35298, 35292, 35302, +35446, 35462, 35455, 35425, 35391, 35447, 35458, 35460, 35445, 35459, +35457, 35444, 35450, 35900, 35915, 35914, 35941, 35940, 35942, 35974, +35972, 35973, 36044, 36200, 36201, 36241, 36236, 36238, 36239, 36237, +36243, 36244, 36240, 36242, 36336, 36320, 36332, 36337, 36334, 36304, +36329, 36323, 36322, 36327, 36338, 36331, 36340, 36614, 36607, 36609, +36608, 36613, 36615, 36616, 36610, 36619, 36946, 36927, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 36932, 36937, 36925, 37136, 37133, 37135, 37137, 37142, +37140, 37131, 37134, 37230, 37231, 37448, 37458, 37424, 37434, 37478, +37427, 37477, 37470, 37507, 37422, 37450, 37446, 37485, 37484, 37455, +37472, 37479, 37487, 37430, 37473, 37488, 37425, 37460, 37475, 37456, +37490, 37454, 37459, 37452, 37462, 37426, 38303, 38300, 38302, 38299, +38546, 38547, 38545, 38551, 38606, 38650, 38653, 38648, 38645, 38771, +38775, 38776, 38770, 38927, 38925, 38926, 39084, 39158, 39161, 39343, +39346, 39344, 39349, 39597, 39595, 39771, 40170, 40173, 40167, 40576, +40701, 20710, 20692, 20695, 20712, 20723, 20699, 20714, 20701, 20708, +20691, 20716, 20720, 20719, 20707, 20704, 20952, 21120, 21121, 21225, +21227, 21296, 21420, 22055, 22037, 22028, 22034, 22012, 22031, 22044, +22017, 22035, 22018, 22010, 22045, 22020, 22015, 22009, 22665, 22652, +22672, 22680, 22662, 22657, 22655, 22644, 22667, 22650, 22663, 22673, +22670, 22646, 22658, 22664, 22651, 22676, 22671, 22782, 22891, 23260, +23278, 23269, 23253, 23274, 23258, 23277, 23275, 23283, 23266, 23264, +23259, 23276, 23262, 23261, 23257, 23272, 23263, 23415, 23520, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 23523, 23651, 23938, 23936, 23933, 23942, 23930, +23937, 23927, 23946, 23945, 23944, 23934, 23932, 23949, 23929, 23935, +24152, 24153, 24147, 24280, 24273, 24279, 24270, 24284, 24277, 24281, +24274, 24276, 24388, 24387, 24431, 24502, 24876, 24872, 24897, 24926, +24945, 24947, 24914, 24915, 24946, 24940, 24960, 24948, 24916, 24954, +24923, 24933, 24891, 24938, 24929, 24918, 25129, 25127, 25131, 25643, +25677, 25691, 25693, 25716, 25718, 25714, 25715, 25725, 25717, 25702, +25766, 25678, 25730, 25694, 25692, 25675, 25683, 25696, 25680, 25727, +25663, 25708, 25707, 25689, 25701, 25719, 25971, 26016, 26273, 26272, +26271, 26373, 26372, 26402, 27057, 27062, 27081, 27040, 27086, 27030, +27056, 27052, 27068, 27025, 27033, 27022, 27047, 27021, 27049, 27070, +27055, 27071, 27076, 27069, 27044, 27092, 27065, 27082, 27034, 27087, +27059, 27027, 27050, 27041, 27038, 27097, 27031, 27024, 27074, 27061, +27045, 27078, 27466, 27469, 27467, 27550, 27551, 27552, 27587, 27588, +27646, 28366, 28405, 28401, 28419, 28453, 28408, 28471, 28411, 28462, +28425, 28494, 28441, 28442, 28455, 28440, 28475, 28434, 28397, 28426, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 28470, 28531, 28409, 28398, 28461, 28480, +28464, 28476, 28469, 28395, 28423, 28430, 28483, 28421, 28413, 28406, +28473, 28444, 28412, 28474, 28447, 28429, 28446, 28424, 28449, 29063, +29072, 29065, 29056, 29061, 29058, 29071, 29051, 29062, 29057, 29079, +29252, 29267, 29335, 29333, 29331, 29507, 29517, 29521, 29516, 29794, +29811, 29809, 29813, 29810, 29799, 29806, 29952, 29954, 29955, 30077, +30096, 30230, 30216, 30220, 30229, 30225, 30218, 30228, 30392, 30593, +30588, 30597, 30594, 30574, 30592, 30575, 30590, 30595, 30898, 30890, +30900, 30893, 30888, 30846, 30891, 30878, 30885, 30880, 30892, 30882, +30884, 31128, 31114, 31115, 31126, 31125, 31124, 31123, 31127, 31112, +31122, 31120, 31275, 31306, 31280, 31279, 31272, 31270, 31400, 31403, +31404, 31470, 31624, 31644, 31626, 31633, 31632, 31638, 31629, 31628, +31643, 31630, 31621, 31640, 21124, 31641, 31652, 31618, 31931, 31935, +31932, 31930, 32167, 32183, 32194, 32163, 32170, 32193, 32192, 32197, +32157, 32206, 32196, 32198, 32203, 32204, 32175, 32185, 32150, 32188, +32159, 32166, 32174, 32169, 32161, 32201, 32627, 32738, 32739, 32741, +32734, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 32804, 32861, 32860, 33161, 33158, +33155, 33159, 33165, 33164, 33163, 33301, 33943, 33956, 33953, 33951, +33978, 33998, 33986, 33964, 33966, 33963, 33977, 33972, 33985, 33997, +33962, 33946, 33969, 34000, 33949, 33959, 33979, 33954, 33940, 33991, +33996, 33947, 33961, 33967, 33960, 34006, 33944, 33974, 33999, 33952, +34007, 34004, 34002, 34011, 33968, 33937, 34401, 34611, 34595, 34600, +34667, 34624, 34606, 34590, 34593, 34585, 34587, 34627, 34604, 34625, +34622, 34630, 34592, 34610, 34602, 34605, 34620, 34578, 34618, 34609, +34613, 34626, 34598, 34599, 34616, 34596, 34586, 34608, 34577, 35063, +35047, 35057, 35058, 35066, 35070, 35054, 35068, 35062, 35067, 35056, +35052, 35051, 35229, 35233, 35231, 35230, 35305, 35307, 35304, 35499, +35481, 35467, 35474, 35471, 35478, 35901, 35944, 35945, 36053, 36047, +36055, 36246, 36361, 36354, 36351, 36365, 36349, 36362, 36355, 36359, +36358, 36357, 36350, 36352, 36356, 36624, 36625, 36622, 36621, 37155, +37148, 37152, 37154, 37151, 37149, 37146, 37156, 37153, 37147, 37242, +37234, 37241, 37235, 37541, 37540, 37494, 37531, 37498, 37536, 37524, +37546, 37517, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37542, 37530, 37547, 37497, +37527, 37503, 37539, 37614, 37518, 37506, 37525, 37538, 37501, 37512, +37537, 37514, 37510, 37516, 37529, 37543, 37502, 37511, 37545, 37533, +37515, 37421, 38558, 38561, 38655, 38744, 38781, 38778, 38782, 38787, +38784, 38786, 38779, 38788, 38785, 38783, 38862, 38861, 38934, 39085, +39086, 39170, 39168, 39175, 39325, 39324, 39363, 39353, 39355, 39354, +39362, 39357, 39367, 39601, 39651, 39655, 39742, 39743, 39776, 39777, +39775, 40177, 40178, 40181, 40615, 20735, 20739, 20784, 20728, 20742, +20743, 20726, 20734, 20747, 20748, 20733, 20746, 21131, 21132, 21233, +21231, 22088, 22082, 22092, 22069, 22081, 22090, 22089, 22086, 22104, +22106, 22080, 22067, 22077, 22060, 22078, 22072, 22058, 22074, 22298, +22699, 22685, 22705, 22688, 22691, 22703, 22700, 22693, 22689, 22783, +23295, 23284, 23293, 23287, 23286, 23299, 23288, 23298, 23289, 23297, +23303, 23301, 23311, 23655, 23961, 23959, 23967, 23954, 23970, 23955, +23957, 23968, 23964, 23969, 23962, 23966, 24169, 24157, 24160, 24156, +32243, 24283, 24286, 24289, 24393, 24498, 24971, 24963, 24953, 25009, +25008, 24994, 24969, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 24987, 24979, 25007, +25005, 24991, 24978, 25002, 24993, 24973, 24934, 25011, 25133, 25710, +25712, 25750, 25760, 25733, 25751, 25756, 25743, 25739, 25738, 25740, +25763, 25759, 25704, 25777, 25752, 25974, 25978, 25977, 25979, 26034, +26035, 26293, 26288, 26281, 26290, 26295, 26282, 26287, 27136, 27142, +27159, 27109, 27128, 27157, 27121, 27108, 27168, 27135, 27116, 27106, +27163, 27165, 27134, 27175, 27122, 27118, 27156, 27127, 27111, 27200, +27144, 27110, 27131, 27149, 27132, 27115, 27145, 27140, 27160, 27173, +27151, 27126, 27174, 27143, 27124, 27158, 27473, 27557, 27555, 27554, +27558, 27649, 27648, 27647, 27650, 28481, 28454, 28542, 28551, 28614, +28562, 28557, 28553, 28556, 28514, 28495, 28549, 28506, 28566, 28534, +28524, 28546, 28501, 28530, 28498, 28496, 28503, 28564, 28563, 28509, +28416, 28513, 28523, 28541, 28519, 28560, 28499, 28555, 28521, 28543, +28565, 28515, 28535, 28522, 28539, 29106, 29103, 29083, 29104, 29088, +29082, 29097, 29109, 29085, 29093, 29086, 29092, 29089, 29098, 29084, +29095, 29107, 29336, 29338, 29528, 29522, 29534, 29535, 29536, 29533, +29531, 29537, 29530, 29529, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 29538, 29831, +29833, 29834, 29830, 29825, 29821, 29829, 29832, 29820, 29817, 29960, +29959, 30078, 30245, 30238, 30233, 30237, 30236, 30243, 30234, 30248, +30235, 30364, 30365, 30366, 30363, 30605, 30607, 30601, 30600, 30925, +30907, 30927, 30924, 30929, 30926, 30932, 30920, 30915, 30916, 30921, +31130, 31137, 31136, 31132, 31138, 31131, 27510, 31289, 31410, 31412, +31411, 31671, 31691, 31678, 31660, 31694, 31663, 31673, 31690, 31669, +31941, 31944, 31948, 31947, 32247, 32219, 32234, 32231, 32215, 32225, +32259, 32250, 32230, 32246, 32241, 32240, 32238, 32223, 32630, 32684, +32688, 32685, 32749, 32747, 32746, 32748, 32742, 32744, 32868, 32871, +33187, 33183, 33182, 33173, 33186, 33177, 33175, 33302, 33359, 33363, +33362, 33360, 33358, 33361, 34084, 34107, 34063, 34048, 34089, 34062, +34057, 34061, 34079, 34058, 34087, 34076, 34043, 34091, 34042, 34056, +34060, 34036, 34090, 34034, 34069, 34039, 34027, 34035, 34044, 34066, +34026, 34025, 34070, 34046, 34088, 34077, 34094, 34050, 34045, 34078, +34038, 34097, 34086, 34023, 34024, 34032, 34031, 34041, 34072, 34080, +34096, 34059, 34073, 34095, 34402, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 34646, +34659, 34660, 34679, 34785, 34675, 34648, 34644, 34651, 34642, 34657, +34650, 34641, 34654, 34669, 34666, 34640, 34638, 34655, 34653, 34671, +34668, 34682, 34670, 34652, 34661, 34639, 34683, 34677, 34658, 34663, +34665, 34906, 35077, 35084, 35092, 35083, 35095, 35096, 35097, 35078, +35094, 35089, 35086, 35081, 35234, 35236, 35235, 35309, 35312, 35308, +35535, 35526, 35512, 35539, 35537, 35540, 35541, 35515, 35543, 35518, +35520, 35525, 35544, 35523, 35514, 35517, 35545, 35902, 35917, 35983, +36069, 36063, 36057, 36072, 36058, 36061, 36071, 36256, 36252, 36257, +36251, 36384, 36387, 36389, 36388, 36398, 36373, 36379, 36374, 36369, +36377, 36390, 36391, 36372, 36370, 36376, 36371, 36380, 36375, 36378, +36652, 36644, 36632, 36634, 36640, 36643, 36630, 36631, 36979, 36976, +36975, 36967, 36971, 37167, 37163, 37161, 37162, 37170, 37158, 37166, +37253, 37254, 37258, 37249, 37250, 37252, 37248, 37584, 37571, 37572, +37568, 37593, 37558, 37583, 37617, 37599, 37592, 37609, 37591, 37597, +37580, 37615, 37570, 37608, 37578, 37576, 37582, 37606, 37581, 37589, +37577, 37600, 37598, 37607, 37585, 37587, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +37557, 37601, 37574, 37556, 38268, 38316, 38315, 38318, 38320, 38564, +38562, 38611, 38661, 38664, 38658, 38746, 38794, 38798, 38792, 38864, +38863, 38942, 38941, 38950, 38953, 38952, 38944, 38939, 38951, 39090, +39176, 39162, 39185, 39188, 39190, 39191, 39189, 39388, 39373, 39375, +39379, 39380, 39374, 39369, 39382, 39384, 39371, 39383, 39372, 39603, +39660, 39659, 39667, 39666, 39665, 39750, 39747, 39783, 39796, 39793, +39782, 39798, 39797, 39792, 39784, 39780, 39788, 40188, 40186, 40189, +40191, 40183, 40199, 40192, 40185, 40187, 40200, 40197, 40196, 40579, +40659, 40719, 40720, 20764, 20755, 20759, 20762, 20753, 20958, 21300, +21473, 22128, 22112, 22126, 22131, 22118, 22115, 22125, 22130, 22110, +22135, 22300, 22299, 22728, 22717, 22729, 22719, 22714, 22722, 22716, +22726, 23319, 23321, 23323, 23329, 23316, 23315, 23312, 23318, 23336, +23322, 23328, 23326, 23535, 23980, 23985, 23977, 23975, 23989, 23984, +23982, 23978, 23976, 23986, 23981, 23983, 23988, 24167, 24168, 24166, +24175, 24297, 24295, 24294, 24296, 24293, 24395, 24508, 24989, 25000, +24982, 25029, 25012, 25030, 25025, 25036, 25018, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 25023, 25016, 24972, 25815, 25814, 25808, 25807, 25801, 25789, +25737, 25795, 25819, 25843, 25817, 25907, 25983, 25980, 26018, 26312, +26302, 26304, 26314, 26315, 26319, 26301, 26299, 26298, 26316, 26403, +27188, 27238, 27209, 27239, 27186, 27240, 27198, 27229, 27245, 27254, +27227, 27217, 27176, 27226, 27195, 27199, 27201, 27242, 27236, 27216, +27215, 27220, 27247, 27241, 27232, 27196, 27230, 27222, 27221, 27213, +27214, 27206, 27477, 27476, 27478, 27559, 27562, 27563, 27592, 27591, +27652, 27651, 27654, 28589, 28619, 28579, 28615, 28604, 28622, 28616, +28510, 28612, 28605, 28574, 28618, 28584, 28676, 28581, 28590, 28602, +28588, 28586, 28623, 28607, 28600, 28578, 28617, 28587, 28621, 28591, +28594, 28592, 29125, 29122, 29119, 29112, 29142, 29120, 29121, 29131, +29140, 29130, 29127, 29135, 29117, 29144, 29116, 29126, 29146, 29147, +29341, 29342, 29545, 29542, 29543, 29548, 29541, 29547, 29546, 29823, +29850, 29856, 29844, 29842, 29845, 29857, 29963, 30080, 30255, 30253, +30257, 30269, 30259, 30268, 30261, 30258, 30256, 30395, 30438, 30618, +30621, 30625, 30620, 30619, 30626, 30627, 30613, 30617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 30615, 30941, 30953, 30949, 30954, 30942, 30947, 30939, +30945, 30946, 30957, 30943, 30944, 31140, 31300, 31304, 31303, 31414, +31416, 31413, 31409, 31415, 31710, 31715, 31719, 31709, 31701, 31717, +31706, 31720, 31737, 31700, 31722, 31714, 31708, 31723, 31704, 31711, +31954, 31956, 31959, 31952, 31953, 32274, 32289, 32279, 32268, 32287, +32288, 32275, 32270, 32284, 32277, 32282, 32290, 32267, 32271, 32278, +32269, 32276, 32293, 32292, 32579, 32635, 32636, 32634, 32689, 32751, +32810, 32809, 32876, 33201, 33190, 33198, 33209, 33205, 33195, 33200, +33196, 33204, 33202, 33207, 33191, 33266, 33365, 33366, 33367, 34134, +34117, 34155, 34125, 34131, 34145, 34136, 34112, 34118, 34148, 34113, +34146, 34116, 34129, 34119, 34147, 34110, 34139, 34161, 34126, 34158, +34165, 34133, 34151, 34144, 34188, 34150, 34141, 34132, 34149, 34156, +34403, 34405, 34404, 34715, 34703, 34711, 34707, 34706, 34696, 34689, +34710, 34712, 34681, 34695, 34723, 34693, 34704, 34705, 34717, 34692, +34708, 34716, 34714, 34697, 35102, 35110, 35120, 35117, 35118, 35111, +35121, 35106, 35113, 35107, 35119, 35116, 35103, 35313, 35552, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 35554, 35570, 35572, 35573, 35549, 35604, 35556, +35551, 35568, 35528, 35550, 35553, 35560, 35583, 35567, 35579, 35985, +35986, 35984, 36085, 36078, 36081, 36080, 36083, 36204, 36206, 36261, +36263, 36403, 36414, 36408, 36416, 36421, 36406, 36412, 36413, 36417, +36400, 36415, 36541, 36662, 36654, 36661, 36658, 36665, 36663, 36660, +36982, 36985, 36987, 36998, 37114, 37171, 37173, 37174, 37267, 37264, +37265, 37261, 37263, 37671, 37662, 37640, 37663, 37638, 37647, 37754, +37688, 37692, 37659, 37667, 37650, 37633, 37702, 37677, 37646, 37645, +37579, 37661, 37626, 37669, 37651, 37625, 37623, 37684, 37634, 37668, +37631, 37673, 37689, 37685, 37674, 37652, 37644, 37643, 37630, 37641, +37632, 37627, 37654, 38332, 38349, 38334, 38329, 38330, 38326, 38335, +38325, 38333, 38569, 38612, 38667, 38674, 38672, 38809, 38807, 38804, +38896, 38904, 38965, 38959, 38962, 39204, 39199, 39207, 39209, 39326, +39406, 39404, 39397, 39396, 39408, 39395, 39402, 39401, 39399, 39609, +39615, 39604, 39611, 39670, 39674, 39673, 39671, 39731, 39808, 39813, +39815, 39804, 39806, 39803, 39810, 39827, 39826, 39824, 39802, 39829, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 39805, 39816, 40229, 40215, 40224, 40222, +40212, 40233, 40221, 40216, 40226, 40208, 40217, 40223, 40584, 40582, +40583, 40622, 40621, 40661, 40662, 40698, 40722, 40765, 20774, 20773, +20770, 20772, 20768, 20777, 21236, 22163, 22156, 22157, 22150, 22148, +22147, 22142, 22146, 22143, 22145, 22742, 22740, 22735, 22738, 23341, +23333, 23346, 23331, 23340, 23335, 23334, 23343, 23342, 23419, 23537, +23538, 23991, 24172, 24170, 24510, 24507, 25027, 25013, 25020, 25063, +25056, 25061, 25060, 25064, 25054, 25839, 25833, 25827, 25835, 25828, +25832, 25985, 25984, 26038, 26074, 26322, 27277, 27286, 27265, 27301, +27273, 27295, 27291, 27297, 27294, 27271, 27283, 27278, 27285, 27267, +27304, 27300, 27281, 27263, 27302, 27290, 27269, 27276, 27282, 27483, +27565, 27657, 28620, 28585, 28660, 28628, 28643, 28636, 28653, 28647, +28646, 28638, 28658, 28637, 28642, 28648, 29153, 29169, 29160, 29170, +29156, 29168, 29154, 29555, 29550, 29551, 29847, 29874, 29867, 29840, +29866, 29869, 29873, 29861, 29871, 29968, 29969, 29970, 29967, 30084, +30275, 30280, 30281, 30279, 30372, 30441, 30645, 30635, 30642, 30647, +30646, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 30644, 30641, 30632, 30704, 30963, +30973, 30978, 30971, 30972, 30962, 30981, 30969, 30974, 30980, 31147, +31144, 31324, 31323, 31318, 31320, 31316, 31322, 31422, 31424, 31425, +31749, 31759, 31730, 31744, 31743, 31739, 31758, 31732, 31755, 31731, +31746, 31753, 31747, 31745, 31736, 31741, 31750, 31728, 31729, 31760, +31754, 31976, 32301, 32316, 32322, 32307, 38984, 32312, 32298, 32329, +32320, 32327, 32297, 32332, 32304, 32315, 32310, 32324, 32314, 32581, +32639, 32638, 32637, 32756, 32754, 32812, 33211, 33220, 33228, 33226, +33221, 33223, 33212, 33257, 33371, 33370, 33372, 34179, 34176, 34191, +34215, 34197, 34208, 34187, 34211, 34171, 34212, 34202, 34206, 34167, +34172, 34185, 34209, 34170, 34168, 34135, 34190, 34198, 34182, 34189, +34201, 34205, 34177, 34210, 34178, 34184, 34181, 34169, 34166, 34200, +34192, 34207, 34408, 34750, 34730, 34733, 34757, 34736, 34732, 34745, +34741, 34748, 34734, 34761, 34755, 34754, 34764, 34743, 34735, 34756, +34762, 34740, 34742, 34751, 34744, 34749, 34782, 34738, 35125, 35123, +35132, 35134, 35137, 35154, 35127, 35138, 35245, 35247, 35246, 35314, +35315, 35614, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 35608, 35606, 35601, 35589, +35595, 35618, 35599, 35602, 35605, 35591, 35597, 35592, 35590, 35612, +35603, 35610, 35919, 35952, 35954, 35953, 35951, 35989, 35988, 36089, +36207, 36430, 36429, 36435, 36432, 36428, 36423, 36675, 36672, 36997, +36990, 37176, 37274, 37282, 37275, 37273, 37279, 37281, 37277, 37280, +37793, 37763, 37807, 37732, 37718, 37703, 37756, 37720, 37724, 37750, +37705, 37712, 37713, 37728, 37741, 37775, 37708, 37738, 37753, 37719, +37717, 37714, 37711, 37745, 37751, 37755, 37729, 37726, 37731, 37735, +37760, 37710, 37721, 38343, 38336, 38345, 38339, 38341, 38327, 38574, +38576, 38572, 38688, 38687, 38680, 38685, 38681, 38810, 38817, 38812, +38814, 38813, 38869, 38868, 38897, 38977, 38980, 38986, 38985, 38981, +38979, 39205, 39211, 39212, 39210, 39219, 39218, 39215, 39213, 39217, +39216, 39320, 39331, 39329, 39426, 39418, 39412, 39415, 39417, 39416, +39414, 39419, 39421, 39422, 39420, 39427, 39614, 39678, 39677, 39681, +39676, 39752, 39834, 39848, 39838, 39835, 39846, 39841, 39845, 39844, +39814, 39842, 39840, 39855, 40243, 40257, 40295, 40246, 40238, 40239, +40241, 40248, 40240, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 40261, 40258, 40259, +40254, 40247, 40256, 40253, 32757, 40237, 40586, 40585, 40589, 40624, +40648, 40666, 40699, 40703, 40740, 40739, 40738, 40788, 40864, 20785, +20781, 20782, 22168, 22172, 22167, 22170, 22173, 22169, 22896, 23356, +23657, 23658, 24000, 24173, 24174, 25048, 25055, 25069, 25070, 25073, +25066, 25072, 25067, 25046, 25065, 25855, 25860, 25853, 25848, 25857, +25859, 25852, 26004, 26075, 26330, 26331, 26328, 27333, 27321, 27325, +27361, 27334, 27322, 27318, 27319, 27335, 27316, 27309, 27486, 27593, +27659, 28679, 28684, 28685, 28673, 28677, 28692, 28686, 28671, 28672, +28667, 28710, 28668, 28663, 28682, 29185, 29183, 29177, 29187, 29181, +29558, 29880, 29888, 29877, 29889, 29886, 29878, 29883, 29890, 29972, +29971, 30300, 30308, 30297, 30288, 30291, 30295, 30298, 30374, 30397, +30444, 30658, 30650, 30975, 30988, 30995, 30996, 30985, 30992, 30994, +30993, 31149, 31148, 31327, 31772, 31785, 31769, 31776, 31775, 31789, +31773, 31782, 31784, 31778, 31781, 31792, 32348, 32336, 32342, 32355, +32344, 32354, 32351, 32337, 32352, 32343, 32339, 32693, 32691, 32759, +32760, 32885, 33233, 33234, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 33232, 33375, +33374, 34228, 34246, 34240, 34243, 34242, 34227, 34229, 34237, 34247, +34244, 34239, 34251, 34254, 34248, 34245, 34225, 34230, 34258, 34340, +34232, 34231, 34238, 34409, 34791, 34790, 34786, 34779, 34795, 34794, +34789, 34783, 34803, 34788, 34772, 34780, 34771, 34797, 34776, 34787, +34724, 34775, 34777, 34817, 34804, 34792, 34781, 35155, 35147, 35151, +35148, 35142, 35152, 35153, 35145, 35626, 35623, 35619, 35635, 35632, +35637, 35655, 35631, 35644, 35646, 35633, 35621, 35639, 35622, 35638, +35630, 35620, 35643, 35645, 35642, 35906, 35957, 35993, 35992, 35991, +36094, 36100, 36098, 36096, 36444, 36450, 36448, 36439, 36438, 36446, +36453, 36455, 36443, 36442, 36449, 36445, 36457, 36436, 36678, 36679, +36680, 36683, 37160, 37178, 37179, 37182, 37288, 37285, 37287, 37295, +37290, 37813, 37772, 37778, 37815, 37787, 37789, 37769, 37799, 37774, +37802, 37790, 37798, 37781, 37768, 37785, 37791, 37773, 37809, 37777, +37810, 37796, 37800, 37812, 37795, 37797, 38354, 38355, 38353, 38579, +38615, 38618, 24002, 38623, 38616, 38621, 38691, 38690, 38693, 38828, +38830, 38824, 38827, 38820, 38826, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 38818, +38821, 38871, 38873, 38870, 38872, 38906, 38992, 38993, 38994, 39096, +39233, 39228, 39226, 39439, 39435, 39433, 39437, 39428, 39441, 39434, +39429, 39431, 39430, 39616, 39644, 39688, 39684, 39685, 39721, 39733, +39754, 39756, 39755, 39879, 39878, 39875, 39871, 39873, 39861, 39864, +39891, 39862, 39876, 39865, 39869, 40284, 40275, 40271, 40266, 40283, +40267, 40281, 40278, 40268, 40279, 40274, 40276, 40287, 40280, 40282, +40590, 40588, 40671, 40705, 40704, 40726, 40741, 40747, 40746, 40745, +40744, 40780, 40789, 20788, 20789, 21142, 21239, 21428, 22187, 22189, +22182, 22183, 22186, 22188, 22746, 22749, 22747, 22802, 23357, 23358, +23359, 24003, 24176, 24511, 25083, 25863, 25872, 25869, 25865, 25868, +25870, 25988, 26078, 26077, 26334, 27367, 27360, 27340, 27345, 27353, +27339, 27359, 27356, 27344, 27371, 27343, 27341, 27358, 27488, 27568, +27660, 28697, 28711, 28704, 28694, 28715, 28705, 28706, 28707, 28713, +28695, 28708, 28700, 28714, 29196, 29194, 29191, 29186, 29189, 29349, +29350, 29348, 29347, 29345, 29899, 29893, 29879, 29891, 29974, 30304, +30665, 30666, 30660, 30705, 31005, 31003, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +31009, 31004, 30999, 31006, 31152, 31335, 31336, 31795, 31804, 31801, +31788, 31803, 31980, 31978, 32374, 32373, 32376, 32368, 32375, 32367, +32378, 32370, 32372, 32360, 32587, 32586, 32643, 32646, 32695, 32765, +32766, 32888, 33239, 33237, 33380, 33377, 33379, 34283, 34289, 34285, +34265, 34273, 34280, 34266, 34263, 34284, 34290, 34296, 34264, 34271, +34275, 34268, 34257, 34288, 34278, 34287, 34270, 34274, 34816, 34810, +34819, 34806, 34807, 34825, 34828, 34827, 34822, 34812, 34824, 34815, +34826, 34818, 35170, 35162, 35163, 35159, 35169, 35164, 35160, 35165, +35161, 35208, 35255, 35254, 35318, 35664, 35656, 35658, 35648, 35667, +35670, 35668, 35659, 35669, 35665, 35650, 35666, 35671, 35907, 35959, +35958, 35994, 36102, 36103, 36105, 36268, 36266, 36269, 36267, 36461, +36472, 36467, 36458, 36463, 36475, 36546, 36690, 36689, 36687, 36688, +36691, 36788, 37184, 37183, 37296, 37293, 37854, 37831, 37839, 37826, +37850, 37840, 37881, 37868, 37836, 37849, 37801, 37862, 37834, 37844, +37870, 37859, 37845, 37828, 37838, 37824, 37842, 37863, 38269, 38362, +38363, 38625, 38697, 38699, 38700, 38696, 38694, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 38835, 38839, 38838, 38877, 38878, 38879, 39004, 39001, 39005, +38999, 39103, 39101, 39099, 39102, 39240, 39239, 39235, 39334, 39335, +39450, 39445, 39461, 39453, 39460, 39451, 39458, 39456, 39463, 39459, +39454, 39452, 39444, 39618, 39691, 39690, 39694, 39692, 39735, 39914, +39915, 39904, 39902, 39908, 39910, 39906, 39920, 39892, 39895, 39916, +39900, 39897, 39909, 39893, 39905, 39898, 40311, 40321, 40330, 40324, +40328, 40305, 40320, 40312, 40326, 40331, 40332, 40317, 40299, 40308, +40309, 40304, 40297, 40325, 40307, 40315, 40322, 40303, 40313, 40319, +40327, 40296, 40596, 40593, 40640, 40700, 40749, 40768, 40769, 40781, +40790, 40791, 40792, 21303, 22194, 22197, 22195, 22755, 23365, 24006, +24007, 24302, 24303, 24512, 24513, 25081, 25879, 25878, 25877, 25875, +26079, 26344, 26339, 26340, 27379, 27376, 27370, 27368, 27385, 27377, +27374, 27375, 28732, 28725, 28719, 28727, 28724, 28721, 28738, 28728, +28735, 28730, 28729, 28736, 28731, 28723, 28737, 29203, 29204, 29352, +29565, 29564, 29882, 30379, 30378, 30398, 30445, 30668, 30670, 30671, +30669, 30706, 31013, 31011, 31015, 31016, 31012, 31017, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 31154, 31342, 31340, 31341, 31479, 31817, 31816, 31818, +31815, 31813, 31982, 32379, 32382, 32385, 32384, 32698, 32767, 32889, +33243, 33241, 33291, 33384, 33385, 34338, 34303, 34305, 34302, 34331, +34304, 34294, 34308, 34313, 34309, 34316, 34301, 34841, 34832, 34833, +34839, 34835, 34838, 35171, 35174, 35257, 35319, 35680, 35690, 35677, +35688, 35683, 35685, 35687, 35693, 36270, 36486, 36488, 36484, 36697, +36694, 36695, 36693, 36696, 36698, 37005, 37187, 37185, 37303, 37301, +37298, 37299, 37899, 37907, 37883, 37920, 37903, 37908, 37886, 37909, +37904, 37928, 37913, 37901, 37877, 37888, 37879, 37895, 37902, 37910, +37906, 37882, 37897, 37880, 37898, 37887, 37884, 37900, 37878, 37905, +37894, 38366, 38368, 38367, 38702, 38703, 38841, 38843, 38909, 38910, +39008, 39010, 39011, 39007, 39105, 39106, 39248, 39246, 39257, 39244, +39243, 39251, 39474, 39476, 39473, 39468, 39466, 39478, 39465, 39470, +39480, 39469, 39623, 39626, 39622, 39696, 39698, 39697, 39947, 39944, +39927, 39941, 39954, 39928, 40000, 39943, 39950, 39942, 39959, 39956, +39945, 40351, 40345, 40356, 40349, 40338, 40344, 40336, 40347, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 40352, 40340, 40348, 40362, 40343, 40353, 40346, +40354, 40360, 40350, 40355, 40383, 40361, 40342, 40358, 40359, 40601, +40603, 40602, 40677, 40676, 40679, 40678, 40752, 40750, 40795, 40800, +40798, 40797, 40793, 40849, 20794, 20793, 21144, 21143, 22211, 22205, +22206, 23368, 23367, 24011, 24015, 24305, 25085, 25883, 27394, 27388, +27395, 27384, 27392, 28739, 28740, 28746, 28744, 28745, 28741, 28742, +29213, 29210, 29209, 29566, 29975, 30314, 30672, 31021, 31025, 31023, +31828, 31827, 31986, 32394, 32391, 32392, 32395, 32390, 32397, 32589, +32699, 32816, 33245, 34328, 34346, 34342, 34335, 34339, 34332, 34329, +34343, 34350, 34337, 34336, 34345, 34334, 34341, 34857, 34845, 34843, +34848, 34852, 34844, 34859, 34890, 35181, 35177, 35182, 35179, 35322, +35705, 35704, 35653, 35706, 35707, 36112, 36116, 36271, 36494, 36492, +36702, 36699, 36701, 37190, 37188, 37189, 37305, 37951, 37947, 37942, +37929, 37949, 37948, 37936, 37945, 37930, 37943, 37932, 37952, 37937, +38373, 38372, 38371, 38709, 38714, 38847, 38881, 39012, 39113, 39110, +39104, 39256, 39254, 39481, 39485, 39494, 39492, 39490, 39489, 39482, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 39487, 39629, 39701, 39703, 39704, 39702, +39738, 39762, 39979, 39965, 39964, 39980, 39971, 39976, 39977, 39972, +39969, 40375, 40374, 40380, 40385, 40391, 40394, 40399, 40382, 40389, +40387, 40379, 40373, 40398, 40377, 40378, 40364, 40392, 40369, 40365, +40396, 40371, 40397, 40370, 40570, 40604, 40683, 40686, 40685, 40731, +40728, 40730, 40753, 40782, 40805, 40804, 40850, 20153, 22214, 22213, +22219, 22897, 23371, 23372, 24021, 24017, 24306, 25889, 25888, 25894, +25890, 27403, 27400, 27401, 27661, 28757, 28758, 28759, 28754, 29214, +29215, 29353, 29567, 29912, 29909, 29913, 29911, 30317, 30381, 31029, +31156, 31344, 31345, 31831, 31836, 31833, 31835, 31834, 31988, 31985, +32401, 32591, 32647, 33246, 33387, 34356, 34357, 34355, 34348, 34354, +34358, 34860, 34856, 34854, 34858, 34853, 35185, 35263, 35262, 35323, +35710, 35716, 35714, 35718, 35717, 35711, 36117, 36501, 36500, 36506, +36498, 36496, 36502, 36503, 36704, 36706, 37191, 37964, 37968, 37962, +37963, 37967, 37959, 37957, 37960, 37961, 37958, 38719, 38883, 39018, +39017, 39115, 39252, 39259, 39502, 39507, 39508, 39500, 39503, 39496, +39498, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 39497, 39506, 39504, 39632, 39705, +39723, 39739, 39766, 39765, 40006, 40008, 39999, 40004, 39993, 39987, +40001, 39996, 39991, 39988, 39986, 39997, 39990, 40411, 40402, 40414, +40410, 40395, 40400, 40412, 40401, 40415, 40425, 40409, 40408, 40406, +40437, 40405, 40413, 40630, 40688, 40757, 40755, 40754, 40770, 40811, +40853, 40866, 20797, 21145, 22760, 22759, 22898, 23373, 24024, 34863, +24399, 25089, 25091, 25092, 25897, 25893, 26006, 26347, 27409, 27410, +27407, 27594, 28763, 28762, 29218, 29570, 29569, 29571, 30320, 30676, +31847, 31846, 32405, 33388, 34362, 34368, 34361, 34364, 34353, 34363, +34366, 34864, 34866, 34862, 34867, 35190, 35188, 35187, 35326, 35724, +35726, 35723, 35720, 35909, 36121, 36504, 36708, 36707, 37308, 37986, +37973, 37981, 37975, 37982, 38852, 38853, 38912, 39510, 39513, 39710, +39711, 39712, 40018, 40024, 40016, 40010, 40013, 40011, 40021, 40025, +40012, 40014, 40443, 40439, 40431, 40419, 40427, 40440, 40420, 40438, +40417, 40430, 40422, 40434, 40432, 40418, 40428, 40436, 40435, 40424, +40429, 40642, 40656, 40690, 40691, 40710, 40732, 40760, 40759, 40758, +40771, 40783, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 40817, 40816, 40814, 40815, +22227, 22221, 23374, 23661, 25901, 26349, 26350, 27411, 28767, 28769, +28765, 28768, 29219, 29915, 29925, 30677, 31032, 31159, 31158, 31850, +32407, 32649, 33389, 34371, 34872, 34871, 34869, 34891, 35732, 35733, +36510, 36511, 36512, 36509, 37310, 37309, 37314, 37995, 37992, 37993, +38629, 38726, 38723, 38727, 38855, 38885, 39518, 39637, 39769, 40035, +40039, 40038, 40034, 40030, 40032, 40450, 40446, 40455, 40451, 40454, +40453, 40448, 40449, 40457, 40447, 40445, 40452, 40608, 40734, 40774, +40820, 40821, 40822, 22228, 25902, 26040, 27416, 27417, 27415, 27418, +28770, 29222, 29354, 30680, 30681, 31033, 31849, 31851, 31990, 32410, +32408, 32411, 32409, 33248, 33249, 34374, 34375, 34376, 35193, 35194, +35196, 35195, 35327, 35736, 35737, 36517, 36516, 36515, 37998, 37997, +37999, 38001, 38003, 38729, 39026, 39263, 40040, 40046, 40045, 40459, +40461, 40464, 40463, 40466, 40465, 40609, 40693, 40713, 40775, 40824, +40827, 40826, 40825, 22302, 28774, 31855, 34876, 36274, 36518, 37315, +38004, 38008, 38006, 38005, 39520, 40052, 40051, 40049, 40053, 40468, +40467, 40694, 40714, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 40868, 28776, 28773, +31991, 34410, 34878, 34877, 34879, 35742, 35996, 36521, 36553, 38731, +39027, 39028, 39116, 39265, 39339, 39524, 39526, 39527, 39716, 40469, +40471, 40776, 25095, 27422, 29223, 34380, 36520, 38018, 38016, 38017, +39529, 39528, 39726, 40473, 29225, 34379, 35743, 38019, 40057, 40631, +30325, 39531, 40058, 40477, 28777, 28778, 40612, 40830, 40777, 40856, +30849, 37561, 35023, 22715, 24658, 31911, 23290, 9556, 9574, 9559, + 9568, 9580, 9571, 9562, 9577, 9565, 9554, 9572, 9557, 9566, + 9578, 9569, 9560, 9575, 9563, 9555, 9573, 9558, 9567, 9579, + 9570, 9561, 9576, 9564, 9553, 9552, 9581, 9582, 9584, 9583, + 9619, 57344, 57345, 57346, 57347, 57348, 57349, 57350, 57351, 57352, +57353, 57354, 57355, 57356, 57357, 57358, 57359, 57360, 57361, 57362, +57363, 57364, 57365, 57366, 57367, 57368, 57369, 57370, 57371, 57372, +57373, 57374, 57375, 57376, 57377, 57378, 57379, 29234, 29244, 29286, +29314, 29327, 29343, 29357, 29361, 29368, 29374, 29389, 29403, 29476, +29487, 29496, 29497, 29629, 29646, 29681, 29814, 29858, 29953, 29977, +29987, 30012, 30020, 30025, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 30029, 30061, +30082, 30083, 30089, 30124, 30166, 30185, 30272, 30285, 30292, 30312, +30336, 30339, 30352, 30391, 30393, 30477, 30494, 30531, 30744, 30748, +30777, 30780, 30791, 30806, 30842, 30901, 30905, 30918, 30937, 30983, +31024, 31028, 31035, 31104, 31133, 31171, 31201, 31238, 31246, 31299, +31312, 31427, 31442, 31458, 31463, 31480, 31542, 31586, 31596, 31610, +31611, 31642, 31646, 31647, 31650, 31655, 31734, 31762, 31764, 31823, +31830, 31832, 31915, 31994, 32072, 32075, 32119, 32212, 32213, 32214, +32228, 32333, 32349, 32383, 32393, 32398, 32402, 32468, 32497, 32530, +32560, 32625, 32642, 32686, 32710, 32800, 32802, 32805, 32817, 32863, +32872, 32940, 32951, 20890, 21526, 21524, 13535, 19581, 25283, 57508, +57509, 57510, 21707, 57512, 21948, 32950, 20903, 57516, 57517, 57518, +21779, 33318, 57521, 21790, 21982, 25529, 26776, 57526, 21762, 21865, +30132, 25596, 40580, 37418, 57533, 57534, 57535, 35015, 24734, 22053, +28997, 23282, 57541, 21135, 22095, 30611, 34694, 36397, 33206, 13822, +29174, 57550, 34820, 37765, 57553, 57554, 30310, 57556, 40050, 57558, +25294, 57560, 40598, 18825, 31955, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 36570, +40619, 25831, 57567, 33450, 26471, 28018, 30982, 31172, 32590, 34798, +57575, 33726, 34351, 35237, 17935, 57580, 39112, 39232, 39245, 39436, +39639, 40600, 40742, 57588, 20227, 57590, 20281, 20274, 20395, 20566, +57595, 20526, 20646, 20697, 20750, 20717, 20737, 20980, 21023, 21088, +21079, 21146, 21201, 21216, 21217, 20947, 20959, 30022, 20990, 21298, +21292, 21299, 21419, 21418, 40846, 21609, 21660, 21466, 27338, 21875, +57625, 13782, 57627, 22033, 22093, 57630, 22100, 13811, 57633, 22342, +22394, 22375, 22586, 22502, 22493, 22592, 57641, 22566, 22748, 22967, +23001, 23584, 57647, 23761, 23785, 23878, 23950, 57652, 24053, 24075, +24082, 24110, 24158, 57658, 24397, 31357, 23491, 31419, 57663, 57664, +24484, 24506, 24508, 57668, 24695, 24740, 24755, 24829, 24880, 57674, +24988, 24921, 24957, 24924, 25471, 25058, 28885, 25145, 25192, 25221, +25218, 25254, 25301, 25444, 25397, 25744, 14940, 26184, 26215, 26398, +26627, 26540, 26617, 26806, 26924, 26881, 26880, 26826, 26995, 27008, +26942, 57706, 27058, 27072, 27018, 27130, 27113, 27314, 27218, 27293, +27421, 27474, 27642, 15569, 27854, 28239, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +28089, 28484, 57723, 28634, 28801, 31180, 28980, 15820, 29046, 57730, +57731, 29205, 29264, 29319, 29484, 29362, 29410, 29442, 29512, 29480, +29519, 29553, 25989, 57744, 29789, 29800, 29982, 30035, 30074, 30369, +30412, 30500, 30507, 16485, 30803, 30931, 30936, 40318, 30895, 57760, +24898, 31145, 39994, 31188, 57765, 31277, 31294, 31305, 31453, 31450, +30147, 30215, 30210, 57774, 30311, 30319, 22048, 35431, 40727, 31519, +31634, 31651, 31695, 57784, 31740, 31810, 31825, 31837, 31856, 31870, +31878, 31875, 31916, 31943, 31938, 57796, 31962, 57798, 32077, 32090, +32245, 32295, 32366, 40597, 21107, 32797, 32866, 32867, 32870, 32859, +32934, 33027, 40577, 33224, 57815, 36768, 33270, 33306, 57819, 34673, +34729, 34700, 40606, 34753, 40476, 57826, 34774, 34805, 34831, 34840, +34861, 34882, 34885, 39989, 34926, 34986, 34976, 25245, 35139, 35149, +29042, 34910, 57843, 33533, 17591, 33488, 33669, 40194, 40809, 33824, +57851, 34010, 33965, 17659, 34123, 57856, 34306, 34320, 25553, 35209, +35210, 35220, 40005, 35260, 35454, 35401, 35596, 35651, 35713, 35660, +57871, 36013, 36075, 36087, 36108, 36226, 36262, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 36308, 36392, 36431, 36471, 36469, 36519, 36633, 57885, 36700, +40260, 37060, 37201, 57890, 37212, 37209, 37223, 37244, 37262, 37307, +40616, 36950, 36940, 37374, 37474, 37566, 37739, 37742, 37818, 37927, +38295, 38311, 57909, 38456, 57911, 38531, 38550, 38529, 38589, 38659, +38689, 38705, 38751, 38815, 38836, 38840, 38842, 38846, 38856, 40639, +38943, 38958, 40869, 38983, 38987, 39014, 39020, 39092, 40794, 39132, +39142, 39234, 39225, 39227, 40787, 39242, 40773, 19326, 39386, 31432, +39610, 39613, 40706, 39722, 57951, 39725, 39650, 39682, 39679, 19463, +39689, 19460, 19515, 39823, 39837, 39856, 39948, 39957, 39946, 39935, +39982, 33000, 33001, 33004, 33038, 27705, 20074, 38465, 22770, 31074, +26658, 57978, 57979, 33031, 22487, 17642, 25653, 34100, 16607, 57986, +26906, 39938, 30129, 33747, 29041, 27147, 57993, 27258, 39668, 57996, +57997, 30649, 25904, 28054, 22071, 26405, 27179, 32093, 36961, 20120, +31910, 31545, 58009, 22901, 14023, 28799, 58013, 28299, 58015, 58016, +38749, 37584, 22356, 58020, 16089, 58022, 58023, 24985, 29792, 28991, +31022, 23190, 37704, 26254, 20477, 37697, 13908, 23925, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 28702, 25979, 28813, 24269, 58039, 24743, 31408, 24419, +58043, 29687, 58045, 29800, 30132, 58048, 39785, 189, 8531, 8532, + 188, 190, 8533, 8534, 8535, 8536, 8537, 8538, 34450, 34464, +34477, 34482, 34725, 34737, 8539, 8540, 8541, 8542, 34778, 34895, +34912, 34951, 34959, 34960, 35046, 35071, 35072, 35108, 35143, 35156, +35173, 35200, 35217, 35356, 35369, 35371, 35384, 35389, 8978, 35472, +35476, 35484, 35497, 35503, 35508, 35562, 35615, 8240, 35647, 35661, +35678, 35682, 35689, 35739, 35921, 35995, 35999, 36052, 36054, 33042, +33073, 33078, 33119, 33133, 33149, 33171, 33194, 33208, 33217, 33321, +33325, 33326, 33342, 33378, 33386, 33416 +}; + +static const uchar ucs_to_big5[][2] = +{ + {'\x00','\x00'},{'\x00','\x01'},{'\x00','\x02'},{'\x00','\x03'},{'\x00','\x04'}, + {'\x00','\x05'},{'\x00','\x06'},{'\x00','\x07'},{'\x00','\x08'},{'\x00','\x09'}, + {'\x00','\x0a'},{'\x00','\x0b'},{'\x00','\x0c'},{'\x00','\x0d'},{'\x00','\x0e'}, + {'\x00','\x0f'},{'\x00','\x10'},{'\x00','\x11'},{'\x00','\x12'},{'\x00','\x13'}, + {'\x00','\x14'},{'\x00','\x15'},{'\x00','\x16'},{'\x00','\x17'},{'\x00','\x18'}, + {'\x00','\x19'},{'\x00','\x1a'},{'\x00','\x1b'},{'\x00','\x1c'},{'\x00','\x1d'}, + {'\x00','\x1e'},{'\x00','\x1f'},{'\x00','\x20'},{'\x00','\x21'},{'\x00','\x22'}, + {'\x00','\x23'},{'\x00','\x24'},{'\x00','\x25'},{'\x00','\x26'},{'\x00','\x27'}, + {'\x00','\x28'},{'\x00','\x29'},{'\x00','\x2a'},{'\x00','\x2b'},{'\x00','\x2c'}, + {'\x00','\x2d'},{'\x00','\x2e'},{'\x00','\x2f'},{'\x00','\x30'},{'\x00','\x31'}, + {'\x00','\x32'},{'\x00','\x33'},{'\x00','\x34'},{'\x00','\x35'},{'\x00','\x36'}, + {'\x00','\x37'},{'\x00','\x38'},{'\x00','\x39'},{'\x00','\x3a'},{'\x00','\x3b'}, + {'\x00','\x3c'},{'\x00','\x3d'},{'\x00','\x3e'},{'\x00','\x3f'},{'\x00','\x40'}, + {'\x00','\x41'},{'\x00','\x42'},{'\x00','\x43'},{'\x00','\x44'},{'\x00','\x45'}, + {'\x00','\x46'},{'\x00','\x47'},{'\x00','\x48'},{'\x00','\x49'},{'\x00','\x4a'}, + {'\x00','\x4b'},{'\x00','\x4c'},{'\x00','\x4d'},{'\x00','\x4e'},{'\x00','\x4f'}, + {'\x00','\x50'},{'\x00','\x51'},{'\x00','\x52'},{'\x00','\x53'},{'\x00','\x54'}, + {'\x00','\x55'},{'\x00','\x56'},{'\x00','\x57'},{'\x00','\x58'},{'\x00','\x59'}, + {'\x00','\x5a'},{'\x00','\x5b'},{'\x00','\x5c'},{'\x00','\x5d'},{'\x00','\x5e'}, + {'\x00','\x5f'},{'\x00','\x60'},{'\x00','\x61'},{'\x00','\x62'},{'\x00','\x63'}, + {'\x00','\x64'},{'\x00','\x65'},{'\x00','\x66'},{'\x00','\x67'},{'\x00','\x68'}, + {'\x00','\x69'},{'\x00','\x6a'},{'\x00','\x6b'},{'\x00','\x6c'},{'\x00','\x6d'}, + {'\x00','\x6e'},{'\x00','\x6f'},{'\x00','\x70'},{'\x00','\x71'},{'\x00','\x72'}, + {'\x00','\x73'},{'\x00','\x74'},{'\x00','\x75'},{'\x00','\x76'},{'\x00','\x77'}, + {'\x00','\x78'},{'\x00','\x79'},{'\x00','\x7a'},{'\x00','\x7b'},{'\x00','\x7c'}, + {'\x00','\x7d'},{'\x00','\x7e'},{'\x00','\x7f'},{'\x00','\x80'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa0','\xdf'},{'\xa2','\x46'},{'\xa2','\x47'},{'\xa0','\xfc'}, + {'\xa2','\x44'},{'\x7c','\x20'},{'\xa1','\xb1'},{'\xc6','\xd8'},{'\x63','\x20'}, + {'\xa0','\xde'},{'\x00','\x00'},{'\x00','\x00'},{'\x2d','\x20'},{'\x97','\xfb'}, + {'\xa1','\xc2'},{'\xa2','\x58'},{'\xa1','\xd3'},{'\x32','\x20'},{'\x33','\x20'}, + {'\xa1','\xac'},{'\xa3','\x67'},{'\x91','\xf8'},{'\xa1','\x50'},{'\xa0','\xfb'}, + {'\x31','\x20'},{'\xa0','\xee'},{'\x00','\x00'},{'\xfe','\xb3'},{'\xfe','\xb0'}, + {'\xfe','\xb4'},{'\xa0','\xef'},{'\xa0','\xa7'},{'\xa0','\xac'},{'\xa0','\xf6'}, + {'\xa0','\xbe'},{'\xa0','\xb6'},{'\xa0','\xd6'},{'\xa0','\xbb'},{'\xa0','\xbc'}, + {'\xa0','\xa8'},{'\xa0','\xd7'},{'\xa0','\xf7'},{'\xa0','\xb7'},{'\xa0','\xa9'}, + {'\xa0','\xad'},{'\xa0','\xf8'},{'\xa0','\xb8'},{'\xa0','\xda'},{'\xa0','\xbd'}, + {'\xa0','\xaa'},{'\xa0','\xae'},{'\xa0','\xf9'},{'\xa0','\xbf'},{'\xa0','\xb9'}, + {'\xa1','\xd1'},{'\xa0','\xd9'},{'\xa0','\xab'},{'\xa0','\xaf'},{'\xa0','\xfa'}, + {'\xa0','\xba'},{'\x59','\x20'},{'\xa0','\xdc'},{'\xa0','\xdd'},{'\xa0','\xe0'}, + {'\xa0','\xc0'},{'\xa0','\xf0'},{'\xa0','\xce'},{'\xa0','\xc6'},{'\xa0','\xe6'}, + {'\xa0','\xcb'},{'\xa0','\xcc'},{'\xa0','\xe1'},{'\xa0','\xc1'},{'\xa0','\xf1'}, + {'\xa0','\xc7'},{'\xa0','\xe2'},{'\xa0','\xc2'},{'\xa0','\xf2'},{'\xa0','\xc8'}, + {'\xa0','\xea'},{'\xa0','\xcd'},{'\xa0','\xe3'},{'\xa0','\xc3'},{'\xa0','\xf3'}, + {'\xa0','\xcf'},{'\xa0','\xc9'},{'\xa1','\xd2'},{'\xa0','\xe9'},{'\xa0','\xe4'}, + {'\xa0','\xc4'},{'\xa0','\xf4'},{'\xa0','\xca'},{'\x79','\x20'},{'\xa0','\xec'}, + {'\xa0','\xed'},{'\x00','\x00'},{'\xa0','\xb0'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa0','\xb1'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa0','\xd1'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa0','\xb2'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9b','\xd5'},{'\x00','\x00'},{'\x00','\x00'},{'\xa0','\xb3'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xe5'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa0','\xb4'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa0','\xfe'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa0','\xd0'},{'\x00','\x00'},{'\xa0','\xd2'}, + {'\x00','\x00'},{'\xa0','\xd3'},{'\x00','\x00'},{'\xa0','\xd4'},{'\x00','\x00'}, + {'\xa0','\xb5'},{'\x00','\x00'},{'\xa0','\xc5'},{'\x00','\x00'},{'\xa0','\xd5'}, + {'\x00','\x00'},{'\xa0','\xe5'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xcb'},{'\x9b','\xe6'}, + {'\x00','\x00'},{'\x9b','\xcc'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x9b','\xcf'},{'\x9b','\xd0'},{'\x9b','\xc8'},{'\x9b','\xd1'}, + {'\x9b','\xce'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xd2'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xc7'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xe0'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xd7'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xe1'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xd9'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xe2'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9b','\xcd'},{'\x00','\x00'},{'\x9b','\xca'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xda'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x9b','\xdc'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xdb'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc6','\xd9'},{'\xa3','\xbe'},{'\x00','\x00'},{'\xa3','\xbc'},{'\xa3','\xbd'}, + {'\xa3','\xbf'},{'\x00','\x00'},{'\xa1','\xc5'},{'\x00','\x00'},{'\x9b','\xe9'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa3','\xbb'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa3','\x44'},{'\xa3','\x45'}, + {'\xa3','\x46'},{'\xa3','\x47'},{'\xa3','\x48'},{'\xa3','\x49'},{'\xa3','\x4a'}, + {'\xa3','\x4b'},{'\xa3','\x4c'},{'\xa3','\x4d'},{'\xa3','\x4e'},{'\xa3','\x4f'}, + {'\xa3','\x50'},{'\xa3','\x51'},{'\xa3','\x52'},{'\xa3','\x53'},{'\xa3','\x54'}, + {'\x00','\x00'},{'\xa3','\x55'},{'\xa3','\x56'},{'\xa3','\x57'},{'\xa3','\x58'}, + {'\xa3','\x59'},{'\xa3','\x5a'},{'\xa3','\x5b'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa3','\x5c'},{'\xa3','\x5d'},{'\xa3','\x5e'},{'\xa3','\x5f'},{'\xa3','\x60'}, + {'\xa3','\x61'},{'\xa3','\x62'},{'\xa3','\x63'},{'\xa3','\x64'},{'\xa3','\x65'}, + {'\xa3','\x66'},{'\xa3','\x67'},{'\xa3','\x68'},{'\xa3','\x69'},{'\xa3','\x6a'}, + {'\xa3','\x6b'},{'\xa3','\x6c'},{'\x00','\x00'},{'\xa3','\x6d'},{'\xa3','\x6e'}, + {'\xa3','\x6f'},{'\xa3','\x70'},{'\xa3','\x71'},{'\xa3','\x72'},{'\xa3','\x73'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc7','\xf9'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc7','\xf3'},{'\xc7','\xf4'},{'\xc7','\xf5'},{'\xc7','\xf6'},{'\xc7','\xf7'}, + {'\xc7','\xf8'},{'\xc7','\xfa'},{'\xc7','\xfb'},{'\xc7','\xfc'},{'\xc7','\xfd'}, + {'\xc7','\xfe'},{'\xc8','\x40'},{'\xc8','\x41'},{'\xc8','\x42'},{'\xc8','\x43'}, + {'\xc8','\x44'},{'\xc8','\x45'},{'\xc8','\x46'},{'\xc8','\x47'},{'\xc8','\x48'}, + {'\xc8','\x49'},{'\xc8','\x4a'},{'\xc8','\x4b'},{'\xc8','\x4c'},{'\xc8','\x4d'}, + {'\xc8','\x4e'},{'\xc8','\x4f'},{'\xc8','\x50'},{'\xc8','\x51'},{'\xc8','\x52'}, + {'\xc8','\x53'},{'\xc8','\x54'},{'\xc8','\x55'},{'\xc8','\x56'},{'\xc8','\x57'}, + {'\xc8','\x58'},{'\xc8','\x59'},{'\xc8','\x5a'},{'\xc8','\x5c'},{'\xc8','\x5d'}, + {'\xc8','\x5e'},{'\xc8','\x5f'},{'\xc8','\x60'},{'\xc8','\x61'},{'\xc8','\x62'}, + {'\xc8','\x63'},{'\xc8','\x64'},{'\xc8','\x65'},{'\xc8','\x66'},{'\xc8','\x67'}, + {'\xc8','\x68'},{'\xc8','\x69'},{'\xc8','\x6a'},{'\xc8','\x6b'},{'\xc8','\x6c'}, + {'\xc8','\x6d'},{'\xc8','\x6e'},{'\xc8','\x6f'},{'\xc8','\x70'},{'\xc8','\x71'}, + {'\xc8','\x72'},{'\xc8','\x73'},{'\xc8','\x74'},{'\xc8','\x75'},{'\x00','\x00'}, + {'\xc8','\x5b'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xd6'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xd3'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9b','\xd4'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa0','\xdb'},{'\xa0','\xeb'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9f','\xec'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\x56'},{'\xa1','\x58'},{'\xa2','\x77'},{'\xa1','\xfc'}, + {'\x00','\x00'},{'\xa1','\xa5'},{'\xa1','\xa6'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa1','\xa7'},{'\xa1','\xa8'},{'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xcf'}, + {'\x91','\xde'},{'\xa1','\x45'},{'\x00','\x00'},{'\xa3','\xbb'},{'\xa1','\x4c'}, + {'\xa1','\x4b'},{'\xa1','\x45'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfe','\xe2'},{'\x00','\x00'},{'\xa1','\xac'},{'\xa1','\xb2'},{'\x00','\x00'}, + {'\xa1','\xab'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\xb0'},{'\x91','\xf7'},{'\x00','\x00'},{'\xa1','\xc3'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa3','\xe1'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa2','\x4a'},{'\x00','\x00'},{'\xa1','\xc1'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa2','\x4b'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9d','\xcf'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\xe2'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x9d','\xc9'},{'\x97','\xfc'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x96','\x52'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9d','\xc8'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xfe','\xb1'},{'\xfe','\xb2'},{'\xfe','\xb5'},{'\xfe','\xb6'}, + {'\xfe','\xb7'},{'\xfe','\xb8'},{'\xfe','\xb9'},{'\xfe','\xba'},{'\xfe','\xc1'}, + {'\xfe','\xc2'},{'\xfe','\xc3'},{'\xfe','\xc4'},{'\x00','\x00'},{'\xa2','\xb9'}, + {'\xa2','\xba'},{'\xa2','\xbb'},{'\xa2','\xbc'},{'\xa2','\xbd'},{'\xa2','\xbe'}, + {'\xa2','\xbf'},{'\xa2','\xc0'},{'\xa2','\xc1'},{'\xa2','\xc2'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc6','\xb5'},{'\xc6','\xb6'},{'\xc6','\xb7'},{'\xc6','\xb8'},{'\xc6','\xb9'}, + {'\xc6','\xba'},{'\xc6','\xbb'},{'\xc6','\xbc'},{'\xc6','\xbd'},{'\xc6','\xbe'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xf6'},{'\xa1','\xf4'},{'\xa1','\xf7'}, + {'\xa1','\xf5'},{'\x91','\xfb'},{'\x91','\xf6'},{'\xa1','\xf8'},{'\xa1','\xf9'}, + {'\xa1','\xfb'},{'\xa1','\xfa'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x91','\xfa'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x9d','\xfd'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc8','\x77'},{'\xc8','\x78'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x96','\x53'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x99','\x65'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\x4a'},{'\xc8','\x76'}, + {'\x9d','\x49'},{'\x9d','\x4c'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x91','\xf9'}, + {'\x00','\x00'},{'\xa0','\x79'},{'\x98','\xf9'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\xbe'},{'\x91','\x6b'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x91','\x5f'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa3','\x53'}, + {'\x00','\x00'},{'\xa3','\x55'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa2','\x41'},{'\xa2','\x42'},{'\x00','\x00'},{'\xa2','\x58'},{'\x00','\x00'}, + {'\xa1','\xd4'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xdb'}, + {'\xa1','\xe8'},{'\xa1','\xe7'},{'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xfd'}, + {'\x00','\x00'},{'\xa1','\xfc'},{'\x00','\x00'},{'\xa3','\x4e'},{'\xa2','\xe4'}, + {'\xa1','\xe4'},{'\xa1','\xe5'},{'\xa1','\xec'},{'\x9f','\x4c'},{'\x00','\x00'}, + {'\xa1','\xed'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\xef'},{'\xa1','\xee'},{'\xa1','\x47'},{'\x9f','\x46'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\xdc'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa1','\xda'},{'\xa1','\xdd'},{'\x00','\x00'},{'\xa1','\xdd'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\xd8'},{'\xa1','\xd9'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9a','\xe0'}, + {'\x9a','\xa6'},{'\x00','\x00'},{'\x00','\x00'},{'\x9c','\x72'},{'\x9c','\xaa'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xf2'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xf3'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xe6'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa1','\xe9'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x91','\xfc'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa1','\x5b'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xfe','\xd9'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa3','\xc0'},{'\xa3','\xc1'},{'\xa3','\xc2'},{'\xa3','\xc3'}, + {'\xa3','\xc4'},{'\xa3','\xc5'},{'\xa3','\xc6'},{'\xa3','\xc7'},{'\xa3','\xc8'}, + {'\xa3','\xc9'},{'\xa3','\xca'},{'\xa3','\xcb'},{'\xa3','\xcc'},{'\xa3','\xcd'}, + {'\xa3','\xce'},{'\xa3','\xcf'},{'\xa3','\xd0'},{'\xa3','\xd1'},{'\xa3','\xd2'}, + {'\xa3','\xd3'},{'\xa3','\xd4'},{'\xa3','\xd5'},{'\xa3','\xd6'},{'\xa3','\xd7'}, + {'\xa3','\xd8'},{'\xa3','\xd9'},{'\xa3','\xda'},{'\xa3','\xdb'},{'\xa3','\xdc'}, + {'\xa3','\xdd'},{'\xa3','\xde'},{'\xa3','\xdf'},{'\x00','\x00'},{'\xa3','\xe0'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xa1'},{'\xc6','\xa2'},{'\xc6','\xa3'}, + {'\xc6','\xa4'},{'\xc6','\xa5'},{'\xc6','\xa6'},{'\xc6','\xa7'},{'\xc6','\xa8'}, + {'\xc6','\xa9'},{'\xc6','\xaa'},{'\x97','\x4b'},{'\x97','\x4c'},{'\x97','\x4d'}, + {'\x97','\x4e'},{'\x97','\x4f'},{'\x97','\x50'},{'\x97','\x51'},{'\x97','\x52'}, + {'\x97','\x53'},{'\x97','\x54'},{'\xc6','\xab'},{'\xc6','\xac'},{'\xc6','\xad'}, + {'\xc6','\xae'},{'\xc6','\xaf'},{'\xc6','\xb0'},{'\xc6','\xb1'},{'\xc6','\xb2'}, + {'\xc6','\xb3'},{'\xc6','\xb4'},{'\x99','\x4b'},{'\x99','\x4c'},{'\x99','\x4d'}, + {'\x99','\x4e'},{'\x99','\x4f'},{'\x99','\x50'},{'\x99','\x51'},{'\x99','\x52'}, + {'\x99','\x53'},{'\x99','\x54'},{'\x9a','\x41'},{'\x9a','\x42'},{'\x9a','\x43'}, + {'\x9a','\x44'},{'\x9a','\x45'},{'\x9a','\x46'},{'\x9a','\x47'},{'\x9a','\x48'}, + {'\x9a','\x49'},{'\x9a','\x4a'},{'\x9a','\x4b'},{'\x9a','\x4c'},{'\x9a','\x4d'}, + {'\x9a','\x4e'},{'\x9a','\x4f'},{'\x9a','\x50'},{'\x9a','\x51'},{'\x9a','\x52'}, + {'\x9a','\x53'},{'\x9a','\x54'},{'\x99','\xe1'},{'\x99','\xe2'},{'\x99','\xe3'}, + {'\x99','\xe4'},{'\x99','\xe5'},{'\x99','\xe6'},{'\x99','\xe7'},{'\x99','\xe8'}, + {'\x99','\xe9'},{'\x99','\xea'},{'\x99','\xeb'},{'\x99','\xec'},{'\x99','\xed'}, + {'\x99','\xee'},{'\x99','\xef'},{'\x99','\xf0'},{'\x99','\xf1'},{'\x99','\xf2'}, + {'\x99','\xf3'},{'\x99','\xf4'},{'\x99','\xf5'},{'\x99','\xf6'},{'\x99','\xf7'}, + {'\x99','\xf8'},{'\x99','\xf9'},{'\x99','\xfa'},{'\x97','\xc7'},{'\x97','\xc8'}, + {'\x97','\xc9'},{'\x97','\xca'},{'\x97','\xcb'},{'\x97','\xcc'},{'\x97','\xcd'}, + {'\x97','\xce'},{'\x97','\xcf'},{'\x97','\xd0'},{'\x97','\xd1'},{'\x97','\xd2'}, + {'\x97','\xd3'},{'\x97','\xd4'},{'\x97','\xd5'},{'\x97','\xd6'},{'\x97','\xd7'}, + {'\x97','\xd8'},{'\x97','\xd9'},{'\x97','\xda'},{'\x97','\xdb'},{'\x97','\xdc'}, + {'\x97','\xdd'},{'\x97','\xde'},{'\x97','\xdf'},{'\x97','\xe0'},{'\x97','\xe1'}, + {'\x97','\xe2'},{'\x97','\xe3'},{'\x97','\xe4'},{'\x97','\xe5'},{'\x97','\xe6'}, + {'\x97','\xe7'},{'\x97','\xe8'},{'\x97','\xe9'},{'\x97','\xea'},{'\x97','\xeb'}, + {'\x97','\xec'},{'\x97','\xed'},{'\x97','\xee'},{'\x97','\xef'},{'\x97','\xf0'}, + {'\x97','\xf1'},{'\x97','\xf2'},{'\x97','\xf3'},{'\x97','\xf4'},{'\x97','\xf5'}, + {'\x97','\xf6'},{'\x97','\xf7'},{'\x97','\xf8'},{'\x97','\xf9'},{'\x97','\xfa'}, + {'\x97','\x40'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa2','\x77'},{'\x9d','\x7d'},{'\xa2','\x78'}, + {'\x9d','\x7e'},{'\xa1','\x4c'},{'\xa1','\x4c'},{'\xa1','\x4a'},{'\xa1','\x4a'}, + {'\xa1','\x4b'},{'\xa1','\x4b'},{'\xa1','\x55'},{'\xa1','\x55'},{'\xa2','\x7a'}, + {'\xa2','\x7a'},{'\xa2','\x7a'},{'\xa2','\x7a'},{'\xa2','\x7b'},{'\xa2','\x7b'}, + {'\xa2','\x7b'},{'\xa2','\x7b'},{'\xa2','\x7c'},{'\xa2','\x7c'},{'\xa2','\x7c'}, + {'\xa2','\x7c'},{'\xa2','\x7d'},{'\xa2','\x7d'},{'\xa2','\x7d'},{'\xa2','\x7d'}, + {'\xa2','\x75'},{'\xa2','\x75'},{'\xa2','\x75'},{'\xa2','\x75'},{'\xa2','\x75'}, + {'\xa2','\x75'},{'\xa2','\x75'},{'\xa2','\x75'},{'\xa2','\x74'},{'\xa2','\x74'}, + {'\xa2','\x74'},{'\xa2','\x74'},{'\xa2','\x74'},{'\xa2','\x74'},{'\xa2','\x74'}, + {'\xa2','\x74'},{'\xa2','\x73'},{'\xa2','\x73'},{'\xa2','\x73'},{'\xa2','\x73'}, + {'\xa2','\x73'},{'\xa2','\x73'},{'\xa2','\x73'},{'\xa2','\x73'},{'\xa2','\x72'}, + {'\xa2','\x72'},{'\xa2','\x72'},{'\xa2','\x72'},{'\xa2','\x72'},{'\xa2','\x72'}, + {'\xa2','\x72'},{'\xa2','\x72'},{'\xa2','\x71'},{'\xa2','\x71'},{'\xa2','\x71'}, + {'\xa2','\x71'},{'\xa2','\x71'},{'\xa2','\x71'},{'\xa2','\x71'},{'\xa2','\x71'}, + {'\xa2','\x71'},{'\xa2','\x71'},{'\xa2','\x71'},{'\xa2','\x71'},{'\xa2','\x71'}, + {'\xa2','\x71'},{'\xa2','\x71'},{'\xa2','\x71'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x91','\xf0'},{'\x00','\x00'},{'\xf9','\xf9'},{'\xf9','\xf8'},{'\xf9','\xe6'}, + {'\xf9','\xef'},{'\xf9','\xdd'},{'\xf9','\xe8'},{'\xf9','\xf1'},{'\xf9','\xdf'}, + {'\xf9','\xec'},{'\xf9','\xf5'},{'\xf9','\xe3'},{'\xf9','\xee'},{'\xf9','\xf7'}, + {'\xf9','\xe5'},{'\xf9','\xe9'},{'\xf9','\xf2'},{'\xf9','\xe0'},{'\xf9','\xeb'}, + {'\xf9','\xf4'},{'\xf9','\xe2'},{'\xf9','\xe7'},{'\xf9','\xf0'},{'\xf9','\xde'}, + {'\xf9','\xed'},{'\xf9','\xf6'},{'\xf9','\xe4'},{'\xf9','\xea'},{'\xf9','\xf3'}, + {'\xf9','\xe1'},{'\xa2','\x7e'},{'\xa2','\xa1'},{'\xa2','\xa3'},{'\xa2','\xa2'}, + {'\xa2','\xac'},{'\xa2','\xad'},{'\xa2','\xae'},{'\xa1','\x5a'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa2','\x62'},{'\xa2','\x63'},{'\xa2','\x64'},{'\xa2','\x65'}, + {'\xa2','\x66'},{'\xa2','\x67'},{'\xa2','\x68'},{'\xa2','\x69'},{'\xa2','\x70'}, + {'\xa2','\x6f'},{'\xa2','\x6e'},{'\xa2','\x6d'},{'\xa2','\x6c'},{'\xa2','\x6b'}, + {'\xa2','\x6a'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xf9','\xfe'}, + {'\xa2','\x76'},{'\xa2','\x79'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xbd'},{'\xa1','\xbc'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa1','\xb6'},{'\xa1','\xb5'},{'\x00','\x00'},{'\x00','\x00'},{'\x91','\xf4'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa1','\xbf'},{'\xa1','\xbe'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x91','\xf5'},{'\x00','\x00'}, + {'\xa1','\xbb'},{'\xa1','\xba'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa1','\xb3'},{'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xb7'},{'\xa1','\xb4'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x91','\xf1'},{'\x91','\xf2'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa2','\xa8'},{'\xa2','\xa9'}, + {'\xa2','\xab'},{'\xa2','\xaa'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\xb3'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\xba'}, + {'\x9d','\xbc'},{'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xb9'},{'\xa1','\xb8'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xf3'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9d','\x40'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9d','\xed'},{'\x9c','\xd1'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9d','\x4f'},{'\x9d','\x4e'},{'\x00','\x00'},{'\x9d','\x4d'},{'\x9d','\x50'}, + {'\x9d','\xd5'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9f','\x55'},{'\x9f','\x56'},{'\x9f','\x5d'},{'\x9f','\x5b'},{'\x9f','\x58'}, + {'\x9f','\x59'},{'\x9f','\x5a'},{'\x9f','\x5c'},{'\x9f','\x57'},{'\x00','\x00'}, + {'\x9d','\x5e'},{'\x9d','\x5d'},{'\x98','\xfc'},{'\x9d','\xb8'},{'\x9d','\x57'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xf0'},{'\xa1','\xf2'},{'\xa1','\xf1'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\xd8'}, + {'\x9d','\xdd'},{'\x9d','\xdb'},{'\x9d','\xda'},{'\x9d','\xd7'},{'\x9d','\xde'}, + {'\x9d','\xdc'},{'\x9d','\xd9'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\x66'}, + {'\x00','\x00'},{'\x9d','\x65'},{'\xa2','\xea'},{'\x00','\x00'},{'\xa1','\xad'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x9d','\x6c'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9d','\xc0'},{'\x9d','\x6b'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\x55'},{'\x00','\x00'}, + {'\x9d','\x54'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9d','\x5c'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9d','\x5b'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc6','\xe6'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\x77'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x98','\x41'},{'\x98','\x42'},{'\x98','\x43'}, + {'\x98','\x44'},{'\x98','\x45'},{'\x98','\x46'},{'\x98','\x47'},{'\x98','\x48'}, + {'\x98','\x49'},{'\x98','\x4a'},{'\xc6','\xa1'},{'\xc6','\xa2'},{'\xc6','\xa3'}, + {'\xc6','\xa4'},{'\xc6','\xa5'},{'\xc6','\xa6'},{'\xc6','\xa7'},{'\xc6','\xa8'}, + {'\xc6','\xa9'},{'\xc6','\xaa'},{'\x98','\x41'},{'\x98','\x42'},{'\x98','\x43'}, + {'\x98','\x44'},{'\x98','\x45'},{'\x98','\x46'},{'\x98','\x47'},{'\x98','\x48'}, + {'\x98','\x49'},{'\x98','\x4a'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x91','\xed'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x9c','\xce'},{'\x00','\x00'},{'\x00','\x00'},{'\x9c','\xd5'}, + {'\x00','\x00'},{'\x9c','\xd4'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9c','\xdb'},{'\x00','\x00'},{'\x91','\xdb'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x91','\xc9'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9c','\xf7'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xbf'}, + {'\xc6','\xc0'},{'\x00','\x00'},{'\xc6','\xc1'},{'\x00','\x00'},{'\xc6','\xc2'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xc3'}, + {'\xc6','\xc4'},{'\xc6','\xc5'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xc6','\xc6'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xc7'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xc8'},{'\x00','\x00'},{'\xc6','\xc9'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xc6','\xca'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xc6','\xcb'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xcc'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xcd'},{'\xc6','\xce'}, + {'\xc6','\xcf'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xd0'}, + {'\xc6','\xd1'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xd2'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xd3'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc6','\xd4'},{'\xc6','\xd5'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xd6'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xd7'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa1','\x40'},{'\xa1','\x42'}, + {'\xa1','\x43'},{'\xa1','\xb2'},{'\x00','\x00'},{'\xc6','\xe0'},{'\xc6','\xe1'}, + {'\xc6','\xe2'},{'\xa1','\x71'},{'\xa1','\x72'},{'\xa1','\x6d'},{'\xa1','\x6e'}, + {'\xa1','\x75'},{'\xa1','\x76'},{'\xa1','\x79'},{'\xa1','\x7a'},{'\xa1','\x69'}, + {'\xa1','\x6a'},{'\xa2','\x45'},{'\x96','\x5d'},{'\xa1','\x65'},{'\xa1','\x66'}, + {'\x9d','\x51'},{'\x9d','\x52'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\xe3'},{'\xa1','\xa9'},{'\xa1','\xaa'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa2','\xc3'},{'\xa2','\xc4'},{'\xa2','\xc5'},{'\xa2','\xc6'}, + {'\xa2','\xc7'},{'\xa2','\xc8'},{'\xa2','\xc9'},{'\xa2','\xca'},{'\xa2','\xcb'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\xca'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa2','\xcc'}, + {'\xa2','\xcd'},{'\xa2','\xce'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xe7'},{'\xc6','\xe8'}, + {'\xc6','\xe9'},{'\xc6','\xea'},{'\xc6','\xeb'},{'\xc6','\xec'},{'\xc6','\xed'}, + {'\xc6','\xee'},{'\xc6','\xef'},{'\xc6','\xf0'},{'\xc6','\xf1'},{'\xc6','\xf2'}, + {'\xc6','\xf3'},{'\xc6','\xf4'},{'\xc6','\xf5'},{'\xc6','\xf6'},{'\xc6','\xf7'}, + {'\xc6','\xf8'},{'\xc6','\xf9'},{'\xc6','\xfa'},{'\xc6','\xfb'},{'\xc6','\xfc'}, + {'\xc6','\xfd'},{'\xc6','\xfe'},{'\xc7','\x40'},{'\xc7','\x41'},{'\xc7','\x42'}, + {'\xc7','\x43'},{'\xc7','\x44'},{'\xc7','\x45'},{'\xc7','\x46'},{'\xc7','\x47'}, + {'\xc7','\x48'},{'\xc7','\x49'},{'\xc7','\x4a'},{'\xc7','\x4b'},{'\xc7','\x4c'}, + {'\xc7','\x4d'},{'\xc7','\x4e'},{'\xc7','\x4f'},{'\xc7','\x50'},{'\xc7','\x51'}, + {'\xc7','\x52'},{'\xc7','\x53'},{'\xc7','\x54'},{'\xc7','\x55'},{'\xc7','\x56'}, + {'\xc7','\x57'},{'\xc7','\x58'},{'\xc7','\x59'},{'\xc7','\x5a'},{'\xc7','\x5b'}, + {'\xc7','\x5c'},{'\xc7','\x5d'},{'\xc7','\x5e'},{'\xc7','\x5f'},{'\xc7','\x60'}, + {'\xc7','\x61'},{'\xc7','\x62'},{'\xc7','\x63'},{'\xc7','\x64'},{'\xc7','\x65'}, + {'\xc7','\x66'},{'\xc7','\x67'},{'\xc7','\x68'},{'\xc7','\x69'},{'\xc7','\x6a'}, + {'\xc7','\x6b'},{'\xc7','\x6c'},{'\xc7','\x6d'},{'\xc7','\x6e'},{'\xc7','\x6f'}, + {'\xc7','\x70'},{'\xc7','\x71'},{'\xc7','\x72'},{'\xc7','\x73'},{'\xc7','\x74'}, + {'\xc7','\x75'},{'\xc7','\x76'},{'\xc7','\x77'},{'\xc7','\x78'},{'\xc7','\x79'}, + {'\xc7','\x7a'},{'\xc8','\xb3'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc8','\xb1'},{'\xc8','\xb2'}, + {'\xc6','\xdc'},{'\xc6','\xdd'},{'\x00','\x00'},{'\x00','\x00'},{'\xc7','\x7b'}, + {'\xc7','\x7c'},{'\xc7','\x7d'},{'\xc7','\x7e'},{'\xc7','\xa1'},{'\xc7','\xa2'}, + {'\xc7','\xa3'},{'\xc7','\xa4'},{'\xc7','\xa5'},{'\xc7','\xa6'},{'\xc7','\xa7'}, + {'\xc7','\xa8'},{'\xc7','\xa9'},{'\xc7','\xaa'},{'\xc7','\xab'},{'\xc7','\xac'}, + {'\xc7','\xad'},{'\xc7','\xae'},{'\xc7','\xaf'},{'\xc7','\xb0'},{'\xc7','\xb1'}, + {'\xc7','\xb2'},{'\xc7','\xb3'},{'\xc7','\xb4'},{'\xc7','\xb5'},{'\xc7','\xb6'}, + {'\xc7','\xb7'},{'\xc7','\xb8'},{'\xc7','\xb9'},{'\xc7','\xba'},{'\xc7','\xbb'}, + {'\xc7','\xbc'},{'\xc7','\xbd'},{'\xc7','\xbe'},{'\xc7','\xbf'},{'\xc7','\xc0'}, + {'\xc7','\xc1'},{'\xc7','\xc2'},{'\xc7','\xc3'},{'\xc7','\xc4'},{'\xc7','\xc5'}, + {'\xc7','\xc6'},{'\xc7','\xc7'},{'\xc7','\xc8'},{'\xc7','\xc9'},{'\xc7','\xca'}, + {'\xc7','\xcb'},{'\xc7','\xcc'},{'\xc7','\xcd'},{'\xc7','\xce'},{'\xc7','\xcf'}, + {'\xc7','\xd0'},{'\xc7','\xd1'},{'\xc7','\xd2'},{'\xc7','\xd3'},{'\xc7','\xd4'}, + {'\xc7','\xd5'},{'\xc7','\xd6'},{'\xc7','\xd7'},{'\xc7','\xd8'},{'\xc7','\xd9'}, + {'\xc7','\xda'},{'\xc7','\xdb'},{'\xc7','\xdc'},{'\xc7','\xdd'},{'\xc7','\xde'}, + {'\xc7','\xdf'},{'\xc7','\xe0'},{'\xc7','\xe1'},{'\xc7','\xe2'},{'\xc7','\xe3'}, + {'\xc7','\xe4'},{'\xc7','\xe5'},{'\xc7','\xe6'},{'\xc7','\xe7'},{'\xc7','\xe8'}, + {'\xc7','\xe9'},{'\xc7','\xea'},{'\xc7','\xeb'},{'\xc7','\xec'},{'\xc7','\xed'}, + {'\xc7','\xee'},{'\xc7','\xef'},{'\xc7','\xf0'},{'\xc7','\xf1'},{'\xc7','\xf2'}, + {'\xc8','\xb4'},{'\xc8','\xb5'},{'\xc8','\xb6'},{'\xc8','\xb7'},{'\xc8','\xb8'}, + {'\xc6','\xe3'},{'\xc6','\xda'},{'\xc6','\xdb'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa3','\x74'}, + {'\xa3','\x75'},{'\xa3','\x76'},{'\xa3','\x77'},{'\xa3','\x78'},{'\xa3','\x79'}, + {'\xa3','\x7a'},{'\xa3','\x7b'},{'\xa3','\x7c'},{'\xa3','\x7d'},{'\xa3','\x7e'}, + {'\xa3','\xa1'},{'\xa3','\xa2'},{'\xa3','\xa3'},{'\xa3','\xa4'},{'\xa3','\xa5'}, + {'\xa3','\xa6'},{'\xa3','\xa7'},{'\xa3','\xa8'},{'\xa3','\xa9'},{'\xa3','\xaa'}, + {'\xa3','\xab'},{'\xa3','\xac'},{'\xa3','\xad'},{'\xa3','\xae'},{'\xa3','\xaf'}, + {'\xa3','\xb0'},{'\xa3','\xb1'},{'\xa3','\xb2'},{'\xa3','\xb3'},{'\xa3','\xb4'}, + {'\xa3','\xb5'},{'\xa3','\xb6'},{'\xa3','\xb7'},{'\xa3','\xb8'},{'\xa3','\xb9'}, + {'\xa3','\xba'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa4','\x40'},{'\xa4','\x47'},{'\xa4','\x54'},{'\xa5','\x7c'},{'\xa4','\x57'}, + {'\xa4','\xa4'},{'\xa4','\x55'},{'\xa5','\xd2'},{'\xa4','\x41'},{'\xa4','\xfe'}, + {'\xa4','\x42'},{'\xa4','\xd1'},{'\xa6','\x61'},{'\xa4','\x48'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xc8','\x79'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9c','\x41'},{'\x9c','\x42'},{'\x9c','\x43'}, + {'\x9c','\x44'},{'\x9c','\x45'},{'\x9c','\x46'},{'\x9c','\x47'},{'\x9c','\x48'}, + {'\x9c','\x49'},{'\x9c','\x4a'},{'\xa4','\xeb'},{'\xa4','\xf5'},{'\xa4','\xf4'}, + {'\xa4','\xec'},{'\xaa','\xf7'},{'\xa4','\x67'},{'\xa4','\xe9'},{'\x99','\xfd'}, + {'\x99','\xfc'},{'\xaa','\xc0'},{'\xa6','\x57'},{'\xaf','\x53'},{'\xb0','\x5d'}, + {'\xaf','\xac'},{'\xb3','\xd2'},{'\xa5','\x4e'},{'\xa9','\x49'},{'\xbe','\xc7'}, + {'\xba','\xca'},{'\xa5','\xf8'},{'\xb8','\xea'},{'\xa8','\xf3'},{'\xb2','\xbd'}, + {'\xa5','\xf0'},{'\xa6','\xdb'},{'\xa6','\xdc'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa4','\x40'},{'\xa4','\x47'}, + {'\xa4','\x54'},{'\xa5','\x7c'},{'\xa4','\xad'},{'\xa4','\xbb'},{'\xa4','\x43'}, + {'\xa4','\x4b'},{'\xa4','\x45'},{'\xa4','\x51'},{'\xa4','\xeb'},{'\xa4','\xf5'}, + {'\xa4','\xf4'},{'\xa4','\xec'},{'\xaa','\xf7'},{'\xa4','\x67'},{'\xa4','\xe9'}, + {'\xae','\xe8'},{'\xa6','\xb3'},{'\xaa','\xc0'},{'\xa6','\x57'},{'\xaf','\x53'}, + {'\xb0','\x5d'},{'\xaf','\xac'},{'\xb3','\xd2'},{'\xaf','\xb5'},{'\xa8','\x6b'}, + {'\xa4','\x6b'},{'\xbe','\x41'},{'\xc0','\x75'},{'\xa6','\x4c'},{'\xaa','\x60'}, + {'\xb6','\xb5'},{'\xa5','\xf0'},{'\xbc','\x67'},{'\xa1','\xc0'},{'\xa4','\x57'}, + {'\xa4','\xa4'},{'\xa4','\x55'},{'\xa5','\xaa'},{'\xa5','\x6b'},{'\xc2','\xe5'}, + {'\xa9','\x76'},{'\xbe','\xc7'},{'\xba','\xca'},{'\xa5','\xf8'},{'\xb8','\xea'}, + {'\xa8','\xf3'},{'\xa9','\x5d'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x48','\x67'}, + {'\x00','\x00'},{'\x65','\x56'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x64','\x61'},{'\x41','\x55'},{'\x00','\x00'},{'\x6f','\x56'},{'\x70','\x63'}, + {'\x64','\x6d'},{'\x00','\x00'},{'\x00','\x00'},{'\x49','\x55'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x70','\x41'}, + {'\x6e','\x41'},{'\x00','\x00'},{'\x6d','\x41'},{'\x6b','\x41'},{'\x4b','\x42'}, + {'\x4d','\x42'},{'\x47','\x42'},{'\x00','\x00'},{'\x00','\x00'},{'\x70','\x46'}, + {'\x6e','\x46'},{'\x00','\x00'},{'\x00','\x00'},{'\xa2','\x55'},{'\xa2','\x56'}, + {'\x48','\x7a'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x66','\x6d'}, + {'\x6e','\x6d'},{'\x00','\x00'},{'\xa2','\x50'},{'\xa2','\x51'},{'\xa2','\x52'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa2','\x54'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x9d','\xe7'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x50','\x61'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x70','\x73'},{'\x6e','\x73'},{'\x00','\x00'}, + {'\x6d','\x73'},{'\x70','\x56'},{'\x6e','\x56'},{'\x00','\x00'},{'\x6d','\x56'}, + {'\x6b','\x56'},{'\x4d','\x56'},{'\x70','\x57'},{'\x6e','\x57'},{'\x00','\x00'}, + {'\x6d','\x57'},{'\x6b','\x57'},{'\x4d','\x57'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9d','\xe3'},{'\x42','\x71'},{'\xa2','\x57'},{'\x63','\x64'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x64','\x42'},{'\x47','\x79'},{'\x68','\x61'},{'\x48','\x50'}, + {'\x69','\x6e'},{'\x4b','\x4b'},{'\xa2','\x53'},{'\x6b','\x74'},{'\x6c','\x6d'}, + {'\xa1','\xeb'},{'\xa1','\xea'},{'\x6c','\x78'},{'\x6d','\x62'},{'\xa2','\x4f'}, + {'\x00','\x00'},{'\x50','\x48'},{'\x9d','\xe4'},{'\x00','\x00'},{'\x50','\x52'}, + {'\x73','\x72'},{'\x53','\x76'},{'\x57','\x62'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x91','\xe0'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa0','\xa2'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfb','\x44'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x95','\xb8'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa0','\x48'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa0','\x4c'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xfb','\xdf'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xfb','\xe5'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xfb','\x6f'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x95','\x42'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xfe','\x7d'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xfe','\x67'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x95','\x5e'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x95','\xde'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x95','\xc7'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfc','\x61'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x95','\xc9'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xfc','\x7c'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfc','\xa8'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xfe','\x71'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfc','\xc2'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xfe','\x4d'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x96','\xad'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9c','\xd3'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xfd','\x5e'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xfe','\x4a'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xfd','\x67'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfb','\xb0'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfb','\x7d'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xfd','\xe3'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfd','\xf1'},{'\x00','\x00'},{'\x00','\x00'},{'\xfd','\xef'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfd','\xf2'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xfb','\x45'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa4','\x40'},{'\xa4','\x42'}, + {'\x00','\x00'},{'\xa4','\x43'},{'\x98','\xa7'},{'\x00','\x00'},{'\x91','\xd7'}, + {'\xc9','\x45'},{'\xa4','\x56'},{'\xa4','\x54'},{'\xa4','\x57'},{'\xa4','\x55'}, + {'\xc9','\x46'},{'\xa4','\xa3'},{'\xc9','\x4f'},{'\xc9','\x4d'},{'\xa4','\xa2'}, + {'\xa4','\xa1'},{'\x00','\x00'},{'\x83','\xfd'},{'\xa5','\x42'},{'\xa5','\x41'}, + {'\xa5','\x40'},{'\x81','\x40'},{'\xa5','\x43'},{'\xa4','\xfe'},{'\x85','\xd2'}, + {'\x8a','\xbd'},{'\x83','\x5b'},{'\x85','\x46'},{'\xa5','\xe0'},{'\xa5','\xe1'}, + {'\x00','\x00'},{'\x93','\xe5'},{'\x81','\x41'},{'\x00','\x00'},{'\x83','\x55'}, + {'\x8b','\xf2'},{'\xa8','\xc3'},{'\x84','\xca'},{'\x9c','\xc9'},{'\x00','\x00'}, + {'\x83','\xaa'},{'\xa4','\x58'},{'\x81','\x42'},{'\xa4','\xa4'},{'\xc9','\x50'}, + {'\x98','\xa8'},{'\xa4','\xa5'},{'\xc9','\x63'},{'\xa6','\xea'},{'\xcb','\xb1'}, + {'\x8a','\x5a'},{'\x00','\x00'},{'\xc6','\xbf'},{'\x91','\xcc'},{'\xa4','\x59'}, + {'\xa4','\xa6'},{'\x83','\x6f'},{'\xa5','\x44'},{'\xc9','\x64'},{'\x8b','\xed'}, + {'\x8a','\x5b'},{'\xc6','\xc0'},{'\x00','\x00'},{'\x00','\x00'},{'\xc9','\x40'}, + {'\xa4','\x44'},{'\x94','\xf2'},{'\xa4','\x5b'},{'\x00','\x00'},{'\xc9','\x47'}, + {'\xa4','\x5c'},{'\x85','\xf3'},{'\x00','\x00'},{'\xa4','\xa7'},{'\x83','\xbf'}, + {'\xa5','\x45'},{'\xa5','\x47'},{'\xa5','\x46'},{'\x87','\xe4'},{'\x00','\x00'}, + {'\xa5','\xe2'},{'\xa5','\xe3'},{'\x84','\xce'},{'\x81','\x43'},{'\xa8','\xc4'}, + {'\x92','\xe9'},{'\xad','\xbc'},{'\xa4','\x41'},{'\x9c','\xdf'},{'\x9c','\xe8'}, + {'\xc9','\x41'},{'\xa4','\x45'},{'\xa4','\x5e'},{'\xa4','\x5d'},{'\x84','\x74'}, + {'\x85','\x70'},{'\x81','\x44'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x83','\xbc'},{'\x00','\x00'},{'\x00','\x00'},{'\xa5','\xe4'},{'\xfe','\x41'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x85','\x67'},{'\x85','\xaf'},{'\x00','\x00'},{'\xa8','\xc5'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa0','\x61'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xb0','\xae'}, + {'\xd4','\x4b'},{'\x93','\xfa'},{'\x98','\xa9'},{'\xb6','\xc3'},{'\xdc','\xb1'}, + {'\xdc','\xb2'},{'\xc6','\xc1'},{'\xa4','\x46'},{'\x98','\xaa'},{'\xa4','\xa9'}, + {'\x83','\x5c'},{'\x81','\x45'},{'\xa8','\xc6'},{'\xa4','\x47'},{'\xc9','\x48'}, + {'\xa4','\x5f'},{'\x8a','\x5f'},{'\x00','\x00'},{'\xa4','\xaa'},{'\xa4','\xac'}, + {'\xc9','\x51'},{'\xa4','\xad'},{'\xa4','\xab'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfe','\x62'},{'\xa5','\xe5'},{'\x83','\x52'},{'\xa8','\xc7'},{'\x92','\x40'}, + {'\x00','\x00'},{'\xa8','\xc8'},{'\xab','\x45'},{'\xc6','\xc2'},{'\xa4','\x60'}, + {'\xa4','\xae'},{'\x98','\xab'},{'\xa5','\xe6'},{'\xa5','\xe8'},{'\xa5','\xe7'}, + {'\x84','\x64'},{'\xa6','\xeb'},{'\x83','\xc2'},{'\x00','\x00'},{'\xa8','\xc9'}, + {'\xa8','\xca'},{'\xab','\x46'},{'\xab','\x47'},{'\x00','\x00'},{'\x81','\x46'}, + {'\x00','\x00'},{'\x89','\x5d'},{'\xad','\xbd'},{'\x00','\x00'},{'\x8a','\x62'}, + {'\xdc','\xb3'},{'\x98','\xac'},{'\x00','\x00'},{'\xf6','\xd6'},{'\xa4','\x48'}, + {'\x9c','\xf4'},{'\x98','\xad'},{'\x00','\x00'},{'\x00','\x00'},{'\x87','\xa3'}, + {'\xa4','\xb0'},{'\xa4','\xaf'},{'\xc9','\x52'},{'\xa4','\xb1'},{'\xa4','\xb7'}, + {'\x85','\xb2'},{'\xa4','\xb2'},{'\xa4','\xb3'},{'\xc9','\x54'},{'\xc9','\x53'}, + {'\xa4','\xb5'},{'\xa4','\xb6'},{'\x00','\x00'},{'\xa4','\xb4'},{'\x84','\x47'}, + {'\x93','\xc2'},{'\x00','\x00'},{'\x83','\x54'},{'\x00','\x00'},{'\x83','\xac'}, + {'\xa5','\x4a'},{'\xa5','\x4b'},{'\xa5','\x4c'},{'\xa5','\x4d'},{'\xa5','\x49'}, + {'\xa5','\x50'},{'\xc9','\x6a'},{'\x00','\x00'},{'\xc9','\x66'},{'\xc9','\x69'}, + {'\xa5','\x51'},{'\xa5','\x61'},{'\x00','\x00'},{'\xc9','\x68'},{'\x00','\x00'}, + {'\xa5','\x4e'},{'\xa5','\x4f'},{'\xa5','\x48'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc9','\x65'},{'\xc9','\x67'},{'\x87','\xa4'},{'\x81','\x47'},{'\x83','\xa8'}, + {'\x81','\x48'},{'\x92','\x54'},{'\x00','\x00'},{'\xa5','\xf5'},{'\xc9','\xb0'}, + {'\xa5','\xf2'},{'\xa5','\xf6'},{'\xc9','\xba'},{'\xc9','\xae'},{'\xa5','\xf3'}, + {'\xc9','\xb2'},{'\x98','\xae'},{'\x00','\x00'},{'\x00','\x00'},{'\xa5','\xf4'}, + {'\x81','\x49'},{'\xa5','\xf7'},{'\x00','\x00'},{'\xa5','\xe9'},{'\xc9','\xb1'}, + {'\xa5','\xf8'},{'\xc9','\xb5'},{'\xfb','\xba'},{'\xc9','\xb9'},{'\xc9','\xb6'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc9','\xb3'},{'\xa5','\xea'},{'\xa5','\xec'}, + {'\xa5','\xf9'},{'\x00','\x00'},{'\xa5','\xee'},{'\xc9','\xab'},{'\xa5','\xf1'}, + {'\xa5','\xef'},{'\xa5','\xf0'},{'\xc9','\xbb'},{'\xc9','\xb8'},{'\xc9','\xaf'}, + {'\xa5','\xed'},{'\x00','\x00'},{'\x84','\x67'},{'\xc9','\xac'},{'\xa5','\xeb'}, + {'\x85','\xd1'},{'\x8d','\xfd'},{'\x81','\x4a'},{'\xc9','\xb4'},{'\x84','\xc4'}, + {'\x83','\xec'},{'\x85','\xb1'},{'\x00','\x00'},{'\xc9','\xb7'},{'\x00','\x00'}, + {'\x85','\xb4'},{'\x83','\xa9'},{'\x83','\xab'},{'\x84','\xc3'},{'\x98','\xaf'}, + {'\x98','\xb0'},{'\x83','\xeb'},{'\x83','\x43'},{'\xc9','\xad'},{'\xca','\x66'}, + {'\x00','\x00'},{'\xa7','\x42'},{'\xa6','\xf4'},{'\x00','\x00'},{'\xfb','\xbd'}, + {'\xca','\x67'},{'\xa6','\xf1'},{'\x00','\x00'},{'\xa7','\x44'},{'\x98','\xb1'}, + {'\xa6','\xf9'},{'\xfb','\xbc'},{'\xa6','\xf8'},{'\xca','\x5b'},{'\xa6','\xfc'}, + {'\xa6','\xf7'},{'\xca','\x60'},{'\xca','\x68'},{'\x00','\x00'},{'\xca','\x64'}, + {'\x98','\xb2'},{'\xa6','\xfa'},{'\x00','\x00'},{'\x98','\xb3'},{'\xa6','\xfd'}, + {'\xa6','\xee'},{'\xa7','\x47'},{'\xca','\x5d'},{'\x00','\x00'},{'\x98','\xb4'}, + {'\xcb','\xbd'},{'\xa6','\xec'},{'\xa7','\x43'},{'\xa6','\xed'},{'\xa6','\xf5'}, + {'\xa6','\xf6'},{'\xca','\x62'},{'\xca','\x5e'},{'\xa6','\xfb'},{'\xa6','\xf3'}, + {'\xca','\x5a'},{'\xa6','\xef'},{'\xca','\x65'},{'\xa7','\x45'},{'\xa7','\x48'}, + {'\xa6','\xf2'},{'\xa7','\x40'},{'\xa7','\x46'},{'\xa6','\xf0'},{'\xca','\x63'}, + {'\xa7','\x41'},{'\xca','\x69'},{'\xca','\x5c'},{'\xa6','\xfe'},{'\xca','\x5f'}, + {'\x8e','\x40'},{'\x00','\x00'},{'\xca','\x61'},{'\x00','\x00'},{'\xa8','\xd8'}, + {'\xcb','\xbf'},{'\xcb','\xcb'},{'\xa8','\xd0'},{'\x00','\x00'},{'\xcb','\xcc'}, + {'\xa8','\xcb'},{'\xa8','\xd5'},{'\x00','\x00'},{'\x98','\xb5'},{'\xa8','\xce'}, + {'\xcb','\xb9'},{'\xa8','\xd6'},{'\xcb','\xb8'},{'\xcb','\xbc'},{'\xcb','\xc3'}, + {'\xcb','\xc1'},{'\xa8','\xde'},{'\xa8','\xd9'},{'\xcb','\xb3'},{'\xcb','\xb5'}, + {'\xa8','\xdb'},{'\xa8','\xcf'},{'\xcb','\xb6'},{'\xcb','\xc2'},{'\xcb','\xc9'}, + {'\xa8','\xd4'},{'\xcb','\xbb'},{'\xcb','\xb4'},{'\xa8','\xd3'},{'\xcb','\xb7'}, + {'\xa8','\xd7'},{'\xcb','\xba'},{'\x81','\x4b'},{'\xa8','\xd2'},{'\x00','\x00'}, + {'\xa8','\xcd'},{'\x00','\x00'},{'\xa8','\xdc'},{'\xcb','\xc4'},{'\xa8','\xdd'}, + {'\xcb','\xc8'},{'\x00','\x00'},{'\xcb','\xc6'},{'\xcb','\xca'},{'\xa8','\xda'}, + {'\xcb','\xbe'},{'\xcb','\xb2'},{'\x00','\x00'},{'\xcb','\xc0'},{'\xa8','\xd1'}, + {'\xcb','\xc5'},{'\xa8','\xcc'},{'\xcb','\xc7'},{'\x00','\x00'},{'\x83','\x65'}, + {'\x92','\x55'},{'\x98','\xb6'},{'\x83','\x66'},{'\x00','\x00'},{'\x86','\xab'}, + {'\x83','\xed'},{'\x83','\xee'},{'\x86','\xac'},{'\x87','\xa7'},{'\x88','\xca'}, + {'\xfb','\xbe'},{'\x87','\xa6'},{'\x82','\x7d'},{'\xab','\x56'},{'\xab','\x4a'}, + {'\x98','\xb7'},{'\x00','\x00'},{'\xcd','\xe0'},{'\xcd','\xe8'},{'\x98','\xf7'}, + {'\xab','\x49'},{'\xab','\x51'},{'\xab','\x5d'},{'\x00','\x00'},{'\xcd','\xee'}, + {'\xcd','\xec'},{'\xcd','\xe7'},{'\x00','\x00'},{'\x98','\xb8'},{'\x00','\x00'}, + {'\xab','\x4b'},{'\xcd','\xed'},{'\xcd','\xe3'},{'\xab','\x59'},{'\xab','\x50'}, + {'\xab','\x58'},{'\xcd','\xde'},{'\x00','\x00'},{'\xcd','\xea'},{'\x98','\xb9'}, + {'\xcd','\xe1'},{'\xab','\x54'},{'\xcd','\xe2'},{'\x98','\xba'},{'\xcd','\xdd'}, + {'\xab','\x5b'},{'\xab','\x4e'},{'\xab','\x57'},{'\xab','\x4d'},{'\x00','\x00'}, + {'\xcd','\xdf'},{'\xcd','\xe4'},{'\x00','\x00'},{'\xcd','\xeb'},{'\xab','\x55'}, + {'\xab','\x52'},{'\xcd','\xe6'},{'\xab','\x5a'},{'\xcd','\xe9'},{'\xcd','\xe5'}, + {'\xab','\x4f'},{'\xab','\x5c'},{'\xab','\x53'},{'\xab','\x4c'},{'\xab','\x48'}, + {'\x00','\x00'},{'\x8d','\xb9'},{'\x94','\x5f'},{'\x94','\x60'},{'\x88','\xc8'}, + {'\x00','\x00'},{'\x8c','\xc8'},{'\x83','\xa7'},{'\x8c','\x6c'},{'\x00','\x00'}, + {'\xcd','\xef'},{'\x87','\xa8'},{'\xad','\xd7'},{'\xad','\xc1'},{'\x98','\xbb'}, + {'\xad','\xd1'},{'\x98','\xbc'},{'\xad','\xd6'},{'\xd0','\xd0'},{'\xd0','\xcf'}, + {'\xd0','\xd4'},{'\xd0','\xd5'},{'\xad','\xc4'},{'\x98','\xbd'},{'\xad','\xcd'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xfe','\x7b'},{'\xad','\xda'},{'\x81','\x4c'}, + {'\xad','\xce'},{'\x00','\x00'},{'\x00','\x00'},{'\x98','\xbe'},{'\x00','\x00'}, + {'\xd0','\xc9'},{'\xad','\xc7'},{'\xd0','\xca'},{'\x98','\xbf'},{'\xad','\xdc'}, + {'\x00','\x00'},{'\xad','\xd3'},{'\xad','\xbe'},{'\xad','\xbf'},{'\xd0','\xdd'}, + {'\xb0','\xbf'},{'\x00','\x00'},{'\xad','\xcc'},{'\xad','\xcb'},{'\xd0','\xcb'}, + {'\xad','\xcf'},{'\xd4','\x5b'},{'\xad','\xc6'},{'\xd0','\xd6'},{'\xad','\xd5'}, + {'\xad','\xd4'},{'\xad','\xca'},{'\xd0','\xce'},{'\xd0','\xd7'},{'\x00','\x00'}, + {'\xd0','\xc8'},{'\xad','\xc9'},{'\xd0','\xd8'},{'\xad','\xd2'},{'\xd0','\xcc'}, + {'\xad','\xc0'},{'\x82','\xa9'},{'\xad','\xc3'},{'\xad','\xc2'},{'\xd0','\xd9'}, + {'\xad','\xd0'},{'\xad','\xc5'},{'\xad','\xd9'},{'\xad','\xdb'},{'\xd0','\xd3'}, + {'\xad','\xd8'},{'\xfb','\xc1'},{'\xd0','\xdb'},{'\xd0','\xcd'},{'\xd0','\xdc'}, + {'\x00','\x00'},{'\xd0','\xd1'},{'\x98','\xc0'},{'\xd0','\xda'},{'\x82','\xa3'}, + {'\xd0','\xd2'},{'\x00','\x00'},{'\x92','\xb2'},{'\x85','\xb0'},{'\x98','\xc1'}, + {'\xad','\xc8'},{'\x00','\x00'},{'\x85','\xb3'},{'\x00','\x00'},{'\xd4','\x63'}, + {'\xd4','\x57'},{'\x81','\x4d'},{'\xb0','\xb3'},{'\x00','\x00'},{'\xd4','\x5c'}, + {'\xd4','\x62'},{'\xb0','\xb2'},{'\xd4','\x55'},{'\xb0','\xb6'},{'\xd4','\x59'}, + {'\xd4','\x52'},{'\xb0','\xb4'},{'\xd4','\x56'},{'\xb0','\xb9'},{'\xb0','\xbe'}, + {'\x81','\x4e'},{'\xd4','\x67'},{'\x00','\x00'},{'\xd4','\x51'},{'\x00','\x00'}, + {'\xb0','\xba'},{'\xfb','\xbf'},{'\xd4','\x66'},{'\x98','\xc2'},{'\x00','\x00'}, + {'\xb0','\xb5'},{'\xd4','\x58'},{'\xb0','\xb1'},{'\xd4','\x53'},{'\xd4','\x4f'}, + {'\xd4','\x5d'},{'\xd4','\x50'},{'\xd4','\x4e'},{'\xd4','\x5a'},{'\xd4','\x60'}, + {'\xd4','\x61'},{'\xb0','\xb7'},{'\x98','\xc3'},{'\x00','\x00'},{'\xd8','\x5b'}, + {'\xd4','\x5e'},{'\xd4','\x4d'},{'\xd4','\x5f'},{'\x85','\xb5'},{'\xb0','\xc1'}, + {'\xd4','\x64'},{'\xb0','\xc0'},{'\xd4','\x4c'},{'\x00','\x00'},{'\xd4','\x54'}, + {'\xd4','\x65'},{'\xb0','\xbc'},{'\xb0','\xbb'},{'\xb0','\xb8'},{'\xb0','\xbd'}, + {'\x81','\x4f'},{'\x00','\x00'},{'\xb0','\xaf'},{'\x8d','\xfe'},{'\x00','\x00'}, + {'\xb0','\xb0'},{'\x8e','\x65'},{'\x89','\xc8'},{'\xb3','\xc8'},{'\x98','\xc4'}, + {'\xd8','\x5e'},{'\xd8','\x57'},{'\x00','\x00'},{'\xb3','\xc5'},{'\x00','\x00'}, + {'\xd8','\x5f'},{'\x90','\xf0'},{'\x00','\x00'},{'\x00','\x00'},{'\xd8','\x55'}, + {'\xd8','\x58'},{'\xb3','\xc4'},{'\xd8','\x59'},{'\x00','\x00'},{'\x98','\xc5'}, + {'\xb3','\xc7'},{'\xd8','\x5d'},{'\x00','\x00'},{'\xd8','\x53'},{'\xd8','\x52'}, + {'\xb3','\xc9'},{'\x00','\x00'},{'\xb3','\xca'},{'\xb3','\xc6'},{'\xb3','\xcb'}, + {'\xd8','\x51'},{'\xd8','\x5c'},{'\xd8','\x5a'},{'\xd8','\x54'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb3','\xc3'},{'\xd8','\x56'},{'\x00','\x00'}, + {'\x8c','\xc9'},{'\xfb','\xc2'},{'\x88','\xc9'},{'\x89','\xc9'},{'\x8f','\xfb'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb6','\xca'},{'\xb6','\xc4'},{'\xdc','\xb7'}, + {'\xb6','\xcd'},{'\xdc','\xbd'},{'\xdc','\xc0'},{'\xb6','\xc6'},{'\xb6','\xc7'}, + {'\xdc','\xba'},{'\xb6','\xc5'},{'\xdc','\xc3'},{'\xb6','\xcb'},{'\xdc','\xc4'}, + {'\x00','\x00'},{'\xdc','\xbf'},{'\xb6','\xcc'},{'\x98','\xc6'},{'\xdc','\xb4'}, + {'\xb6','\xc9'},{'\xdc','\xb5'},{'\x00','\x00'},{'\xdc','\xbe'},{'\xdc','\xbc'}, + {'\x00','\x00'},{'\xdc','\xb8'},{'\xb6','\xc8'},{'\xdc','\xb6'},{'\xb6','\xce'}, + {'\xdc','\xbb'},{'\xdc','\xc2'},{'\xdc','\xb9'},{'\xdc','\xc1'},{'\x00','\x00'}, + {'\x94','\x4f'},{'\xb9','\xb6'},{'\xb9','\xb3'},{'\x98','\xc7'},{'\xb9','\xb4'}, + {'\x00','\x00'},{'\xe0','\xf9'},{'\xe0','\xf1'},{'\xb9','\xb2'},{'\xb9','\xaf'}, + {'\xe0','\xf2'},{'\x81','\x50'},{'\xfb','\xc3'},{'\xb9','\xb1'},{'\xe0','\xf5'}, + {'\x00','\x00'},{'\xe0','\xf7'},{'\x81','\x51'},{'\x98','\xc8'},{'\xe0','\xfe'}, + {'\x98','\xc9'},{'\x00','\x00'},{'\xe0','\xfd'},{'\xe0','\xf8'},{'\xb9','\xae'}, + {'\xe0','\xf0'},{'\xb9','\xac'},{'\xe0','\xf3'},{'\xb9','\xb7'},{'\xe0','\xf6'}, + {'\x00','\x00'},{'\xe0','\xfa'},{'\xb9','\xb0'},{'\xb9','\xad'},{'\xe0','\xfc'}, + {'\xe0','\xfb'},{'\xb9','\xb5'},{'\x00','\x00'},{'\xe0','\xf4'},{'\x81','\x52'}, + {'\xbb','\xf8'},{'\xe4','\xec'},{'\x00','\x00'},{'\xe4','\xe9'},{'\xbb','\xf9'}, + {'\x00','\x00'},{'\xbb','\xf7'},{'\x98','\xca'},{'\xe4','\xf0'},{'\xe4','\xed'}, + {'\xe4','\xe6'},{'\xbb','\xf6'},{'\xfb','\xc6'},{'\xbb','\xfa'},{'\xe4','\xe7'}, + {'\xbb','\xf5'},{'\xbb','\xfd'},{'\xe4','\xea'},{'\xe4','\xeb'},{'\xbb','\xfb'}, + {'\xbb','\xfc'},{'\xe4','\xf1'},{'\xe4','\xee'},{'\xe4','\xef'},{'\x98','\xcb'}, + {'\xfb','\xc4'},{'\x00','\x00'},{'\xbe','\xaa'},{'\xe8','\xf8'},{'\xbe','\xa7'}, + {'\xe8','\xf5'},{'\xbe','\xa9'},{'\xbe','\xab'},{'\x81','\x53'},{'\xe8','\xf6'}, + {'\xbe','\xa8'},{'\x00','\x00'},{'\xe8','\xf7'},{'\x00','\x00'},{'\xe8','\xf4'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc0','\x76'},{'\xec','\xbd'},{'\xc0','\x77'}, + {'\xec','\xbb'},{'\x00','\x00'},{'\xec','\xbc'},{'\xec','\xba'},{'\xec','\xb9'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xec','\xbe'},{'\xc0','\x75'},{'\x98','\xcc'}, + {'\x00','\x00'},{'\xef','\xb8'},{'\xef','\xb9'},{'\x00','\x00'},{'\xe4','\xe8'}, + {'\xef','\xb7'},{'\xc0','\x78'},{'\xc3','\x5f'},{'\xf1','\xeb'},{'\xf1','\xec'}, + {'\x00','\x00'},{'\xc4','\xd7'},{'\xc4','\xd8'},{'\xf5','\xc1'},{'\xf5','\xc0'}, + {'\xc5','\x6c'},{'\xc5','\x6b'},{'\xf7','\xd0'},{'\x00','\x00'},{'\xa4','\x49'}, + {'\xa4','\x61'},{'\xa4','\xb9'},{'\x00','\x00'},{'\xa4','\xb8'},{'\xa5','\x53'}, + {'\xa5','\x52'},{'\xa5','\xfc'},{'\xa5','\xfb'},{'\xa5','\xfd'},{'\xa5','\xfa'}, + {'\x81','\x54'},{'\xa7','\x4a'},{'\xa7','\x49'},{'\xa7','\x4b'},{'\x95','\xfc'}, + {'\x00','\x00'},{'\x92','\xd1'},{'\x81','\x55'},{'\xa8','\xe0'},{'\x00','\x00'}, + {'\xa8','\xdf'},{'\xa8','\xe1'},{'\x83','\x67'},{'\xab','\x5e'},{'\x00','\x00'}, + {'\xa2','\x59'},{'\xd0','\xde'},{'\xa2','\x5a'},{'\xb0','\xc2'},{'\xa2','\x5c'}, + {'\xa2','\x5b'},{'\xd8','\x60'},{'\x98','\xcd'},{'\xa2','\x5d'},{'\xb9','\xb8'}, + {'\xa2','\x5e'},{'\x81','\x56'},{'\xa4','\x4a'},{'\x00','\x00'},{'\xa4','\xba'}, + {'\xa5','\xfe'},{'\xa8','\xe2'},{'\x81','\x57'},{'\xa4','\x4b'},{'\xa4','\xbd'}, + {'\xa4','\xbb'},{'\xa4','\xbc'},{'\x00','\x00'},{'\x8c','\xa3'},{'\xa6','\x40'}, + {'\x00','\x00'},{'\x8b','\xd7'},{'\x89','\x55'},{'\xa7','\x4c'},{'\xa8','\xe4'}, + {'\xa8','\xe3'},{'\xa8','\xe5'},{'\x90','\xbc'},{'\x00','\x00'},{'\x88','\xb5'}, + {'\xad','\xdd'},{'\x8b','\xa6'},{'\x00','\x00'},{'\x00','\x00'},{'\xbe','\xac'}, + {'\x90','\x54'},{'\xc6','\xc3'},{'\x00','\x00'},{'\x00','\x00'},{'\x81','\x58'}, + {'\x92','\x4c'},{'\xc9','\x4e'},{'\x83','\x58'},{'\xa5','\x54'},{'\xa5','\x55'}, + {'\x00','\x00'},{'\x95','\xe4'},{'\xa6','\x41'},{'\x00','\x00'},{'\xca','\x6a'}, + {'\x81','\x59'},{'\xab','\x60'},{'\xab','\x5f'},{'\xd0','\xe0'},{'\xd0','\xdf'}, + {'\xb0','\xc3'},{'\xc6','\xc4'},{'\xa4','\xbe'},{'\xc9','\x55'},{'\x87','\xc0'}, + {'\xfb','\x41'},{'\x83','\x7e'},{'\x86','\x61'},{'\x81','\x5a'},{'\xcb','\xcd'}, + {'\x00','\x00'},{'\xab','\x61'},{'\x00','\x00'},{'\xad','\xe0'},{'\x00','\x00'}, + {'\xad','\xde'},{'\xad','\xdf'},{'\x81','\x5b'},{'\xfb','\x4e'},{'\x81','\x5c'}, + {'\x81','\x5d'},{'\xbe','\xad'},{'\xc6','\xc5'},{'\xa5','\x56'},{'\x00','\x00'}, + {'\x98','\xce'},{'\x85','\xad'},{'\xa6','\x42'},{'\xc9','\xbc'},{'\x83','\x4c'}, + {'\x83','\x4b'},{'\x94','\xfb'},{'\x95','\xd5'},{'\xa7','\x4d'},{'\xa7','\x4e'}, + {'\x98','\xcf'},{'\xca','\x6b'},{'\x00','\x00'},{'\x83','\xad'},{'\xcb','\xce'}, + {'\xa8','\xe6'},{'\xcb','\xcf'},{'\x00','\x00'},{'\x84','\x60'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x95','\xf3'},{'\xd0','\xe2'},{'\xd0','\xe3'},{'\xad','\xe3'}, + {'\x81','\x5e'},{'\xd0','\xe4'},{'\x84','\x5b'},{'\xd0','\xe1'},{'\xad','\xe4'}, + {'\xad','\xe2'},{'\xad','\xe1'},{'\xd0','\xe5'},{'\x90','\xb6'},{'\xd4','\x68'}, + {'\x84','\xee'},{'\x98','\xd0'},{'\xfb','\xcf'},{'\xd8','\x61'},{'\x00','\x00'}, + {'\x81','\x5f'},{'\xdc','\xc5'},{'\xe1','\x40'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x81','\x60'},{'\xbb','\xfe'},{'\xbe','\xae'},{'\xe8','\xf9'},{'\xfb','\xd0'}, + {'\xa4','\x4c'},{'\xa4','\x5a'},{'\x98','\xd1'},{'\x00','\x00'},{'\x87','\xa1'}, + {'\x00','\x00'},{'\x92','\xe1'},{'\x94','\x4c'},{'\x00','\x00'},{'\x94','\x61'}, + {'\x94','\x52'},{'\x8e','\x63'},{'\x81','\x61'},{'\x88','\xd7'},{'\x00','\x00'}, + {'\x84','\xc5'},{'\xb0','\xc4'},{'\xb3','\xcd'},{'\x00','\x00'},{'\xb9','\xb9'}, + {'\xfb','\xc7'},{'\xc9','\x42'},{'\xa4','\xbf'},{'\x00','\x00'},{'\xa5','\x59'}, + {'\xa5','\x57'},{'\xa5','\x58'},{'\x89','\xdb'},{'\x81','\x62'},{'\xa8','\xe7'}, + {'\xfb','\xd2'},{'\x8d','\xad'},{'\xa4','\x4d'},{'\xa4','\x4e'},{'\xc8','\x7d'}, + {'\xa4','\x62'},{'\x95','\xcf'},{'\x98','\xd2'},{'\xa4','\xc0'},{'\xa4','\xc1'}, + {'\xa4','\xc2'},{'\xc9','\xbe'},{'\xa5','\x5a'},{'\x81','\x63'},{'\xc9','\x6b'}, + {'\x83','\xd2'},{'\xa6','\x46'},{'\x00','\x00'},{'\xc9','\xbf'},{'\xa6','\x44'}, + {'\xa6','\x45'},{'\xc9','\xbd'},{'\x81','\x64'},{'\x81','\x65'},{'\xa6','\x47'}, + {'\xa6','\x43'},{'\x87','\xaa'},{'\x83','\x68'},{'\x83','\xae'},{'\x84','\xc7'}, + {'\xca','\x6c'},{'\xaa','\xec'},{'\xca','\x6d'},{'\xfb','\xc8'},{'\x81','\x66'}, + {'\xca','\x6e'},{'\x00','\x00'},{'\xa0','\x7e'},{'\xa7','\x50'},{'\xa7','\x4f'}, + {'\x95','\x7b'},{'\x95','\xe5'},{'\xa7','\x53'},{'\xa7','\x51'},{'\xa7','\x52'}, + {'\x81','\x67'},{'\x00','\x00'},{'\x8d','\xba'},{'\xa8','\xed'},{'\x00','\x00'}, + {'\xa8','\xec'},{'\xcb','\xd4'},{'\xcb','\xd1'},{'\xcb','\xd2'},{'\x98','\xd3'}, + {'\xcb','\xd0'},{'\xa8','\xee'},{'\xa8','\xea'},{'\xa8','\xe9'},{'\x81','\x68'}, + {'\xa8','\xeb'},{'\xa8','\xe8'},{'\x98','\xd4'},{'\x87','\xac'},{'\x00','\x00'}, + {'\x8e','\xaf'},{'\x84','\xc6'},{'\xa8','\xef'},{'\x88','\xcc'},{'\xab','\x63'}, + {'\xcd','\xf0'},{'\x00','\x00'},{'\xcb','\xd3'},{'\xab','\x68'},{'\x00','\x00'}, + {'\xcd','\xf1'},{'\xab','\x64'},{'\xab','\x67'},{'\xab','\x66'},{'\xab','\x65'}, + {'\xab','\x62'},{'\x81','\x69'},{'\x8d','\xc8'},{'\x87','\xab'},{'\xd0','\xe8'}, + {'\x00','\x00'},{'\xad','\xe7'},{'\xd0','\xeb'},{'\xad','\xe5'},{'\xfb','\xca'}, + {'\x00','\x00'},{'\x98','\xd5'},{'\xd0','\xe7'},{'\xad','\xe8'},{'\xad','\xe6'}, + {'\xad','\xe9'},{'\xd0','\xe9'},{'\xd0','\xea'},{'\xfb','\xc9'},{'\xd0','\xe6'}, + {'\xd0','\xec'},{'\x92','\xb3'},{'\x92','\xc9'},{'\x82','\x76'},{'\x00','\x00'}, + {'\x87','\xa9'},{'\x98','\xd6'},{'\xb3','\xd1'},{'\xb0','\xc5'},{'\xd4','\x69'}, + {'\xd4','\x6b'},{'\xd4','\x6a'},{'\xd4','\x6c'},{'\xb0','\xc6'},{'\x92','\xeb'}, + {'\x81','\x6a'},{'\xb3','\xce'},{'\xfc','\xf5'},{'\xb3','\xcf'},{'\xb3','\xd0'}, + {'\x00','\x00'},{'\xb6','\xd0'},{'\xdc','\xc7'},{'\x98','\xd7'},{'\xdc','\xc6'}, + {'\xdc','\xc8'},{'\xdc','\xc9'},{'\xb6','\xd1'},{'\x00','\x00'},{'\xb6','\xcf'}, + {'\xe1','\x41'},{'\xe1','\x42'},{'\xb9','\xbb'},{'\xb9','\xba'},{'\xe3','\x5a'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xbc','\x40'},{'\xbc','\x41'},{'\xbc','\x42'}, + {'\xbc','\x44'},{'\xe4','\xf2'},{'\xe4','\xf3'},{'\xbc','\x43'},{'\x00','\x00'}, + {'\xfb','\x69'},{'\x81','\x6b'},{'\xbe','\xaf'},{'\x81','\x6c'},{'\xbe','\xb0'}, + {'\x81','\x6d'},{'\x00','\x00'},{'\xf1','\xed'},{'\xf5','\xc3'},{'\xf5','\xc2'}, + {'\xf7','\xd1'},{'\xfb','\xcb'},{'\xa4','\x4f'},{'\x81','\x6e'},{'\x8b','\xef'}, + {'\x89','\x74'},{'\xa5','\x5c'},{'\xa5','\x5b'},{'\x83','\xef'},{'\x8e','\xb0'}, + {'\xa6','\x48'},{'\x98','\xd8'},{'\x00','\x00'},{'\xc9','\xc0'},{'\x00','\x00'}, + {'\x83','\xf0'},{'\xa7','\x55'},{'\xa7','\x56'},{'\xa7','\x54'},{'\xa7','\x57'}, + {'\xca','\x6f'},{'\xca','\x70'},{'\x81','\x6f'},{'\x00','\x00'},{'\x89','\xca'}, + {'\x83','\x69'},{'\x84','\xc8'},{'\x93','\xf5'},{'\x81','\x70'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x95','\xa2'},{'\x00','\x00'},{'\xa8','\xf1'}, + {'\xcb','\xd5'},{'\x00','\x00'},{'\xa8','\xf0'},{'\x85','\xb7'},{'\xcd','\xf2'}, + {'\xab','\x6c'},{'\xcd','\xf3'},{'\xab','\x6b'},{'\x00','\x00'},{'\x95','\x44'}, + {'\x00','\x00'},{'\xab','\x69'},{'\x00','\x00'},{'\xab','\x6a'},{'\x00','\x00'}, + {'\x84','\xc9'},{'\x98','\xd9'},{'\xd0','\xed'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x81','\x71'},{'\xfb','\xcc'},{'\xb0','\xc7'},{'\xd4','\x6e'},{'\x00','\x00'}, + {'\xb0','\xca'},{'\xd4','\x6d'},{'\xb1','\xe5'},{'\xb0','\xc9'},{'\xb0','\xc8'}, + {'\x00','\x00'},{'\xb3','\xd4'},{'\x00','\x00'},{'\xb3','\xd3'},{'\xb3','\xd2'}, + {'\xb6','\xd2'},{'\xfb','\xcd'},{'\xfb','\xce'},{'\xb6','\xd5'},{'\xb6','\xd6'}, + {'\xb6','\xd4'},{'\x00','\x00'},{'\xb6','\xd3'},{'\x92','\x68'},{'\x00','\x00'}, + {'\xe1','\x43'},{'\x00','\x00'},{'\xe1','\x44'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xe4','\xf5'},{'\xbc','\x45'},{'\xe4','\xf4'},{'\x92','\xa4'}, + {'\xbe','\xb1'},{'\xec','\xbf'},{'\xc0','\x79'},{'\x00','\x00'},{'\xf1','\xee'}, + {'\xc4','\x55'},{'\xc6','\xc6'},{'\xa4','\x63'},{'\xa4','\xc3'},{'\xc9','\x56'}, + {'\x00','\x00'},{'\xa4','\xc4'},{'\xa4','\xc5'},{'\x81','\x72'},{'\x94','\x5e'}, + {'\x94','\x53'},{'\x9c','\xd0'},{'\x00','\x00'},{'\xa5','\x5d'},{'\xa5','\x5e'}, + {'\x81','\x73'},{'\xa6','\x49'},{'\xca','\x71'},{'\xcb','\xd6'},{'\xcb','\xd7'}, + {'\x00','\x00'},{'\xab','\x6d'},{'\xd0','\xee'},{'\xb0','\xcc'},{'\xb0','\xcb'}, + {'\xd8','\x63'},{'\xd8','\x62'},{'\x00','\x00'},{'\x00','\x00'},{'\xa4','\x50'}, + {'\xa4','\xc6'},{'\xa5','\x5f'},{'\x00','\x00'},{'\xb0','\xcd'},{'\xc9','\x43'}, + {'\x00','\x00'},{'\xc9','\x6c'},{'\xa5','\x60'},{'\x00','\x00'},{'\xc9','\xc2'}, + {'\xa6','\x4b'},{'\xa6','\x4a'},{'\xc9','\xc1'},{'\xa7','\x58'},{'\x81','\x74'}, + {'\x00','\x00'},{'\x8d','\xc9'},{'\x98','\xda'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xad','\xea'},{'\x00','\x00'},{'\xfb','\xd4'},{'\xd4','\x6f'},{'\x86','\xad'}, + {'\xb6','\xd7'},{'\xe1','\x45'},{'\xb9','\xbc'},{'\xfb','\xd3'},{'\xfb','\xd5'}, + {'\xe8','\xfa'},{'\x00','\x00'},{'\x00','\x00'},{'\xf3','\xfd'},{'\xc6','\xc7'}, + {'\xa4','\xc7'},{'\x83','\xf1'},{'\x8b','\x4b'},{'\xcb','\xd8'},{'\xcd','\xf4'}, + {'\xb0','\xd0'},{'\xb0','\xce'},{'\xb0','\xcf'},{'\xa4','\x51'},{'\x98','\xdb'}, + {'\xa4','\x64'},{'\xa2','\xcd'},{'\xa4','\xca'},{'\x81','\x75'},{'\xa4','\xc9'}, + {'\xa4','\xc8'},{'\xa5','\x63'},{'\xa5','\x62'},{'\x00','\x00'},{'\xc9','\x6d'}, + {'\xc9','\xc3'},{'\x85','\x4f'},{'\x83','\x56'},{'\x00','\x00'},{'\xa8','\xf5'}, + {'\xa8','\xf2'},{'\xa8','\xf4'},{'\xa8','\xf3'},{'\x84','\xcb'},{'\x88','\x6f'}, + {'\xab','\x6e'},{'\x93','\x6d'},{'\x00','\x00'},{'\xb3','\xd5'},{'\x00','\x00'}, + {'\xa4','\x52'},{'\x98','\xdc'},{'\xa4','\xcb'},{'\x81','\x76'},{'\xa5','\x65'}, + {'\xa5','\x64'},{'\x89','\x41'},{'\xca','\x72'},{'\x84','\xc0'},{'\x00','\x00'}, + {'\xa8','\xf6'},{'\x83','\x60'},{'\x00','\x00'},{'\xc6','\xc8'},{'\x00','\x00'}, + {'\x88','\x55'},{'\xc9','\x57'},{'\x95','\xf2'},{'\xa5','\x67'},{'\xa5','\x66'}, + {'\xa6','\x4c'},{'\xa6','\x4d'},{'\xca','\x73'},{'\xa7','\x59'},{'\x83','\x6a'}, + {'\xa7','\x5a'},{'\x00','\x00'},{'\xa8','\xf7'},{'\xa8','\xf8'},{'\xa8','\xf9'}, + {'\x8d','\xbd'},{'\xab','\x6f'},{'\xcd','\xf5'},{'\x98','\xdd'},{'\x98','\xde'}, + {'\xad','\xeb'},{'\x00','\x00'},{'\x00','\x00'},{'\xc9','\x44'},{'\x00','\x00'}, + {'\xa4','\xcc'},{'\x8d','\x6d'},{'\x88','\xe5'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x87','\xad'},{'\xc9','\xc4'},{'\x89','\xcd'},{'\x86','\xae'},{'\x8d','\xbb'}, + {'\xca','\x74'},{'\xca','\x75'},{'\x00','\x00'},{'\x00','\x00'},{'\xcb','\xd9'}, + {'\x81','\x77'},{'\xcb','\xda'},{'\x84','\xda'},{'\xcd','\xf7'},{'\xcd','\xf6'}, + {'\xcd','\xf9'},{'\xcd','\xf8'},{'\xab','\x70'},{'\x00','\x00'},{'\xd4','\x70'}, + {'\xad','\xed'},{'\xd0','\xef'},{'\xad','\xec'},{'\x95','\xe8'},{'\x00','\x00'}, + {'\x95','\xe9'},{'\x8f','\xb6'},{'\xd8','\x64'},{'\xb3','\xd6'},{'\x95','\x7a'}, + {'\xd8','\x65'},{'\x87','\xc5'},{'\x84','\xdb'},{'\xfb','\xd7'},{'\xfb','\xd6'}, + {'\xe1','\x46'},{'\xb9','\xbd'},{'\x87','\xc7'},{'\x00','\x00'},{'\x81','\x78'}, + {'\x00','\x00'},{'\xbc','\x46'},{'\x92','\xba'},{'\xf1','\xef'},{'\x00','\x00'}, + {'\xc6','\xc9'},{'\x00','\x00'},{'\x00','\x00'},{'\xc9','\x58'},{'\x00','\x00'}, + {'\xa5','\x68'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x89','\x4f'}, + {'\x00','\x00'},{'\x95','\x48'},{'\x83','\xf2'},{'\xb0','\xd1'},{'\x00','\x00'}, + {'\x98','\xdf'},{'\x00','\x00'},{'\x00','\x00'},{'\xa4','\x53'},{'\xa4','\x65'}, + {'\xa4','\xce'},{'\xa4','\xcd'},{'\x8b','\x5a'},{'\xa4','\xcf'},{'\x83','\x42'}, + {'\x00','\x00'},{'\x98','\xe0'},{'\x84','\xfa'},{'\x98','\xe1'},{'\x00','\x00'}, + {'\xa8','\xfb'},{'\x00','\x00'},{'\xa8','\xfa'},{'\xa8','\xfc'},{'\x8d','\x40'}, + {'\x95','\xb3'},{'\xfb','\xdb'},{'\xab','\x71'},{'\x00','\x00'},{'\x81','\x79'}, + {'\x00','\x00'},{'\xad','\xee'},{'\x8c','\xd4'},{'\xe8','\xfb'},{'\xc2','\x4f'}, + {'\xa4','\x66'},{'\xa5','\x6a'},{'\xa5','\x79'},{'\xa5','\x74'},{'\x00','\x00'}, + {'\xa5','\x6f'},{'\xa5','\x6e'},{'\xa5','\x75'},{'\xa5','\x73'},{'\xa5','\x6c'}, + {'\xa5','\x7a'},{'\xa5','\x6d'},{'\xa5','\x69'},{'\xa5','\x78'},{'\xa5','\x77'}, + {'\xa5','\x76'},{'\xa5','\x6b'},{'\x00','\x00'},{'\xa5','\x72'},{'\x85','\xfc'}, + {'\x86','\x41'},{'\xa5','\x71'},{'\x86','\xb1'},{'\x94','\x62'},{'\xa5','\x7b'}, + {'\xa5','\x70'},{'\x87','\xb4'},{'\x98','\xe2'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa6','\x53'},{'\x00','\x00'},{'\xa6','\x59'},{'\xa6','\x55'},{'\x00','\x00'}, + {'\xa6','\x5b'},{'\xc9','\xc5'},{'\xa6','\x58'},{'\xa6','\x4e'},{'\xa6','\x51'}, + {'\xa6','\x54'},{'\xa6','\x50'},{'\xa6','\x57'},{'\xa6','\x5a'},{'\xa6','\x4f'}, + {'\xa6','\x52'},{'\xa6','\x56'},{'\xa6','\x5c'},{'\x89','\xcc'},{'\xfb','\x43'}, + {'\x90','\xb8'},{'\xfb','\x42'},{'\x85','\xba'},{'\xca','\x7e'},{'\xca','\x7b'}, + {'\xa0','\x55'},{'\xa7','\x67'},{'\xca','\x7c'},{'\xa7','\x5b'},{'\xa7','\x5d'}, + {'\xa7','\x75'},{'\xa7','\x70'},{'\x96','\xb2'},{'\x00','\x00'},{'\x81','\x7a'}, + {'\xca','\xa5'},{'\xca','\x7d'},{'\xa7','\x5f'},{'\xa7','\x61'},{'\xca','\xa4'}, + {'\xa7','\x68'},{'\xca','\x78'},{'\xa7','\x74'},{'\xa7','\x76'},{'\xa7','\x5c'}, + {'\xa7','\x6d'},{'\x84','\x51'},{'\xca','\x76'},{'\xa7','\x73'},{'\x96','\xb4'}, + {'\xa7','\x64'},{'\x83','\x45'},{'\xa7','\x6e'},{'\xa7','\x6f'},{'\xca','\x77'}, + {'\xa7','\x6c'},{'\xa7','\x6a'},{'\x00','\x00'},{'\xa7','\x6b'},{'\xa7','\x71'}, + {'\xca','\xa1'},{'\xa7','\x5e'},{'\x00','\x00'},{'\xa7','\x72'},{'\xca','\xa3'}, + {'\xa7','\x66'},{'\xa7','\x63'},{'\x00','\x00'},{'\xca','\x7a'},{'\xa7','\x62'}, + {'\xca','\xa6'},{'\xa7','\x65'},{'\x92','\xbb'},{'\xa7','\x69'},{'\x96','\xa4'}, + {'\x00','\x00'},{'\xa0','\x5a'},{'\xa7','\x60'},{'\xca','\xa2'},{'\x81','\x7b'}, + {'\x81','\x7c'},{'\x8e','\xb2'},{'\x8c','\xca'},{'\xca','\x79'},{'\x86','\xb0'}, + {'\x8f','\xb7'},{'\x8d','\xc2'},{'\x83','\xb0'},{'\x8d','\xbc'},{'\x00','\x00'}, + {'\x85','\xbc'},{'\x85','\xbb'},{'\x00','\x00'},{'\x00','\x00'},{'\x82','\xaf'}, + {'\xcb','\xeb'},{'\xcb','\xea'},{'\xa9','\x4f'},{'\xcb','\xed'},{'\xcb','\xef'}, + {'\xcb','\xe4'},{'\xcb','\xe7'},{'\xcb','\xee'},{'\xa9','\x50'},{'\xfb','\xd9'}, + {'\x94','\xfc'},{'\xcb','\xe1'},{'\xcb','\xe5'},{'\x98','\xe3'},{'\x00','\x00'}, + {'\xcb','\xe9'},{'\xce','\x49'},{'\xa9','\x4b'},{'\xce','\x4d'},{'\xa8','\xfd'}, + {'\xcb','\xe6'},{'\xa8','\xfe'},{'\xa9','\x4c'},{'\xa9','\x45'},{'\xa9','\x41'}, + {'\x00','\x00'},{'\xcb','\xe2'},{'\xa9','\x44'},{'\xa9','\x49'},{'\xa9','\x52'}, + {'\xcb','\xe3'},{'\xcb','\xdc'},{'\xa9','\x43'},{'\xcb','\xdd'},{'\xcb','\xdf'}, + {'\x00','\x00'},{'\xa9','\x46'},{'\x98','\xe4'},{'\xa9','\x48'},{'\xcb','\xdb'}, + {'\xcb','\xe0'},{'\x00','\x00'},{'\x81','\x7d'},{'\xa9','\x51'},{'\xa9','\x4d'}, + {'\xcb','\xe8'},{'\xa9','\x53'},{'\x95','\xa3'},{'\xa9','\x4a'},{'\xcb','\xde'}, + {'\xa9','\x47'},{'\x98','\xe5'},{'\x96','\xb6'},{'\xa9','\x42'},{'\xa9','\x40'}, + {'\xa0','\x57'},{'\xcb','\xec'},{'\x8b','\xf0'},{'\xa9','\x4e'},{'\x89','\xcb'}, + {'\xfb','\xda'},{'\x81','\x7e'},{'\x98','\xe6'},{'\x00','\x00'},{'\xce','\x48'}, + {'\xcd','\xfb'},{'\xce','\x4b'},{'\x81','\xa1'},{'\x95','\x79'},{'\xcd','\xfd'}, + {'\xab','\x78'},{'\xab','\xa8'},{'\xab','\x74'},{'\xab','\xa7'},{'\xab','\x7d'}, + {'\xab','\xa4'},{'\xab','\x72'},{'\xcd','\xfc'},{'\xce','\x43'},{'\xab','\xa3'}, + {'\xce','\x4f'},{'\xab','\xa5'},{'\x94','\x46'},{'\xab','\x79'},{'\x81','\xa2'}, + {'\x00','\x00'},{'\xce','\x45'},{'\xce','\x42'},{'\xab','\x77'},{'\x98','\xe7'}, + {'\xcd','\xfa'},{'\xab','\xa6'},{'\xce','\x4a'},{'\xab','\x7c'},{'\xce','\x4c'}, + {'\xab','\xa9'},{'\xab','\x73'},{'\xab','\x7e'},{'\xab','\x7b'},{'\xce','\x40'}, + {'\xab','\xa1'},{'\xce','\x46'},{'\xce','\x47'},{'\xab','\x7a'},{'\xab','\xa2'}, + {'\xab','\x76'},{'\x00','\x00'},{'\xfb','\x4a'},{'\x96','\xcf'},{'\x8c','\xb7'}, + {'\xab','\x75'},{'\xcd','\xfe'},{'\x81','\xa3'},{'\x83','\xf3'},{'\x8e','\xe2'}, + {'\x8e','\xb1'},{'\x86','\xb4'},{'\x8e','\xe3'},{'\xce','\x44'},{'\x87','\xb0'}, + {'\x94','\x63'},{'\x8e','\xe4'},{'\x96','\xb3'},{'\x00','\x00'},{'\x8f','\x4f'}, + {'\x88','\xce'},{'\xce','\x4e'},{'\x84','\xcc'},{'\xd1','\x44'},{'\xad','\xfb'}, + {'\xd0','\xf1'},{'\x98','\xe8'},{'\xd0','\xf6'},{'\xad','\xf4'},{'\xae','\x40'}, + {'\xd0','\xf4'},{'\xad','\xef'},{'\xad','\xf9'},{'\xad','\xfe'},{'\xd0','\xfb'}, + {'\x00','\x00'},{'\xad','\xfa'},{'\xad','\xfd'},{'\x98','\xe9'},{'\x00','\x00'}, + {'\xd0','\xfe'},{'\xad','\xf5'},{'\xd0','\xf5'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd1','\x42'},{'\xd1','\x43'},{'\x00','\x00'},{'\xad','\xf7'}, + {'\xd1','\x41'},{'\xad','\xf3'},{'\xae','\x43'},{'\x00','\x00'},{'\xd0','\xf8'}, + {'\x00','\x00'},{'\xad','\xf1'},{'\xfb','\x5a'},{'\xd1','\x46'},{'\xd0','\xf9'}, + {'\xd0','\xfd'},{'\xad','\xf6'},{'\xae','\x42'},{'\xd0','\xfa'},{'\xad','\xfc'}, + {'\xd1','\x40'},{'\xd1','\x47'},{'\xd4','\xa1'},{'\x98','\xea'},{'\xd1','\x45'}, + {'\xae','\x44'},{'\xad','\xf0'},{'\xd0','\xfc'},{'\xd0','\xf3'},{'\xfb','\x52'}, + {'\xad','\xf8'},{'\x00','\x00'},{'\x82','\x40'},{'\xd0','\xf2'},{'\x98','\xeb'}, + {'\x00','\x00'},{'\xd0','\xf7'},{'\x8e','\x66'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfb','\x55'},{'\x00','\x00'},{'\x87','\xae'},{'\x00','\x00'},{'\x8e','\x41'}, + {'\x81','\xa4'},{'\x84','\xcd'},{'\x98','\xec'},{'\xd0','\xf0'},{'\xae','\x41'}, + {'\x98','\xed'},{'\x00','\x00'},{'\xd4','\x77'},{'\x98','\xee'},{'\xb0','\xe4'}, + {'\xd4','\xa7'},{'\xb0','\xe2'},{'\xb0','\xdf'},{'\xd4','\x7c'},{'\xb0','\xdb'}, + {'\xd4','\xa2'},{'\xb0','\xe6'},{'\xd4','\x76'},{'\xd4','\x7b'},{'\xd4','\x7a'}, + {'\xad','\xf2'},{'\xb0','\xe1'},{'\xd4','\xa5'},{'\x00','\x00'},{'\xd4','\xa8'}, + {'\xd4','\x73'},{'\x00','\x00'},{'\xb3','\xe8'},{'\x81','\xa5'},{'\xd4','\xa9'}, + {'\xb0','\xe7'},{'\x00','\x00'},{'\xb0','\xd9'},{'\xb0','\xd6'},{'\xd4','\x7e'}, + {'\xb0','\xd3'},{'\x98','\xef'},{'\xd4','\xa6'},{'\x96','\xb1'},{'\xb0','\xda'}, + {'\xd4','\xaa'},{'\x81','\xa6'},{'\xd4','\x74'},{'\xd4','\xa4'},{'\xb0','\xdd'}, + {'\xd4','\x75'},{'\xd4','\x78'},{'\xd4','\x7d'},{'\x81','\xa7'},{'\x00','\x00'}, + {'\xb0','\xde'},{'\xb0','\xdc'},{'\xb0','\xe8'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb0','\xe3'},{'\x81','\xa8'},{'\xb0','\xd7'}, + {'\xb1','\xd2'},{'\x00','\x00'},{'\xb0','\xd8'},{'\xd4','\x79'},{'\xb0','\xe5'}, + {'\xb0','\xe0'},{'\xd4','\xa3'},{'\xb0','\xd5'},{'\x86','\xb3'},{'\x00','\x00'}, + {'\xfb','\x5b'},{'\xb0','\xd4'},{'\xa0','\x46'},{'\x81','\xa9'},{'\x8c','\x6e'}, + {'\x8c','\xc7'},{'\x00','\x00'},{'\x00','\x00'},{'\xa0','\x49'},{'\xa0','\x45'}, + {'\xfb','\xdd'},{'\x00','\x00'},{'\xd4','\x71'},{'\xd4','\x72'},{'\xd8','\x6a'}, + {'\x87','\xb3'},{'\x98','\xf0'},{'\x00','\x00'},{'\xb3','\xd7'},{'\xb3','\xda'}, + {'\xd8','\x75'},{'\xb3','\xee'},{'\xd8','\x78'},{'\xb3','\xd8'},{'\xd8','\x71'}, + {'\xb3','\xde'},{'\xb3','\xe4'},{'\xb5','\xbd'},{'\x00','\x00'},{'\x95','\xed'}, + {'\xb3','\xe2'},{'\xd8','\x6e'},{'\xb3','\xef'},{'\xb3','\xdb'},{'\xb3','\xe3'}, + {'\xd8','\x76'},{'\xdc','\xd7'},{'\xd8','\x7b'},{'\xd8','\x6f'},{'\x98','\xf1'}, + {'\xd8','\x66'},{'\xd8','\x73'},{'\xd8','\x6d'},{'\xb3','\xe1'},{'\xd8','\x79'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb3','\xdd'},{'\xb3','\xf1'},{'\xb3','\xea'}, + {'\x00','\x00'},{'\xb3','\xdf'},{'\xb3','\xdc'},{'\x81','\xaa'},{'\xb3','\xe7'}, + {'\x00','\x00'},{'\xd8','\x7a'},{'\xd8','\x6c'},{'\xd8','\x72'},{'\xd8','\x74'}, + {'\xd8','\x68'},{'\xd8','\x77'},{'\xb3','\xd9'},{'\xd8','\x67'},{'\x81','\xab'}, + {'\xb3','\xe0'},{'\xb3','\xf0'},{'\xb3','\xec'},{'\xd8','\x69'},{'\xb3','\xe6'}, + {'\x00','\x00'},{'\x94','\x42'},{'\xb3','\xed'},{'\xb3','\xe9'},{'\xb3','\xe5'}, + {'\x98','\xf2'},{'\xd8','\x70'},{'\x92','\x49'},{'\x87','\xb2'},{'\x00','\x00'}, + {'\x96','\xb5'},{'\xa0','\x4a'},{'\xb3','\xeb'},{'\xfb','\x4c'},{'\x86','\xb2'}, + {'\x8f','\xd9'},{'\xdc','\xd5'},{'\xdc','\xd1'},{'\x98','\xf3'},{'\xdc','\xe0'}, + {'\xdc','\xca'},{'\xdc','\xd3'},{'\xb6','\xe5'},{'\xb6','\xe6'},{'\xb6','\xde'}, + {'\xdc','\xdc'},{'\xb6','\xe8'},{'\xdc','\xcf'},{'\xdc','\xce'},{'\xdc','\xcc'}, + {'\xdc','\xde'},{'\xb6','\xdc'},{'\xdc','\xd8'},{'\xdc','\xcd'},{'\xb6','\xdf'}, + {'\xdc','\xd6'},{'\xb6','\xda'},{'\xdc','\xd2'},{'\xdc','\xd9'},{'\xdc','\xdb'}, + {'\x98','\xf4'},{'\x98','\xf5'},{'\xdc','\xdf'},{'\xb6','\xe3'},{'\xdc','\xcb'}, + {'\xb6','\xdd'},{'\xdc','\xd0'},{'\xfb','\x56'},{'\xb6','\xd8'},{'\x00','\x00'}, + {'\xb6','\xe4'},{'\xdc','\xda'},{'\xb6','\xe0'},{'\xb6','\xe1'},{'\xb6','\xe7'}, + {'\xb6','\xdb'},{'\xa2','\x5f'},{'\xb6','\xd9'},{'\xdc','\xd4'},{'\x96','\xc9'}, + {'\x8c','\x6d'},{'\x81','\xac'},{'\x00','\x00'},{'\x00','\x00'},{'\xb6','\xe2'}, + {'\xa0','\x4d'},{'\xa0','\x4b'},{'\xdc','\xdd'},{'\x88','\xcf'},{'\x00','\x00'}, + {'\x81','\xad'},{'\xb9','\xcd'},{'\xb9','\xc8'},{'\x00','\x00'},{'\xe1','\x55'}, + {'\xe1','\x51'},{'\x98','\xf6'},{'\xe1','\x4b'},{'\xb9','\xc2'},{'\xb9','\xbe'}, + {'\xe1','\x54'},{'\xb9','\xbf'},{'\xe1','\x4e'},{'\xe1','\x50'},{'\x00','\x00'}, + {'\xe1','\x53'},{'\xa0','\x4e'},{'\xb9','\xc4'},{'\x00','\x00'},{'\xb9','\xcb'}, + {'\xb9','\xc5'},{'\x00','\x00'},{'\x00','\x00'},{'\xe1','\x49'},{'\xb9','\xc6'}, + {'\xb9','\xc7'},{'\xe1','\x4c'},{'\xb9','\xcc'},{'\xfb','\xe1'},{'\xe1','\x4a'}, + {'\xe1','\x4f'},{'\xb9','\xc3'},{'\xe1','\x48'},{'\xb9','\xc9'},{'\xb9','\xc1'}, + {'\x82','\xb3'},{'\x00','\x00'},{'\x00','\x00'},{'\xb9','\xc0'},{'\xe1','\x4d'}, + {'\xe1','\x52'},{'\xa0','\x52'},{'\xb9','\xca'},{'\xfc','\xd9'},{'\x98','\xf8'}, + {'\xa0','\x4f'},{'\x81','\xae'},{'\x8b','\xf1'},{'\xfb','\x65'},{'\x00','\x00'}, + {'\xe1','\x47'},{'\x00','\x00'},{'\xbc','\x4d'},{'\xe5','\x47'},{'\x00','\x00'}, + {'\xe5','\x44'},{'\xa0','\x50'},{'\xbc','\x47'},{'\xbc','\x53'},{'\xbc','\x54'}, + {'\x8d','\x51'},{'\xbc','\x4a'},{'\xe5','\x42'},{'\xbc','\x4c'},{'\xe4','\xf9'}, + {'\xbc','\x52'},{'\xfe','\x5d'},{'\xe5','\x46'},{'\xbc','\x49'},{'\xe5','\x48'}, + {'\xbc','\x48'},{'\x00','\x00'},{'\xe5','\x43'},{'\xe5','\x45'},{'\xbc','\x4b'}, + {'\xe5','\x41'},{'\xe4','\xfa'},{'\xe4','\xf7'},{'\xa0','\x51'},{'\x00','\x00'}, + {'\xd8','\x6b'},{'\xe4','\xfd'},{'\x00','\x00'},{'\xe4','\xf6'},{'\xe4','\xfc'}, + {'\xe4','\xfb'},{'\x00','\x00'},{'\xe4','\xf8'},{'\xfb','\xe2'},{'\xbc','\x4f'}, + {'\xfb','\x6a'},{'\x81','\xaf'},{'\x00','\x00'},{'\x98','\xfa'},{'\xbc','\x4e'}, + {'\xfb','\xe4'},{'\x00','\x00'},{'\x00','\x00'},{'\xbc','\x50'},{'\xe4','\xfe'}, + {'\xbe','\xb2'},{'\xe5','\x40'},{'\x82','\x4f'},{'\x8a','\xbe'},{'\x99','\x40'}, + {'\xe9','\x45'},{'\x00','\x00'},{'\xe8','\xfd'},{'\x99','\x55'},{'\xbe','\xbe'}, + {'\xe9','\x42'},{'\xbe','\xb6'},{'\xbe','\xba'},{'\xe9','\x41'},{'\x00','\x00'}, + {'\xbe','\xb9'},{'\xbe','\xb5'},{'\xbe','\xb8'},{'\xbe','\xb3'},{'\xbe','\xbd'}, + {'\xe9','\x43'},{'\xe8','\xfe'},{'\xbe','\xbc'},{'\xe8','\xfc'},{'\xbe','\xbb'}, + {'\xe9','\x44'},{'\xe9','\x40'},{'\xbc','\x51'},{'\x00','\x00'},{'\xbe','\xbf'}, + {'\xe9','\x46'},{'\xbe','\xb7'},{'\xbe','\xb4'},{'\x94','\x57'},{'\x96','\xca'}, + {'\x81','\xb0'},{'\x00','\x00'},{'\xec','\xc6'},{'\xec','\xc8'},{'\xc0','\x7b'}, + {'\xec','\xc9'},{'\xec','\xc7'},{'\xec','\xc5'},{'\xec','\xc4'},{'\xc0','\x7d'}, + {'\xec','\xc3'},{'\xc0','\x7e'},{'\x00','\x00'},{'\x99','\x56'},{'\x81','\xb1'}, + {'\x99','\x57'},{'\xec','\xc1'},{'\xec','\xc2'},{'\xc0','\x7a'},{'\xc0','\xa1'}, + {'\xc0','\x7c'},{'\x00','\x00'},{'\xa0','\x53'},{'\xec','\xc0'},{'\x81','\xb2'}, + {'\xc2','\x50'},{'\x00','\x00'},{'\xef','\xbc'},{'\xef','\xba'},{'\xef','\xbf'}, + {'\xef','\xbd'},{'\x00','\x00'},{'\xef','\xbb'},{'\xef','\xbe'},{'\x99','\x58'}, + {'\xa0','\x5c'},{'\x81','\xb3'},{'\x99','\x59'},{'\x82','\x74'},{'\x8c','\x6f'}, + {'\xa0','\x5b'},{'\xc3','\x60'},{'\xf1','\xf2'},{'\xf1','\xf3'},{'\xc4','\x56'}, + {'\x00','\x00'},{'\xf1','\xf4'},{'\xf1','\xf0'},{'\xf1','\xf5'},{'\xf1','\xf1'}, + {'\xc2','\x51'},{'\x81','\xb4'},{'\x00','\x00'},{'\x99','\x5a'},{'\xf3','\xfe'}, + {'\xf4','\x41'},{'\xc4','\x59'},{'\xf4','\x40'},{'\xc4','\x58'},{'\xc4','\x57'}, + {'\x00','\x00'},{'\x99','\x5b'},{'\x00','\x00'},{'\x00','\x00'},{'\xc4','\x5a'}, + {'\xf5','\xc5'},{'\xf5','\xc6'},{'\x99','\x5c'},{'\xc4','\xda'},{'\xc4','\xd9'}, + {'\xc4','\xdb'},{'\xf5','\xc4'},{'\x00','\x00'},{'\xf6','\xd8'},{'\xf6','\xd7'}, + {'\x00','\x00'},{'\xc5','\x6d'},{'\xc5','\x6f'},{'\xc5','\x6e'},{'\xf6','\xd9'}, + {'\xc5','\xc8'},{'\xf8','\xa6'},{'\x94','\x64'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc5','\xf1'},{'\x00','\x00'},{'\xf8','\xa5'},{'\xf8','\xee'},{'\x00','\x00'}, + {'\x99','\x5d'},{'\xc9','\x49'},{'\x81','\xb5'},{'\x00','\x00'},{'\xa5','\x7d'}, + {'\xa5','\x7c'},{'\x00','\x00'},{'\xa6','\x5f'},{'\xa6','\x5e'},{'\xc9','\xc7'}, + {'\xa6','\x5d'},{'\xc9','\xc6'},{'\x86','\xb5'},{'\x93','\x6f'},{'\xa7','\x79'}, + {'\xca','\xa9'},{'\x00','\x00'},{'\xca','\xa8'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa7','\x77'},{'\xa7','\x7a'},{'\x00','\x00'},{'\x85','\xbd'},{'\xca','\xa7'}, + {'\x99','\x5e'},{'\xa7','\x78'},{'\x83','\x46'},{'\x92','\x43'},{'\x92','\xf6'}, + {'\x84','\xcf'},{'\x8d','\xca'},{'\x00','\x00'},{'\xcb','\xf0'},{'\x00','\x00'}, + {'\xcb','\xf1'},{'\xa9','\x54'},{'\x9d','\x56'},{'\x00','\x00'},{'\x83','\xf6'}, + {'\x86','\xb6'},{'\xab','\xaa'},{'\x81','\xb6'},{'\xd1','\x48'},{'\xd1','\x49'}, + {'\xae','\x45'},{'\xae','\x46'},{'\x00','\x00'},{'\x85','\xbe'},{'\xd4','\xac'}, + {'\xb0','\xe9'},{'\xb0','\xeb'},{'\xd4','\xab'},{'\xb0','\xea'},{'\xd8','\x7c'}, + {'\xb3','\xf2'},{'\x00','\x00'},{'\x92','\xb5'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb6','\xe9'},{'\xb6','\xea'},{'\xdc','\xe1'},{'\x99','\x5f'},{'\xb9','\xcf'}, + {'\x00','\x00'},{'\xb9','\xce'},{'\x00','\x00'},{'\xe5','\x49'},{'\xe9','\x48'}, + {'\xe9','\x47'},{'\x99','\x60'},{'\xf9','\x6b'},{'\xa4','\x67'},{'\xc9','\x59'}, + {'\x00','\x00'},{'\xc9','\x6e'},{'\xc9','\x6f'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x94','\x65'},{'\x92','\x42'},{'\xa6','\x62'},{'\xa6','\x66'},{'\xc9','\xc9'}, + {'\x00','\x00'},{'\xa6','\x64'},{'\xa6','\x63'},{'\xc9','\xc8'},{'\xa6','\x65'}, + {'\xa6','\x61'},{'\x00','\x00'},{'\x99','\x61'},{'\xa6','\x60'},{'\xc9','\xca'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x94','\x66'},{'\x94','\x67'},{'\x8a','\xbf'}, + {'\x84','\xd1'},{'\xa7','\xa6'},{'\x00','\x00'},{'\x99','\x62'},{'\xa7','\xa3'}, + {'\x99','\x63'},{'\xa7','\x7d'},{'\xca','\xaa'},{'\x95','\xb5'},{'\x99','\x64'}, + {'\x00','\x00'},{'\xca','\xab'},{'\xfb','\xe7'},{'\xa7','\xa1'},{'\x00','\x00'}, + {'\xca','\xad'},{'\xa7','\x7b'},{'\xca','\xae'},{'\xca','\xac'},{'\xa7','\x7e'}, + {'\xa7','\xa2'},{'\xa7','\xa5'},{'\xa7','\xa4'},{'\xa7','\x7c'},{'\xca','\xaf'}, + {'\x00','\x00'},{'\xfe','\x6f'},{'\x00','\x00'},{'\x00','\x00'},{'\x85','\xc0'}, + {'\x00','\x00'},{'\x81','\xb7'},{'\x83','\xf7'},{'\x88','\xd1'},{'\x8b','\x6f'}, + {'\x8d','\x52'},{'\x85','\xc1'},{'\x87','\xb6'},{'\x87','\xb7'},{'\xa9','\x59'}, + {'\xcb','\xfe'},{'\x00','\x00'},{'\xa9','\x5b'},{'\x81','\xb8'},{'\xa9','\x5a'}, + {'\xfb','\xe9'},{'\xcc','\x40'},{'\xa9','\x58'},{'\xa9','\x57'},{'\xcb','\xf5'}, + {'\x00','\x00'},{'\xcb','\xf4'},{'\x00','\x00'},{'\xcb','\xf2'},{'\xcb','\xf7'}, + {'\xcb','\xf6'},{'\xcb','\xf3'},{'\xcb','\xfc'},{'\xcb','\xfd'},{'\xcb','\xfa'}, + {'\xcb','\xf8'},{'\xa9','\x56'},{'\x00','\x00'},{'\x00','\x00'},{'\xfb','\xe8'}, + {'\xcb','\xfb'},{'\xa9','\x5c'},{'\xcc','\x41'},{'\x99','\x66'},{'\x81','\xb9'}, + {'\xcb','\xf9'},{'\x00','\x00'},{'\xab','\xab'},{'\xa9','\x55'},{'\x8b','\x6e'}, + {'\x81','\xba'},{'\x8f','\xb8'},{'\x00','\x00'},{'\x94','\x68'},{'\x81','\xbb'}, + {'\x99','\x67'},{'\xab','\xac'},{'\xce','\x54'},{'\x99','\x68'},{'\x00','\x00'}, + {'\xce','\x5a'},{'\x99','\x69'},{'\x00','\x00'},{'\x8a','\xc0'},{'\xab','\xb2'}, + {'\xce','\x58'},{'\xce','\x5e'},{'\x00','\x00'},{'\xce','\x55'},{'\xce','\x59'}, + {'\xce','\x5b'},{'\xce','\x5d'},{'\xce','\x57'},{'\x99','\x6a'},{'\xce','\x56'}, + {'\xce','\x51'},{'\xce','\x52'},{'\xab','\xad'},{'\x81','\xbc'},{'\xab','\xaf'}, + {'\xab','\xae'},{'\xce','\x53'},{'\xce','\x5c'},{'\x88','\xd0'},{'\x8d','\xb6'}, + {'\x00','\x00'},{'\x83','\xf8'},{'\x94','\x6a'},{'\x86','\xb8'},{'\x81','\xbd'}, + {'\x8d','\xcb'},{'\xab','\xb1'},{'\x00','\x00'},{'\x94','\x6b'},{'\x00','\x00'}, + {'\x8e','\x42'},{'\x94','\x69'},{'\x81','\xbe'},{'\xce','\x50'},{'\xd1','\x53'}, + {'\x00','\x00'},{'\xd1','\x52'},{'\xd1','\x57'},{'\xd1','\x4e'},{'\x99','\x6b'}, + {'\xd1','\x51'},{'\xd1','\x50'},{'\x99','\x6c'},{'\xd1','\x54'},{'\x81','\xbf'}, + {'\xd1','\x58'},{'\xae','\x47'},{'\xae','\x4a'},{'\x99','\x6d'},{'\x00','\x00'}, + {'\xd1','\x4f'},{'\xd1','\x55'},{'\x81','\xc0'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xae','\x49'},{'\xd1','\x4a'},{'\x00','\x00'},{'\xab','\xb0'},{'\xd4','\xba'}, + {'\xd1','\x56'},{'\x00','\x00'},{'\xd1','\x4d'},{'\x81','\xc1'},{'\xae','\x48'}, + {'\xd1','\x4c'},{'\x94','\x6c'},{'\xfe','\x49'},{'\x85','\xc2'},{'\x89','\xce'}, + {'\x84','\xd3'},{'\x00','\x00'},{'\xd4','\xb1'},{'\xfb','\xec'},{'\x99','\x6e'}, + {'\xb0','\xec'},{'\xb0','\xf0'},{'\xd4','\xc1'},{'\xd4','\xaf'},{'\xd4','\xbd'}, + {'\xb0','\xf1'},{'\xd4','\xbf'},{'\xfb','\xeb'},{'\xd4','\xc5'},{'\x00','\x00'}, + {'\xd4','\xc9'},{'\x00','\x00'},{'\x00','\x00'},{'\xd4','\xc0'},{'\xd4','\xb4'}, + {'\xd4','\xbc'},{'\x81','\xc2'},{'\xd4','\xca'},{'\xd4','\xc8'},{'\xd4','\xbe'}, + {'\xd4','\xb9'},{'\xd4','\xb2'},{'\xd8','\xa6'},{'\xd4','\xb0'},{'\xb0','\xf5'}, + {'\xd4','\xb7'},{'\xb0','\xf6'},{'\xb0','\xf2'},{'\xd4','\xad'},{'\xd4','\xc3'}, + {'\xd4','\xb5'},{'\x99','\x6f'},{'\x00','\x00'},{'\xd4','\xb3'},{'\xd4','\xc6'}, + {'\xb0','\xf3'},{'\x95','\x4a'},{'\xd4','\xcc'},{'\xb0','\xed'},{'\xb0','\xef'}, + {'\xd4','\xbb'},{'\xd4','\xb6'},{'\xae','\x4b'},{'\xb0','\xee'},{'\xd4','\xb8'}, + {'\xd4','\xc7'},{'\xd4','\xcb'},{'\xd4','\xc2'},{'\x00','\x00'},{'\xd4','\xc4'}, + {'\x86','\xb9'},{'\x99','\x70'},{'\x00','\x00'},{'\xd4','\xae'},{'\x87','\xb8'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xd8','\xa1'},{'\x00','\x00'}, + {'\xd8','\xaa'},{'\xd8','\xa9'},{'\xb3','\xfa'},{'\xd8','\xa2'},{'\x00','\x00'}, + {'\xb3','\xfb'},{'\xb3','\xf9'},{'\x99','\x71'},{'\xd8','\xa4'},{'\xb3','\xf6'}, + {'\xd8','\xa8'},{'\xfb','\xef'},{'\xd8','\xa3'},{'\xd8','\xa5'},{'\xd8','\x7d'}, + {'\xb3','\xf4'},{'\x00','\x00'},{'\xd8','\xb2'},{'\xd8','\xb1'},{'\xd8','\xae'}, + {'\xb3','\xf3'},{'\xb3','\xf7'},{'\xb3','\xf8'},{'\xd1','\x4b'},{'\xd8','\xab'}, + {'\xb3','\xf5'},{'\xb0','\xf4'},{'\xd8','\xad'},{'\xd8','\x7e'},{'\xd8','\xb0'}, + {'\xd8','\xaf'},{'\xfb','\xea'},{'\xd8','\xb3'},{'\x00','\x00'},{'\xdc','\xef'}, + {'\x00','\x00'},{'\xd8','\xac'},{'\x94','\x59'},{'\x93','\xe9'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x81','\xc3'},{'\x00','\x00'},{'\x00','\x00'},{'\x99','\x72'}, + {'\xd8','\xa7'},{'\xdc','\xe7'},{'\xb6','\xf4'},{'\xb6','\xf7'},{'\xb6','\xf2'}, + {'\xdc','\xe6'},{'\xdc','\xea'},{'\xdc','\xe5'},{'\x00','\x00'},{'\xb6','\xec'}, + {'\xb6','\xf6'},{'\xdc','\xe2'},{'\xb6','\xf0'},{'\xdc','\xe9'},{'\x00','\x00'}, + {'\xb6','\xee'},{'\xb6','\xed'},{'\xdc','\xec'},{'\xb6','\xef'},{'\xdc','\xee'}, + {'\x99','\x73'},{'\xdc','\xeb'},{'\xb6','\xeb'},{'\x99','\x74'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xb6','\xf5'},{'\xdc','\xf0'},{'\xdc','\xe4'},{'\xdc','\xed'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xdc','\xe3'},{'\x95','\xcd'},{'\x00','\x00'}, + {'\xb6','\xf1'},{'\x81','\xc4'},{'\xb6','\xf3'},{'\x00','\x00'},{'\xdc','\xe8'}, + {'\x94','\x6d'},{'\xdc','\xf1'},{'\x95','\x62'},{'\x99','\x75'},{'\xe1','\x5d'}, + {'\xb9','\xd0'},{'\xe1','\x63'},{'\x00','\x00'},{'\x00','\x00'},{'\xb9','\xd5'}, + {'\xe1','\x5f'},{'\xe1','\x66'},{'\xe1','\x57'},{'\xb9','\xd7'},{'\xb9','\xd1'}, + {'\xe1','\x5c'},{'\xbc','\x55'},{'\xe1','\x5b'},{'\xe1','\x64'},{'\xb9','\xd2'}, + {'\x00','\x00'},{'\xb9','\xd6'},{'\xe1','\x5a'},{'\xe1','\x60'},{'\xe1','\x65'}, + {'\xe1','\x56'},{'\xb9','\xd4'},{'\xe1','\x5e'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xe1','\x62'},{'\xe1','\x68'},{'\xe1','\x58'},{'\xe1','\x61'},{'\x81','\xc5'}, + {'\xb9','\xd3'},{'\xe1','\x67'},{'\x00','\x00'},{'\x00','\x00'},{'\x93','\x5e'}, + {'\xe1','\x59'},{'\x89','\xf5'},{'\x81','\xc6'},{'\x00','\x00'},{'\xbc','\x59'}, + {'\xe5','\x4b'},{'\xbc','\x57'},{'\xbc','\x56'},{'\xe5','\x4d'},{'\xe5','\x52'}, + {'\x00','\x00'},{'\xe5','\x4e'},{'\x00','\x00'},{'\xe5','\x51'},{'\xbc','\x5c'}, + {'\x99','\x76'},{'\xbe','\xa5'},{'\xbc','\x5b'},{'\x99','\x77'},{'\xe5','\x4a'}, + {'\xe5','\x50'},{'\x00','\x00'},{'\xbc','\x5a'},{'\xe5','\x4f'},{'\x99','\x78'}, + {'\xe5','\x4c'},{'\x81','\xc7'},{'\xbc','\x58'},{'\x00','\x00'},{'\x99','\x79'}, + {'\x99','\x7a'},{'\x00','\x00'},{'\x81','\xc8'},{'\x94','\x6e'},{'\xe9','\x4d'}, + {'\xf9','\xd9'},{'\xe9','\x4f'},{'\xe9','\x4a'},{'\xbe','\xc1'},{'\xe9','\x4c'}, + {'\x00','\x00'},{'\xbe','\xc0'},{'\xe9','\x4e'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xbe','\xc3'},{'\xe9','\x50'},{'\xbe','\xc2'},{'\xe9','\x49'},{'\xe9','\x4b'}, + {'\x92','\x5c'},{'\x99','\x7b'},{'\x92','\xee'},{'\x00','\x00'},{'\xc0','\xa5'}, + {'\xec','\xcc'},{'\x99','\x7c'},{'\xc0','\xa4'},{'\xec','\xcd'},{'\xc0','\xa3'}, + {'\xec','\xcb'},{'\xc0','\xa2'},{'\xec','\xca'},{'\x94','\x6f'},{'\xc2','\x53'}, + {'\xc2','\x52'},{'\xf1','\xf6'},{'\xf1','\xf8'},{'\xfb','\xf0'},{'\xf1','\xf7'}, + {'\xc3','\x61'},{'\xc3','\x62'},{'\x99','\x7d'},{'\x00','\x00'},{'\xc3','\x63'}, + {'\xf4','\x42'},{'\xc4','\x5b'},{'\x81','\xc9'},{'\x00','\x00'},{'\xf7','\xd3'}, + {'\xf7','\xd2'},{'\xc5','\xf2'},{'\x00','\x00'},{'\xa4','\x68'},{'\xa4','\xd0'}, + {'\x00','\x00'},{'\x83','\x47'},{'\xa7','\xa7'},{'\x8a','\x52'},{'\x92','\x45'}, + {'\x93','\xb3'},{'\x84','\xea'},{'\xce','\x5f'},{'\x00','\x00'},{'\x84','\xd4'}, + {'\x82','\x41'},{'\x00','\x00'},{'\xb3','\xfc'},{'\xb3','\xfd'},{'\x81','\xca'}, + {'\xdc','\xf2'},{'\xb9','\xd8'},{'\xe1','\x69'},{'\xe5','\x53'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x81','\xcb'},{'\xc9','\x5a'},{'\x84','\x7a'},{'\x99','\x7e'}, + {'\xca','\xb0'},{'\x84','\xc2'},{'\x00','\x00'},{'\x93','\xc4'},{'\xc6','\xca'}, + {'\x81','\xcc'},{'\xcc','\x42'},{'\xce','\x60'},{'\xd1','\x59'},{'\xae','\x4c'}, + {'\x81','\xcd'},{'\x99','\xa1'},{'\xf1','\xf9'},{'\x00','\x00'},{'\xc4','\xdc'}, + {'\xa4','\x69'},{'\xa5','\x7e'},{'\xc9','\x70'},{'\x81','\xce'},{'\xa6','\x67'}, + {'\xa6','\x68'},{'\x81','\xcf'},{'\xa9','\x5d'},{'\x9d','\x58'},{'\x00','\x00'}, + {'\x83','\xfa'},{'\xb0','\xf7'},{'\x00','\x00'},{'\xb9','\xda'},{'\x00','\x00'}, + {'\xb9','\xdb'},{'\xb9','\xd9'},{'\x00','\x00'},{'\xa4','\x6a'},{'\x00','\x00'}, + {'\xa4','\xd1'},{'\xa4','\xd3'},{'\xa4','\xd2'},{'\xc9','\x5b'},{'\xa4','\xd4'}, + {'\xa5','\xa1'},{'\xc9','\x71'},{'\x00','\x00'},{'\xa5','\xa2'},{'\x82','\xb5'}, + {'\x00','\x00'},{'\x89','\xb3'},{'\x00','\x00'},{'\x00','\x00'},{'\xa6','\x69'}, + {'\xa6','\x6a'},{'\x83','\x48'},{'\x86','\xbc'},{'\x00','\x00'},{'\xc9','\xcb'}, + {'\x00','\x00'},{'\xa7','\xa8'},{'\x00','\x00'},{'\xca','\xb1'},{'\x86','\xbd'}, + {'\x83','\x6b'},{'\x00','\x00'},{'\xa9','\x61'},{'\xcc','\x43'},{'\x00','\x00'}, + {'\xa9','\x5f'},{'\xa9','\x60'},{'\xa9','\x5e'},{'\xd1','\x5a'},{'\x88','\xd2'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xab','\xb6'},{'\xab','\xb5'},{'\xab','\xb7'}, + {'\xab','\xb4'},{'\x00','\x00'},{'\xce','\x61'},{'\xa9','\x62'},{'\xab','\xb3'}, + {'\x87','\xf2'},{'\xae','\x4d'},{'\xae','\x4e'},{'\x00','\x00'},{'\xae','\x4f'}, + {'\x82','\xb6'},{'\xd4','\xcd'},{'\x82','\xb7'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb3','\xfe'},{'\xd8','\xb4'},{'\xb0','\xf8'},{'\x82','\xb8'},{'\x00','\x00'}, + {'\x85','\xc4'},{'\x00','\x00'},{'\xb6','\xf8'},{'\x92','\xe6'},{'\xb9','\xdd'}, + {'\xb9','\xdc'},{'\xe1','\x6a'},{'\x82','\xb9'},{'\xbc','\x5d'},{'\xbe','\xc4'}, + {'\x00','\x00'},{'\xef','\xc0'},{'\xf6','\xda'},{'\xf7','\xd4'},{'\xa4','\x6b'}, + {'\xa5','\xa3'},{'\xfe','\x66'},{'\xa5','\xa4'},{'\xc9','\xd1'},{'\xa6','\x6c'}, + {'\xa6','\x6f'},{'\x00','\x00'},{'\xc9','\xcf'},{'\xc9','\xcd'},{'\xa6','\x6e'}, + {'\xc9','\xd0'},{'\xc9','\xd2'},{'\xc9','\xcc'},{'\xa6','\x71'},{'\xa6','\x70'}, + {'\xa6','\x6d'},{'\xa6','\x6b'},{'\xc9','\xce'},{'\x83','\x49'},{'\x83','\xfc'}, + {'\x85','\xc5'},{'\x99','\xa2'},{'\xa7','\xb3'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xa7','\xb0'},{'\xca','\xb6'},{'\xca','\xb9'},{'\xca','\xb8'},{'\x00','\x00'}, + {'\xa7','\xaa'},{'\xa7','\xb2'},{'\x99','\xa3'},{'\x00','\x00'},{'\xa7','\xaf'}, + {'\xca','\xb5'},{'\xca','\xb3'},{'\xa7','\xae'},{'\x99','\xa4'},{'\x82','\xba'}, + {'\x00','\x00'},{'\xa7','\xa9'},{'\xa7','\xac'},{'\x99','\xa5'},{'\xca','\xb4'}, + {'\xca','\xbb'},{'\xca','\xb7'},{'\xa7','\xad'},{'\xa7','\xb1'},{'\xa7','\xb4'}, + {'\xca','\xb2'},{'\xca','\xba'},{'\xa7','\xab'},{'\x87','\xbb'},{'\x86','\xbe'}, + {'\x8d','\xdb'},{'\x95','\xa5'},{'\x00','\x00'},{'\xa9','\x67'},{'\xa9','\x6f'}, + {'\x99','\xa6'},{'\xcc','\x4f'},{'\xcc','\x48'},{'\xa9','\x70'},{'\xcc','\x53'}, + {'\xcc','\x44'},{'\xcc','\x4b'},{'\xfb','\xf1'},{'\x99','\xa7'},{'\xa9','\x66'}, + {'\xcc','\x45'},{'\xa9','\x64'},{'\xcc','\x4c'},{'\xcc','\x50'},{'\xa9','\x63'}, + {'\x9b','\x40'},{'\xcc','\x51'},{'\xcc','\x4a'},{'\x00','\x00'},{'\xcc','\x4d'}, + {'\x99','\xa8'},{'\xa9','\x72'},{'\xa9','\x69'},{'\xcc','\x54'},{'\xcc','\x52'}, + {'\x93','\xfc'},{'\xa9','\x6e'},{'\xa9','\x6c'},{'\xcc','\x49'},{'\xa9','\x6b'}, + {'\xcc','\x47'},{'\xcc','\x46'},{'\xa9','\x6a'},{'\xa9','\x68'},{'\xa9','\x71'}, + {'\xa9','\x6d'},{'\xa9','\x65'},{'\x00','\x00'},{'\xcc','\x4e'},{'\x82','\xbb'}, + {'\xab','\xb9'},{'\xfb','\xf2'},{'\xab','\xc0'},{'\xce','\x6f'},{'\xab','\xb8'}, + {'\xce','\x67'},{'\xce','\x63'},{'\x00','\x00'},{'\xce','\x73'},{'\xce','\x62'}, + {'\x00','\x00'},{'\xab','\xbb'},{'\xce','\x6c'},{'\xab','\xbe'},{'\xab','\xc1'}, + {'\x00','\x00'},{'\xab','\xbc'},{'\xce','\x70'},{'\xab','\xbf'},{'\x82','\xbc'}, + {'\xae','\x56'},{'\xce','\x76'},{'\xce','\x64'},{'\x99','\xa9'},{'\x99','\xaa'}, + {'\xce','\x66'},{'\xce','\x6d'},{'\xce','\x71'},{'\xce','\x75'},{'\xce','\x72'}, + {'\xce','\x6b'},{'\xce','\x6e'},{'\x99','\xab'},{'\x95','\xc0'},{'\xce','\x68'}, + {'\xab','\xc3'},{'\xce','\x6a'},{'\xce','\x69'},{'\xce','\x74'},{'\xab','\xba'}, + {'\xce','\x65'},{'\xab','\xc2'},{'\x99','\xac'},{'\xab','\xbd'},{'\x83','\xfb'}, + {'\x8d','\xcc'},{'\x87','\xbd'},{'\x87','\xbc'},{'\x90','\x55'},{'\xae','\x5c'}, + {'\xd1','\x62'},{'\x99','\xad'},{'\xae','\x5b'},{'\x99','\xae'},{'\x00','\x00'}, + {'\xd1','\x60'},{'\x00','\x00'},{'\xae','\x50'},{'\x99','\xaf'},{'\xae','\x55'}, + {'\x00','\x00'},{'\xd1','\x5f'},{'\xd1','\x5c'},{'\xd1','\x61'},{'\xae','\x51'}, + {'\xd1','\x5b'},{'\x82','\xbd'},{'\xae','\x54'},{'\xae','\x52'},{'\x00','\x00'}, + {'\xd1','\x63'},{'\xae','\x53'},{'\xae','\x57'},{'\x99','\xb0'},{'\x00','\x00'}, + {'\xae','\x58'},{'\x99','\xb1'},{'\xae','\x5a'},{'\x00','\x00'},{'\x99','\xb2'}, + {'\x00','\x00'},{'\xae','\x59'},{'\x99','\xb3'},{'\x99','\xb4'},{'\x99','\xb5'}, + {'\xd1','\x5d'},{'\xd1','\x5e'},{'\x92','\xbc'},{'\x00','\x00'},{'\x83','\xb1'}, + {'\x84','\xd5'},{'\xd1','\x64'},{'\x87','\xb9'},{'\xd4','\xd4'},{'\xb0','\xf9'}, + {'\xd8','\xc2'},{'\xd4','\xd3'},{'\xd4','\xe6'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb1','\x40'},{'\x99','\xb6'},{'\xd4','\xe4'},{'\x00','\x00'},{'\xb0','\xfe'}, + {'\xb0','\xfa'},{'\xd4','\xed'},{'\xd4','\xdd'},{'\xd4','\xe0'},{'\x99','\xb7'}, + {'\xb1','\x43'},{'\xd4','\xea'},{'\xd4','\xe2'},{'\xb0','\xfb'},{'\xb1','\x44'}, + {'\x00','\x00'},{'\xd4','\xe7'},{'\xd4','\xe5'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xd4','\xd6'},{'\xd4','\xeb'},{'\xd4','\xdf'},{'\xd4','\xda'},{'\x99','\xb8'}, + {'\xd4','\xd0'},{'\xd4','\xec'},{'\xd4','\xdc'},{'\xd4','\xcf'},{'\x99','\xb9'}, + {'\xb1','\x42'},{'\xd4','\xe1'},{'\xd4','\xee'},{'\xd4','\xde'},{'\xd4','\xd2'}, + {'\xd4','\xd7'},{'\xd4','\xce'},{'\x99','\xba'},{'\xb1','\x41'},{'\x95','\x63'}, + {'\xd4','\xdb'},{'\xd4','\xd8'},{'\xb0','\xfc'},{'\xd4','\xd1'},{'\x99','\xbb'}, + {'\xd4','\xe9'},{'\xb0','\xfd'},{'\x99','\xbc'},{'\xd4','\xd9'},{'\xd4','\xd5'}, + {'\x99','\xbd'},{'\x00','\x00'},{'\xd4','\xe8'},{'\x99','\xbe'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x89','\xcf'},{'\x87','\xba'},{'\x8a','\xc1'},{'\xb4','\x40'}, + {'\xd8','\xbb'},{'\x99','\xbf'},{'\xd8','\xb8'},{'\xd8','\xc9'},{'\xd8','\xbd'}, + {'\xd8','\xca'},{'\x99','\xc0'},{'\xb4','\x42'},{'\x00','\x00'},{'\x99','\xc1'}, + {'\x99','\xc2'},{'\xd8','\xc6'},{'\xd8','\xc3'},{'\x00','\x00'},{'\x99','\xc3'}, + {'\x00','\x00'},{'\x99','\xc4'},{'\x00','\x00'},{'\xd8','\xc4'},{'\xd8','\xc7'}, + {'\xd8','\xcb'},{'\x00','\x00'},{'\xd4','\xe3'},{'\xd8','\xcd'},{'\xdd','\x47'}, + {'\x99','\xc5'},{'\xb4','\x43'},{'\xd8','\xce'},{'\xd8','\xb6'},{'\xd8','\xc0'}, + {'\xfe','\x78'},{'\xd8','\xc5'},{'\x00','\x00'},{'\x99','\xc6'},{'\xb4','\x41'}, + {'\xb4','\x44'},{'\xd8','\xcc'},{'\xd8','\xcf'},{'\xd8','\xba'},{'\xd8','\xb7'}, + {'\x99','\xc7'},{'\x99','\xc8'},{'\xd8','\xb9'},{'\x00','\x00'},{'\x9c','\x70'}, + {'\xd8','\xbe'},{'\xd8','\xbc'},{'\xb4','\x45'},{'\x00','\x00'},{'\xd8','\xc8'}, + {'\x82','\xbe'},{'\x99','\xc9'},{'\xd8','\xbf'},{'\x00','\x00'},{'\xd8','\xc1'}, + {'\xd8','\xb5'},{'\xdc','\xfa'},{'\xdc','\xf8'},{'\xb7','\x42'},{'\xb7','\x40'}, + {'\xdd','\x43'},{'\xdc','\xf9'},{'\xdd','\x44'},{'\xdd','\x40'},{'\xdc','\xf7'}, + {'\xdd','\x46'},{'\xdc','\xf6'},{'\xdc','\xfd'},{'\xb6','\xfe'},{'\xb6','\xfd'}, + {'\xb6','\xfc'},{'\xdc','\xfb'},{'\xdd','\x41'},{'\xb6','\xf9'},{'\xb7','\x41'}, + {'\x99','\xca'},{'\xdc','\xf4'},{'\x00','\x00'},{'\xdc','\xfe'},{'\xdc','\xf3'}, + {'\xdc','\xfc'},{'\xb6','\xfa'},{'\xdd','\x42'},{'\xdc','\xf5'},{'\xb6','\xfb'}, + {'\xdd','\x45'},{'\x99','\xcb'},{'\x99','\xcc'},{'\x82','\xbf'},{'\x9d','\x67'}, + {'\x8e','\xe5'},{'\x99','\xcd'},{'\x89','\xd0'},{'\xe1','\x6e'},{'\xb9','\xe2'}, + {'\xb9','\xe1'},{'\xb9','\xe3'},{'\xe1','\x7a'},{'\xe1','\x70'},{'\xe1','\x76'}, + {'\xe1','\x6b'},{'\xe1','\x79'},{'\xe1','\x78'},{'\xe1','\x7c'},{'\xe1','\x75'}, + {'\xb9','\xde'},{'\xe1','\x74'},{'\xb9','\xe4'},{'\x99','\xce'},{'\xe1','\x6d'}, + {'\xb9','\xdf'},{'\x00','\x00'},{'\xe1','\x7b'},{'\xb9','\xe0'},{'\xe1','\x6f'}, + {'\xe1','\x72'},{'\xe1','\x77'},{'\xe1','\x71'},{'\xe1','\x6c'},{'\x00','\x00'}, + {'\x99','\xcf'},{'\x82','\xc0'},{'\xfb','\x67'},{'\xe1','\x73'},{'\xe5','\x55'}, + {'\xbc','\x61'},{'\xe5','\x58'},{'\xe5','\x57'},{'\xe5','\x5a'},{'\xe5','\x5c'}, + {'\xf9','\xdc'},{'\xbc','\x5f'},{'\x00','\x00'},{'\xe5','\x56'},{'\x99','\xd0'}, + {'\xe5','\x54'},{'\x00','\x00'},{'\xe5','\x5d'},{'\xe5','\x5b'},{'\xe5','\x59'}, + {'\x00','\x00'},{'\xe5','\x5f'},{'\x00','\x00'},{'\xe5','\x5e'},{'\xbc','\x63'}, + {'\xbc','\x5e'},{'\x00','\x00'},{'\xbc','\x60'},{'\xbc','\x62'},{'\x99','\xd1'}, + {'\x00','\x00'},{'\xe5','\x60'},{'\xe9','\x57'},{'\x99','\xd2'},{'\x00','\x00'}, + {'\xe9','\x56'},{'\xe9','\x55'},{'\x99','\xd3'},{'\xe9','\x58'},{'\xe9','\x51'}, + {'\x00','\x00'},{'\xe9','\x52'},{'\xe9','\x5a'},{'\xe9','\x53'},{'\x00','\x00'}, + {'\xbe','\xc5'},{'\xe9','\x5c'},{'\x99','\xd4'},{'\xe9','\x5b'},{'\xe9','\x54'}, + {'\x92','\xef'},{'\xec','\xd1'},{'\xc0','\xa8'},{'\xec','\xcf'},{'\xec','\xd4'}, + {'\xec','\xd3'},{'\xe9','\x59'},{'\x00','\x00'},{'\xc0','\xa7'},{'\x99','\xd5'}, + {'\xec','\xd2'},{'\xec','\xce'},{'\xec','\xd6'},{'\xec','\xd5'},{'\xc0','\xa6'}, + {'\x00','\x00'},{'\xec','\xd0'},{'\x00','\x00'},{'\xbe','\xc6'},{'\x00','\x00'}, + {'\x82','\xc1'},{'\x89','\xd1'},{'\xc2','\x54'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xef','\xc1'},{'\xf1','\xfa'},{'\xf1','\xfb'},{'\xf1','\xfc'}, + {'\xc4','\x5c'},{'\x99','\xd6'},{'\x00','\x00'},{'\xc4','\x5d'},{'\x99','\xd7'}, + {'\xf4','\x43'},{'\x99','\xd8'},{'\xf5','\xc8'},{'\xf5','\xc7'},{'\x00','\x00'}, + {'\x99','\xd9'},{'\xf6','\xdb'},{'\xf6','\xdc'},{'\xf7','\xd5'},{'\xf8','\xa7'}, + {'\x99','\xda'},{'\xa4','\x6c'},{'\xa4','\x6d'},{'\x00','\x00'},{'\xa4','\x6e'}, + {'\xa4','\xd5'},{'\xa5','\xa5'},{'\xc9','\xd3'},{'\xa6','\x72'},{'\xa6','\x73'}, + {'\x83','\xb2'},{'\xa7','\xb7'},{'\xa7','\xb8'},{'\xa7','\xb6'},{'\xa7','\xb5'}, + {'\x00','\x00'},{'\xa9','\x73'},{'\x00','\x00'},{'\x00','\x00'},{'\xcc','\x55'}, + {'\xa9','\x75'},{'\xa9','\x74'},{'\xcc','\x56'},{'\x88','\xd4'},{'\x00','\x00'}, + {'\x99','\xdb'},{'\xab','\xc4'},{'\x8c','\xcb'},{'\xae','\x5d'},{'\xd1','\x65'}, + {'\xa0','\x41'},{'\xd4','\xf0'},{'\x00','\x00'},{'\xb1','\x45'},{'\xb4','\x47'}, + {'\xd4','\xef'},{'\xb4','\x46'},{'\x99','\xdc'},{'\xb9','\xe5'},{'\x99','\xdd'}, + {'\xe1','\x7d'},{'\xbe','\xc7'},{'\x00','\x00'},{'\xc0','\xa9'},{'\xec','\xd7'}, + {'\x99','\xde'},{'\xc4','\x5e'},{'\x00','\x00'},{'\xc5','\x70'},{'\xc6','\xcb'}, + {'\xc9','\x72'},{'\x99','\xdf'},{'\xa5','\xa6'},{'\xc9','\x73'},{'\xa6','\x76'}, + {'\x00','\x00'},{'\xa6','\x74'},{'\xa6','\x75'},{'\xa6','\x77'},{'\x00','\x00'}, + {'\xa7','\xba'},{'\xa7','\xb9'},{'\x93','\xfd'},{'\xca','\xbc'},{'\xa7','\xbb'}, + {'\x99','\xe0'},{'\x00','\x00'},{'\xca','\xbd'},{'\xcc','\x57'},{'\x00','\x00'}, + {'\xcc','\x58'},{'\x9a','\x40'},{'\xa9','\x76'},{'\xa9','\x78'},{'\xa9','\x7a'}, + {'\xa9','\x77'},{'\xa9','\x7b'},{'\xa9','\x79'},{'\x8b','\xf3'},{'\x86','\xbf'}, + {'\x92','\xd4'},{'\x8b','\x70'},{'\x87','\xbf'},{'\xab','\xc8'},{'\xab','\xc5'}, + {'\xab','\xc7'},{'\xab','\xc9'},{'\xab','\xc6'},{'\xd1','\x66'},{'\xce','\x77'}, + {'\x00','\x00'},{'\x88','\xd6'},{'\x90','\xb3'},{'\xd1','\x68'},{'\xd1','\x67'}, + {'\xae','\x63'},{'\x00','\x00'},{'\xae','\x5f'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xae','\x60'},{'\xae','\x62'},{'\xae','\x64'},{'\xae','\x61'},{'\x9d','\x68'}, + {'\xae','\x66'},{'\xae','\x65'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x87','\xbe'},{'\x87','\x59'},{'\xb1','\x4a'},{'\xd4','\xf2'},{'\xd4','\xf1'}, + {'\xb1','\x49'},{'\xfc','\x43'},{'\xb1','\x48'},{'\xb1','\x47'},{'\xb1','\x4b'}, + {'\xb1','\x46'},{'\x00','\x00'},{'\x82','\xc2'},{'\xd8','\xd5'},{'\xd8','\xd2'}, + {'\xb4','\x49'},{'\xd8','\xd1'},{'\xd8','\xd6'},{'\x00','\x00'},{'\xb4','\x4b'}, + {'\xd8','\xd4'},{'\xb4','\x48'},{'\xb4','\x4a'},{'\xd8','\xd3'},{'\x9a','\x55'}, + {'\xdd','\x48'},{'\x9a','\x56'},{'\xdd','\x49'},{'\xdd','\x4a'},{'\x00','\x00'}, + {'\x92','\x69'},{'\x00','\x00'},{'\x86','\xc0'},{'\xb9','\xe6'},{'\xb9','\xee'}, + {'\xe1','\x7e'},{'\xb9','\xe8'},{'\xb9','\xec'},{'\xe1','\xa1'},{'\xb9','\xed'}, + {'\xb9','\xe9'},{'\xb9','\xea'},{'\xb9','\xe7'},{'\xb9','\xeb'},{'\xbc','\x66'}, + {'\xd8','\xd0'},{'\xbc','\x67'},{'\xbc','\x65'},{'\x00','\x00'},{'\xbc','\x64'}, + {'\xe9','\x5d'},{'\xbe','\xc8'},{'\xec','\xd8'},{'\xec','\xd9'},{'\x82','\xc3'}, + {'\x00','\x00'},{'\xc3','\x64'},{'\xc4','\x5f'},{'\x00','\x00'},{'\xa4','\x6f'}, + {'\x86','\xc1'},{'\xa6','\x78'},{'\x84','\xd6'},{'\x88','\xd5'},{'\x00','\x00'}, + {'\x93','\x66'},{'\x86','\xba'},{'\x00','\x00'},{'\xab','\xca'},{'\x93','\x47'}, + {'\xd1','\x69'},{'\xae','\x67'},{'\x95','\x5b'},{'\x92','\xe2'},{'\xb1','\x4e'}, + {'\xb1','\x4d'},{'\xb1','\x4c'},{'\xb4','\x4c'},{'\xb4','\x4d'},{'\xd8','\xd7'}, + {'\xb9','\xef'},{'\xbe','\xc9'},{'\xa4','\x70'},{'\xc9','\x5c'},{'\xa4','\xd6'}, + {'\xc9','\x74'},{'\x82','\xc4'},{'\x86','\xe0'},{'\xc9','\xd4'},{'\xa6','\x79'}, + {'\x00','\x00'},{'\x86','\xb7'},{'\x00','\x00'},{'\xa9','\x7c'},{'\x00','\x00'}, + {'\x82','\xc5'},{'\x86','\xaf'},{'\x82','\xc6'},{'\xdd','\x4b'},{'\xfb','\xf3'}, + {'\x00','\x00'},{'\xa4','\x71'},{'\x9a','\x57'},{'\xa4','\xd7'},{'\xc9','\xd5'}, + {'\x00','\x00'},{'\x84','\xd0'},{'\xca','\xbe'},{'\x00','\x00'},{'\xca','\xbf'}, + {'\x00','\x00'},{'\xa7','\xbc'},{'\x82','\x59'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xd8','\xd8'},{'\xb4','\x4e'},{'\x00','\x00'},{'\xdd','\x4c'},{'\x89','\xd2'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc0','\xaa'},{'\xa4','\x72'},{'\xa4','\xa8'}, + {'\xa4','\xd8'},{'\xc9','\x75'},{'\xa5','\xa7'},{'\x86','\xe9'},{'\xa7','\xc0'}, + {'\xa7','\xbf'},{'\xa7','\xbd'},{'\xa7','\xbe'},{'\x87','\xc1'},{'\x00','\x00'}, + {'\xcc','\x59'},{'\xa9','\x7e'},{'\xa9','\xa1'},{'\xcc','\x5a'},{'\xa9','\x7d'}, + {'\x84','\x40'},{'\x83','\x57'},{'\xab','\xce'},{'\xce','\x78'},{'\xab','\xcd'}, + {'\xab','\xcb'},{'\xab','\xcc'},{'\xae','\x6a'},{'\xae','\x68'},{'\x00','\x00'}, + {'\x82','\xc7'},{'\xd1','\x6b'},{'\xae','\x69'},{'\xd1','\x6a'},{'\x00','\x00'}, + {'\xae','\x5e'},{'\xd4','\xf3'},{'\x00','\x00'},{'\x00','\x00'},{'\xb1','\x50'}, + {'\xb1','\x51'},{'\x8c','\x70'},{'\x00','\x00'},{'\xb1','\x4f'},{'\x86','\xc2'}, + {'\xb9','\xf0'},{'\xe1','\xa2'},{'\xbc','\x68'},{'\xbc','\x69'},{'\x89','\xd3'}, + {'\xe5','\x61'},{'\xc0','\xab'},{'\xef','\xc2'},{'\xef','\xc3'},{'\x00','\x00'}, + {'\xc4','\xdd'},{'\xf8','\xa8'},{'\xc9','\x4b'},{'\xa4','\xd9'},{'\x00','\x00'}, + {'\xa4','\x73'},{'\x00','\x00'},{'\xc9','\x77'},{'\xc9','\x76'},{'\x00','\x00'}, + {'\x94','\x70'},{'\x00','\x00'},{'\x9d','\x64'},{'\xa6','\x7a'},{'\xc9','\xd7'}, + {'\xc9','\xd8'},{'\xc9','\xd6'},{'\x00','\x00'},{'\xc9','\xd9'},{'\x89','\xd4'}, + {'\x00','\x00'},{'\x85','\xd7'},{'\x83','\xdb'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9a','\x58'},{'\xca','\xc7'},{'\x00','\x00'},{'\xca','\xc2'},{'\xca','\xc4'}, + {'\xca','\xc6'},{'\xca','\xc3'},{'\xa7','\xc4'},{'\xca','\xc0'},{'\x00','\x00'}, + {'\xca','\xc1'},{'\xa7','\xc1'},{'\xa7','\xc2'},{'\xca','\xc5'},{'\xca','\xc8'}, + {'\xa7','\xc3'},{'\xca','\xc9'},{'\x86','\xc4'},{'\x84','\x42'},{'\x83','\xb5'}, + {'\x82','\xc8'},{'\x84','\xd7'},{'\x83','\xb4'},{'\x82','\xc9'},{'\xcc','\x68'}, + {'\x9a','\x59'},{'\xcc','\x62'},{'\xcc','\x5d'},{'\xa9','\xa3'},{'\xcc','\x65'}, + {'\xcc','\x63'},{'\xcc','\x5c'},{'\xcc','\x69'},{'\xcc','\x6c'},{'\xcc','\x67'}, + {'\xcc','\x60'},{'\xa9','\xa5'},{'\xcc','\x66'},{'\xa9','\xa6'},{'\xcc','\x61'}, + {'\xcc','\x64'},{'\xcc','\x5b'},{'\xcc','\x5f'},{'\xcc','\x6b'},{'\xa9','\xa7'}, + {'\x00','\x00'},{'\xa9','\xa8'},{'\x00','\x00'},{'\xcc','\x5e'},{'\xcc','\x6a'}, + {'\xa9','\xa2'},{'\xa9','\xa4'},{'\x00','\x00'},{'\x82','\xca'},{'\x82','\xcb'}, + {'\x94','\x71'},{'\x8d','\xcd'},{'\x94','\x73'},{'\x8f','\xfc'},{'\x00','\x00'}, + {'\x82','\xcc'},{'\x9a','\x5a'},{'\x00','\x00'},{'\x8e','\xe6'},{'\x94','\x72'}, + {'\xce','\xab'},{'\xce','\xa4'},{'\xce','\xaa'},{'\xce','\xa3'},{'\xce','\xa5'}, + {'\xce','\x7d'},{'\xce','\x7b'},{'\x00','\x00'},{'\xce','\xac'},{'\xce','\xa9'}, + {'\xce','\x79'},{'\xfb','\xf5'},{'\xab','\xd0'},{'\xce','\xa7'},{'\xce','\xa8'}, + {'\x9d','\x71'},{'\xce','\xa6'},{'\xce','\x7c'},{'\xce','\x7a'},{'\xab','\xcf'}, + {'\xce','\xa2'},{'\xce','\x7e'},{'\x00','\x00'},{'\x00','\x00'},{'\xce','\xa1'}, + {'\xce','\xad'},{'\x94','\x50'},{'\x83','\xb3'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x8e','\xb4'},{'\x84','\x41'},{'\x8c','\xcd'},{'\x00','\x00'},{'\xae','\x6f'}, + {'\xfb','\xf6'},{'\xae','\x6e'},{'\x00','\x00'},{'\xd1','\x6c'},{'\xae','\x6b'}, + {'\xd1','\x6e'},{'\x95','\x5d'},{'\xae','\x70'},{'\xd1','\x6f'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xae','\x73'},{'\x82','\xcd'},{'\xae','\x71'},{'\xd1','\x70'}, + {'\xce','\xae'},{'\xd1','\x72'},{'\x82','\xce'},{'\xae','\x6d'},{'\x9d','\x69'}, + {'\xae','\x6c'},{'\x00','\x00'},{'\xd1','\x6d'},{'\xd1','\x71'},{'\xae','\x72'}, + {'\x8e','\xb3'},{'\x8d','\xce'},{'\x00','\x00'},{'\x00','\x00'},{'\xb1','\x53'}, + {'\xb1','\x52'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xd4','\xf5'}, + {'\xd4','\xf9'},{'\xd4','\xfb'},{'\xb1','\x54'},{'\xd4','\xfe'},{'\x9a','\x5b'}, + {'\xb1','\x58'},{'\xd5','\x41'},{'\x00','\x00'},{'\xb1','\x5a'},{'\x82','\xcf'}, + {'\xb1','\x56'},{'\xb1','\x5e'},{'\x82','\xd0'},{'\xb1','\x5b'},{'\xd4','\xf7'}, + {'\xb1','\x55'},{'\x00','\x00'},{'\xd4','\xf6'},{'\xd4','\xf4'},{'\xd5','\x43'}, + {'\xd4','\xf8'},{'\x00','\x00'},{'\xb1','\x57'},{'\xd5','\x42'},{'\xb1','\x5c'}, + {'\xd4','\xfd'},{'\xd4','\xfc'},{'\xb1','\x5d'},{'\xd4','\xfa'},{'\xb1','\x59'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9a','\x5c'},{'\x86','\xc3'},{'\xd5','\x44'}, + {'\x9a','\x5d'},{'\xd5','\x40'},{'\xd8','\xe7'},{'\xd8','\xee'},{'\xd8','\xe3'}, + {'\xb4','\x51'},{'\xd8','\xdf'},{'\xd8','\xef'},{'\xd8','\xd9'},{'\xd8','\xec'}, + {'\xd8','\xea'},{'\xd8','\xe4'},{'\x00','\x00'},{'\xd8','\xed'},{'\xd8','\xe6'}, + {'\x82','\xd1'},{'\xd8','\xde'},{'\xd8','\xf0'},{'\xd8','\xdc'},{'\xd8','\xe9'}, + {'\xd8','\xda'},{'\x00','\x00'},{'\xd8','\xf1'},{'\xfb','\xf7'},{'\xb4','\x52'}, + {'\x9a','\x5e'},{'\xd8','\xeb'},{'\xdd','\x4f'},{'\xd8','\xdd'},{'\xb4','\x4f'}, + {'\x00','\x00'},{'\xd8','\xe1'},{'\x00','\x00'},{'\xb4','\x50'},{'\xd8','\xe0'}, + {'\xd8','\xe5'},{'\x82','\xd2'},{'\x00','\x00'},{'\xd8','\xe2'},{'\x9a','\x5f'}, + {'\x95','\x65'},{'\x89','\xd5'},{'\xd8','\xe8'},{'\x00','\x00'},{'\x8d','\xdc'}, + {'\x82','\xd3'},{'\x8e','\x67'},{'\xdd','\x53'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xdd','\x56'},{'\xdd','\x4e'},{'\x00','\x00'},{'\xdd','\x50'}, + {'\x00','\x00'},{'\xdd','\x55'},{'\xdd','\x54'},{'\xb7','\x43'},{'\x00','\x00'}, + {'\xd8','\xdb'},{'\xdd','\x52'},{'\x82','\xd4'},{'\x00','\x00'},{'\xb7','\x44'}, + {'\x9a','\x60'},{'\xdd','\x4d'},{'\xdd','\x51'},{'\x82','\xd5'},{'\x82','\xd6'}, + {'\xfe','\x7e'},{'\x94','\x74'},{'\xe1','\xa9'},{'\x9d','\x7a'},{'\xe1','\xb0'}, + {'\xe1','\xa7'},{'\x9a','\x61'},{'\xe1','\xae'},{'\xe1','\xa5'},{'\xe1','\xad'}, + {'\xe1','\xb1'},{'\xe1','\xa4'},{'\xe1','\xa8'},{'\xe1','\xa3'},{'\x00','\x00'}, + {'\xb9','\xf1'},{'\x9a','\x62'},{'\xe1','\xa6'},{'\xb9','\xf2'},{'\xe1','\xac'}, + {'\xe1','\xab'},{'\xe1','\xaa'},{'\x93','\xfe'},{'\x82','\xd7'},{'\xe1','\xaf'}, + {'\xfb','\xf8'},{'\x00','\x00'},{'\x82','\xd8'},{'\x00','\x00'},{'\xe5','\x65'}, + {'\xe5','\x67'},{'\xbc','\x6b'},{'\xe5','\x68'},{'\x00','\x00'},{'\xe5','\x63'}, + {'\x00','\x00'},{'\xe5','\x62'},{'\xe5','\x6c'},{'\x00','\x00'},{'\xe5','\x6a'}, + {'\xbc','\x6a'},{'\xe5','\x6d'},{'\xe5','\x64'},{'\xe5','\x69'},{'\xe5','\x6b'}, + {'\xe5','\x66'},{'\x00','\x00'},{'\x9a','\x63'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xe9','\x61'},{'\xe9','\x66'},{'\xe9','\x60'},{'\xe9','\x65'},{'\x9a','\x64'}, + {'\xe9','\x5e'},{'\xe9','\x68'},{'\xe9','\x64'},{'\xe9','\x69'},{'\xe9','\x63'}, + {'\xe9','\x5f'},{'\xe9','\x67'},{'\x00','\x00'},{'\xe9','\x6a'},{'\xe9','\x62'}, + {'\x9a','\x65'},{'\xec','\xda'},{'\xc0','\xaf'},{'\x82','\xd9'},{'\xc0','\xad'}, + {'\x00','\x00'},{'\xc0','\xac'},{'\xc0','\xae'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xef','\xc4'},{'\x9a','\x66'},{'\xf1','\x72'},{'\xf1','\xfd'},{'\x00','\x00'}, + {'\x8c','\xcc'},{'\xf4','\x44'},{'\xf4','\x45'},{'\x00','\x00'},{'\xc4','\x60'}, + {'\x00','\x00'},{'\xf5','\xc9'},{'\x82','\x53'},{'\xc4','\xde'},{'\x00','\x00'}, + {'\xf5','\xca'},{'\x82','\xda'},{'\xf6','\xde'},{'\xc5','\x72'},{'\x82','\xdb'}, + {'\xc5','\x71'},{'\xf6','\xdd'},{'\xc5','\xc9'},{'\x9a','\x67'},{'\xf7','\xd6'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xcc'},{'\x00','\x00'},{'\xa4','\x74'}, + {'\xa6','\x7b'},{'\xc9','\xda'},{'\xca','\xca'},{'\xa8','\xb5'},{'\xb1','\x5f'}, + {'\x93','\x57'},{'\x00','\x00'},{'\xa4','\x75'},{'\xa5','\xaa'},{'\xa5','\xa9'}, + {'\xa5','\xa8'},{'\x88','\xb2'},{'\x00','\x00'},{'\xa7','\xc5'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xae','\x74'},{'\x8e','\x43'},{'\xdd','\x57'},{'\xa4','\x76'}, + {'\xa4','\x77'},{'\xa4','\x78'},{'\xa4','\xda'},{'\xfb','\xfa'},{'\x00','\x00'}, + {'\xab','\xd1'},{'\x00','\x00'},{'\xce','\xaf'},{'\x00','\x00'},{'\x92','\x66'}, + {'\x00','\x00'},{'\xb4','\x53'},{'\xa4','\x79'},{'\xc9','\x5d'},{'\x00','\x00'}, + {'\x86','\xc5'},{'\xa5','\xab'},{'\xa5','\xac'},{'\xc9','\x78'},{'\x83','\x6c'}, + {'\xa6','\x7c'},{'\x00','\x00'},{'\x83','\xb6'},{'\x9a','\x68'},{'\xca','\xcb'}, + {'\xfb','\xfb'},{'\xa7','\xc6'},{'\x00','\x00'},{'\xca','\xcc'},{'\x84','\xd9'}, + {'\x84','\x44'},{'\xa9','\xae'},{'\xfb','\xfc'},{'\x00','\x00'},{'\xcc','\x6e'}, + {'\xa9','\xac'},{'\xa9','\xab'},{'\xcc','\x6d'},{'\xa9','\xa9'},{'\xcc','\x6f'}, + {'\xa9','\xaa'},{'\xa9','\xad'},{'\x87','\xc3'},{'\xab','\xd2'},{'\x00','\x00'}, + {'\xab','\xd4'},{'\xce','\xb3'},{'\xce','\xb0'},{'\xce','\xb1'},{'\xce','\xb2'}, + {'\xce','\xb4'},{'\xab','\xd3'},{'\x84','\x43'},{'\x84','\xd8'},{'\xd1','\x74'}, + {'\xd1','\x73'},{'\x00','\x00'},{'\xae','\x76'},{'\x00','\x00'},{'\xae','\x75'}, + {'\x89','\xd6'},{'\x93','\x67'},{'\x92','\x6f'},{'\x8f','\x50'},{'\x00','\x00'}, + {'\xb1','\x62'},{'\xd5','\x46'},{'\x00','\x00'},{'\xb1','\x61'},{'\xb1','\x63'}, + {'\xb1','\x60'},{'\x00','\x00'},{'\x00','\x00'},{'\x8e','\x68'},{'\x86','\xc6'}, + {'\xb4','\x55'},{'\xd5','\x45'},{'\x00','\x00'},{'\xb4','\x56'},{'\xd8','\xf3'}, + {'\x88','\xcb'},{'\xb4','\x57'},{'\xd8','\xf2'},{'\xb4','\x54'},{'\x00','\x00'}, + {'\x82','\xdc'},{'\x9a','\x69'},{'\x00','\x00'},{'\xdd','\x5a'},{'\xdd','\x5c'}, + {'\xb7','\x45'},{'\xdd','\x5b'},{'\xdd','\x59'},{'\xdd','\x58'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xe1','\xb4'},{'\xb9','\xf7'},{'\xb9','\xf5'}, + {'\x00','\x00'},{'\xb9','\xf6'},{'\xe1','\xb2'},{'\xe1','\xb3'},{'\x00','\x00'}, + {'\xb9','\xf3'},{'\xe5','\x71'},{'\xe5','\x6f'},{'\xfb','\xfe'},{'\xbc','\x6d'}, + {'\xe5','\x70'},{'\xbc','\x6e'},{'\xbc','\x6c'},{'\xb9','\xf4'},{'\x82','\xdd'}, + {'\x00','\x00'},{'\xe9','\x6d'},{'\xe9','\x6b'},{'\xe9','\x6c'},{'\xe5','\x6e'}, + {'\xec','\xdc'},{'\xc0','\xb0'},{'\xec','\xdb'},{'\xef','\xc5'},{'\xef','\xc6'}, + {'\xe9','\x6e'},{'\xf1','\xfe'},{'\x00','\x00'},{'\xa4','\x7a'},{'\xa5','\xad'}, + {'\xa6','\x7e'},{'\xc9','\xdb'},{'\xa6','\x7d'},{'\x00','\x00'},{'\xa9','\xaf'}, + {'\xb7','\x46'},{'\xc6','\xcd'},{'\xa4','\xdb'},{'\xa5','\xae'},{'\xab','\xd5'}, + {'\xb4','\x58'},{'\xc6','\xce'},{'\xc9','\x79'},{'\x93','\x75'},{'\xc9','\x7a'}, + {'\x92','\xbe'},{'\xc9','\xdc'},{'\x00','\x00'},{'\x87','\xca'},{'\xa7','\xc8'}, + {'\xca','\xd0'},{'\xca','\xce'},{'\xa7','\xc9'},{'\xca','\xcd'},{'\xca','\xcf'}, + {'\xca','\xd1'},{'\x00','\x00'},{'\xa7','\xc7'},{'\x8b','\x72'},{'\x8e','\xb5'}, + {'\x9a','\x6a'},{'\x83','\xb7'},{'\x89','\xd8'},{'\xa9','\xb3'},{'\xa9','\xb4'}, + {'\xa9','\xb1'},{'\x00','\x00'},{'\x87','\xc6'},{'\xa9','\xb0'},{'\xce','\xb8'}, + {'\xa9','\xb2'},{'\x00','\x00'},{'\x8b','\x71'},{'\x87','\xc4'},{'\xab','\xd6'}, + {'\x00','\x00'},{'\xce','\xb7'},{'\xce','\xb9'},{'\xce','\xb6'},{'\xce','\xba'}, + {'\xab','\xd7'},{'\xae','\x79'},{'\xd1','\x75'},{'\x00','\x00'},{'\xd1','\x77'}, + {'\xae','\x77'},{'\xd1','\x78'},{'\xae','\x78'},{'\xd1','\x76'},{'\x00','\x00'}, + {'\xce','\xb5'},{'\xd5','\x47'},{'\xd5','\x4a'},{'\xd5','\x4b'},{'\xd5','\x48'}, + {'\xb1','\x67'},{'\xb1','\x66'},{'\xb1','\x64'},{'\xb1','\x65'},{'\xd5','\x49'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9a','\x6b'},{'\xb1','\x68'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb4','\x5a'},{'\xb4','\x5b'},{'\x93','\xb2'}, + {'\xb4','\x5c'},{'\xdd','\x5d'},{'\xdd','\x5f'},{'\xdd','\x61'},{'\xb7','\x48'}, + {'\xb7','\x47'},{'\xb4','\x59'},{'\xdd','\x60'},{'\xdd','\x5e'},{'\xfe','\xa4'}, + {'\xe1','\xb8'},{'\x82','\xde'},{'\x82','\xdf'},{'\xe1','\xb6'},{'\xe1','\xbc'}, + {'\xb9','\xf8'},{'\xe1','\xbd'},{'\xe1','\xba'},{'\xb9','\xf9'},{'\xe1','\xb7'}, + {'\xe1','\xb5'},{'\xe1','\xbb'},{'\xbc','\x70'},{'\xe5','\x73'},{'\xe1','\xb9'}, + {'\xbc','\x72'},{'\xe5','\x74'},{'\xbc','\x71'},{'\xbc','\x74'},{'\xe5','\x75'}, + {'\xbc','\x6f'},{'\xbc','\x73'},{'\x00','\x00'},{'\xe9','\x73'},{'\xe9','\x71'}, + {'\xe9','\x70'},{'\xe9','\x72'},{'\xe9','\x6f'},{'\x82','\xe0'},{'\x00','\x00'}, + {'\xc3','\x66'},{'\x00','\x00'},{'\xf4','\x46'},{'\xf4','\x47'},{'\x82','\xe1'}, + {'\xf5','\xcb'},{'\xf6','\xdf'},{'\xc6','\x55'},{'\xc6','\xcf'},{'\x00','\x00'}, + {'\xa9','\xb5'},{'\xa7','\xca'},{'\x95','\xa4'},{'\x95','\xa1'},{'\xab','\xd8'}, + {'\x95','\xee'},{'\x95','\xfa'},{'\x00','\x00'},{'\xa4','\x7b'},{'\xa4','\xdc'}, + {'\x85','\x7b'},{'\xa5','\xaf'},{'\xc9','\xdd'},{'\x84','\x56'},{'\xa7','\xcb'}, + {'\xca','\xd2'},{'\x00','\x00'},{'\xce','\xbb'},{'\xab','\xd9'},{'\x82','\xe2'}, + {'\xb9','\xfa'},{'\xa4','\x7c'},{'\x82','\xe3'},{'\x95','\xaa'},{'\x9a','\x6c'}, + {'\xa6','\xa1'},{'\x93','\xae'},{'\x82','\xe4'},{'\xb7','\x49'},{'\xa4','\x7d'}, + {'\xa4','\xdd'},{'\xa4','\xde'},{'\x94','\x75'},{'\xa5','\xb1'},{'\xa5','\xb0'}, + {'\x00','\x00'},{'\xc9','\xde'},{'\xa6','\xa2'},{'\x00','\x00'},{'\xca','\xd3'}, + {'\x00','\x00'},{'\xa7','\xcc'},{'\x84','\x45'},{'\x82','\xe5'},{'\xcc','\x71'}, + {'\xcc','\x72'},{'\xcc','\x73'},{'\x93','\xf9'},{'\xa9','\xb6'},{'\xa9','\xb7'}, + {'\xcc','\x70'},{'\xa9','\xb8'},{'\x8d','\xc3'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xab','\xda'},{'\xce','\xbc'},{'\x8c','\xce'},{'\xd1','\x7a'},{'\xae','\x7a'}, + {'\x00','\x00'},{'\xd1','\x79'},{'\x82','\xe6'},{'\xb1','\x69'},{'\xd5','\x4c'}, + {'\xb1','\x6a'},{'\xd5','\x4d'},{'\x87','\xc9'},{'\x84','\x46'},{'\x9d','\x7b'}, + {'\xb4','\x5d'},{'\x00','\x00'},{'\x93','\x71'},{'\x00','\x00'},{'\xdd','\x62'}, + {'\x82','\xe7'},{'\x00','\x00'},{'\xe1','\xbf'},{'\xe1','\xbe'},{'\x82','\xe8'}, + {'\xb9','\xfb'},{'\x00','\x00'},{'\xbc','\x75'},{'\xe5','\x76'},{'\xbe','\xca'}, + {'\xe9','\x74'},{'\xc0','\xb1'},{'\xfc','\x41'},{'\xc5','\x73'},{'\xf7','\xd8'}, + {'\xc6','\xd0'},{'\x82','\xe9'},{'\x8a','\xd0'},{'\x85','\xe5'},{'\xcc','\x74'}, + {'\x89','\xa3'},{'\xce','\xbd'},{'\xb1','\x6b'},{'\xd8','\xf4'},{'\xb7','\x4a'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x82','\xea'},{'\xc2','\x55'},{'\xc2','\x55'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc6','\xd1'},{'\xa7','\xce'},{'\xfe','\xa8'}, + {'\xa7','\xcd'},{'\xab','\xdb'},{'\x82','\xeb'},{'\xd1','\x7b'},{'\x00','\x00'}, + {'\xb1','\x6d'},{'\xb3','\x43'},{'\xb1','\x6e'},{'\xb1','\x6c'},{'\xb4','\x5e'}, + {'\x00','\x00'},{'\xe1','\xc0'},{'\xb9','\xfc'},{'\xbc','\x76'},{'\x9a','\x6d'}, + {'\xc9','\x4c'},{'\xc9','\xdf'},{'\x00','\x00'},{'\xca','\xd5'},{'\xa7','\xcf'}, + {'\xca','\xd4'},{'\xa7','\xd0'},{'\x00','\x00'},{'\x86','\xc7'},{'\xa9','\xbc'}, + {'\xcc','\x77'},{'\xcc','\x76'},{'\xa9','\xbb'},{'\xa9','\xb9'},{'\xa9','\xba'}, + {'\xcc','\x75'},{'\x82','\xec'},{'\x92','\xa6'},{'\xab','\xdd'},{'\xce','\xbe'}, + {'\xab','\xe0'},{'\xab','\xdc'},{'\xab','\xe2'},{'\xab','\xde'},{'\xab','\xdf'}, + {'\xab','\xe1'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xae','\x7d'}, + {'\xae','\x7c'},{'\xae','\x7b'},{'\x92','\xdc'},{'\x00','\x00'},{'\x84','\x48'}, + {'\xd5','\x4f'},{'\xb1','\x6f'},{'\xb1','\x72'},{'\xb1','\x70'},{'\x00','\x00'}, + {'\xd5','\x4e'},{'\xb1','\x75'},{'\x00','\x00'},{'\xb1','\x71'},{'\xd5','\x50'}, + {'\xb1','\x74'},{'\xb1','\x73'},{'\x00','\x00'},{'\x00','\x00'},{'\xfc','\x47'}, + {'\xd8','\xf6'},{'\xd8','\xf5'},{'\x95','\x5a'},{'\xb4','\x61'},{'\xb4','\x5f'}, + {'\xb4','\x60'},{'\xd8','\xf7'},{'\xb7','\x4b'},{'\xdd','\x64'},{'\xb7','\x4c'}, + {'\xdd','\x63'},{'\x00','\x00'},{'\x9a','\x6e'},{'\xe5','\x77'},{'\x93','\xa8'}, + {'\x93','\x76'},{'\xbc','\x78'},{'\xe1','\xc1'},{'\xbc','\x77'},{'\x00','\x00'}, + {'\xb9','\xfd'},{'\xfc','\x48'},{'\xec','\xde'},{'\xe9','\x75'},{'\xc0','\xb2'}, + {'\xec','\xdd'},{'\xf2','\x40'},{'\xf4','\x48'},{'\xf4','\x49'},{'\x9a','\x6f'}, + {'\xa4','\xdf'},{'\x9c','\xf5'},{'\xa5','\xb2'},{'\x88','\xda'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xc9','\x7b'},{'\x00','\x00'},{'\x00','\x00'},{'\xa7','\xd2'}, + {'\xa7','\xd4'},{'\x00','\x00'},{'\xc9','\xe2'},{'\xca','\xd8'},{'\xca','\xd7'}, + {'\xca','\xd6'},{'\x00','\x00'},{'\xc9','\xe1'},{'\xc9','\xe0'},{'\xa6','\xa4'}, + {'\xa7','\xd3'},{'\xa7','\xd1'},{'\xa6','\xa3'},{'\x00','\x00'},{'\x9a','\x70'}, + {'\x92','\x4e'},{'\xa9','\xbd'},{'\xcc','\x78'},{'\x9a','\x71'},{'\xa9','\xbe'}, + {'\xca','\xdd'},{'\x00','\x00'},{'\xca','\xdf'},{'\xca','\xde'},{'\xcc','\x79'}, + {'\x00','\x00'},{'\x87','\xcc'},{'\xca','\xda'},{'\x00','\x00'},{'\xa7','\xd8'}, + {'\xa7','\xd6'},{'\x00','\x00'},{'\xca','\xd9'},{'\xca','\xdb'},{'\xca','\xe1'}, + {'\x82','\xed'},{'\xa7','\xd5'},{'\x00','\x00'},{'\xca','\xdc'},{'\xca','\xe5'}, + {'\xa9','\xc0'},{'\x00','\x00'},{'\xca','\xe2'},{'\xa7','\xd7'},{'\x00','\x00'}, + {'\xca','\xe0'},{'\xca','\xe3'},{'\x00','\x00'},{'\xa9','\xbf'},{'\x85','\xc7'}, + {'\xa9','\xc1'},{'\xca','\xe4'},{'\x86','\xc8'},{'\x87','\xcd'},{'\x87','\xd1'}, + {'\x8e','\x6b'},{'\x84','\x4a'},{'\x85','\xc8'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xcc','\xaf'},{'\xcc','\xa2'},{'\xcc','\x7e'},{'\xcc','\xae'},{'\xcc','\xa9'}, + {'\xab','\xe7'},{'\xa9','\xc2'},{'\xcc','\xaa'},{'\xcc','\xad'},{'\xab','\xe3'}, + {'\xcc','\xac'},{'\xa9','\xc3'},{'\xa9','\xc8'},{'\xa9','\xc6'},{'\xcc','\xa3'}, + {'\x00','\x00'},{'\xcc','\x7c'},{'\xcc','\xa5'},{'\xa9','\xcd'},{'\xcc','\xb0'}, + {'\xab','\xe4'},{'\xcc','\xa6'},{'\x00','\x00'},{'\xab','\xe5'},{'\xa9','\xc9'}, + {'\xcc','\xa8'},{'\x9a','\x72'},{'\xce','\xcd'},{'\xab','\xe6'},{'\xcc','\x7b'}, + {'\xa9','\xca'},{'\xab','\xe8'},{'\xa9','\xcb'},{'\xa9','\xc7'},{'\xa9','\xcc'}, + {'\xcc','\xa7'},{'\xcc','\x7a'},{'\xcc','\xab'},{'\xa9','\xc4'},{'\x00','\x00'}, + {'\x95','\xa6'},{'\xcc','\x7d'},{'\xcc','\xa4'},{'\xcc','\xa1'},{'\xa9','\xc5'}, + {'\x00','\x00'},{'\xce','\xbf'},{'\x00','\x00'},{'\xce','\xc0'},{'\x94','\x76'}, + {'\x8a','\x4b'},{'\x8f','\x74'},{'\x00','\x00'},{'\x00','\x00'},{'\x8e','\xe7'}, + {'\xce','\xca'},{'\xd1','\xa1'},{'\xce','\xcb'},{'\xab','\xee'},{'\xce','\xce'}, + {'\xce','\xc4'},{'\xab','\xed'},{'\xce','\xc6'},{'\x00','\x00'},{'\xce','\xc7'}, + {'\x82','\xee'},{'\x8c','\xf6'},{'\xce','\xc9'},{'\xab','\xe9'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xae','\xa3'},{'\x00','\x00'},{'\xf9','\xda'},{'\xce','\xc5'}, + {'\xce','\xc1'},{'\xae','\xa4'},{'\x00','\x00'},{'\x00','\x00'},{'\xce','\xcf'}, + {'\xae','\x7e'},{'\xd1','\x7d'},{'\xce','\xc8'},{'\x00','\x00'},{'\xd1','\x7c'}, + {'\xce','\xc3'},{'\xce','\xcc'},{'\x82','\xef'},{'\x00','\x00'},{'\xab','\xec'}, + {'\xae','\xa1'},{'\xab','\xf2'},{'\xae','\xa2'},{'\xce','\xd0'},{'\xd1','\x7e'}, + {'\xab','\xeb'},{'\xae','\xa6'},{'\xab','\xf1'},{'\xab','\xf0'},{'\xab','\xef'}, + {'\xae','\xa5'},{'\xce','\xd1'},{'\xae','\xa7'},{'\xab','\xea'},{'\x00','\x00'}, + {'\xce','\xc2'},{'\x89','\xd9'},{'\x00','\x00'},{'\x92','\xa8'},{'\x84','\xdc'}, + {'\xfc','\x4b'},{'\x86','\xca'},{'\x8f','\x51'},{'\x85','\xc9'},{'\x84','\xdf'}, + {'\x84','\xe0'},{'\x8d','\xdd'},{'\x9a','\x73'},{'\xb1','\x76'},{'\xd1','\xa4'}, + {'\xd1','\xa6'},{'\x00','\x00'},{'\xd1','\xa8'},{'\xae','\xa8'},{'\xae','\xae'}, + {'\xd5','\x53'},{'\xd1','\xac'},{'\xd1','\xa3'},{'\xb1','\x78'},{'\xd5','\x51'}, + {'\x82','\xf0'},{'\xae','\xad'},{'\xae','\xab'},{'\xd1','\xae'},{'\x00','\x00'}, + {'\xd5','\x52'},{'\x00','\x00'},{'\xd1','\xa5'},{'\x00','\x00'},{'\xae','\xac'}, + {'\xd1','\xa9'},{'\xae','\xaf'},{'\xd1','\xab'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xae','\xaa'},{'\xd1','\xaa'},{'\xd1','\xad'},{'\xd1','\xa7'},{'\xfb','\x64'}, + {'\xae','\xa9'},{'\xb1','\x79'},{'\x00','\x00'},{'\xd1','\xa2'},{'\xb1','\x77'}, + {'\xfc','\x4c'},{'\x00','\x00'},{'\x82','\xf1'},{'\xfe','\xa6'},{'\xb1','\x7a'}, + {'\x93','\xaf'},{'\x92','\x41'},{'\x8e','\x69'},{'\x8b','\xf4'},{'\x8e','\x6a'}, + {'\x00','\x00'},{'\x87','\xce'},{'\xd5','\x55'},{'\xd5','\x5e'},{'\xb4','\x64'}, + {'\xfc','\x4d'},{'\xb1','\x7c'},{'\xb1','\xa3'},{'\xb4','\x65'},{'\xd5','\x60'}, + {'\xb1','\xaa'},{'\xd8','\xf9'},{'\xd5','\x56'},{'\xb1','\xa2'},{'\xb1','\xa5'}, + {'\xb1','\x7e'},{'\xd5','\x54'},{'\xd5','\x62'},{'\xd5','\x65'},{'\xd9','\x49'}, + {'\x00','\x00'},{'\xd5','\x63'},{'\xd8','\xfd'},{'\xb1','\xa1'},{'\xb1','\xa8'}, + {'\xb1','\xac'},{'\xd5','\x5d'},{'\xd8','\xf8'},{'\xd5','\x61'},{'\xb1','\x7b'}, + {'\xd8','\xfa'},{'\xd5','\x64'},{'\xd8','\xfc'},{'\xd5','\x59'},{'\x00','\x00'}, + {'\xb4','\x62'},{'\x00','\x00'},{'\xd5','\x57'},{'\xd5','\x58'},{'\xb1','\xa7'}, + {'\x00','\x00'},{'\x9a','\x74'},{'\xb1','\xa6'},{'\xd5','\x5b'},{'\xb1','\xab'}, + {'\xd5','\x5f'},{'\xb1','\xa4'},{'\xd5','\x5c'},{'\x82','\xf2'},{'\xb1','\xa9'}, + {'\xb4','\x66'},{'\xb4','\x63'},{'\xd8','\xfb'},{'\x82','\xad'},{'\xd5','\x5a'}, + {'\x00','\x00'},{'\xb1','\x7d'},{'\x8c','\x71'},{'\x86','\xcc'},{'\x8b','\x73'}, + {'\x00','\x00'},{'\x88','\xd8'},{'\x84','\xde'},{'\x86','\xcb'},{'\x87','\xcf'}, + {'\x86','\xc9'},{'\xb4','\x6b'},{'\xb4','\x6f'},{'\xd9','\x40'},{'\xb7','\x51'}, + {'\xb4','\x6d'},{'\xd9','\x44'},{'\xb4','\x71'},{'\xdd','\x65'},{'\xd9','\x46'}, + {'\xb7','\x53'},{'\xb4','\x69'},{'\xb4','\x6c'},{'\xd9','\x47'},{'\xfc','\x4e'}, + {'\xd9','\x48'},{'\xd9','\x4e'},{'\xb4','\x73'},{'\xb7','\x54'},{'\x00','\x00'}, + {'\xd9','\x4a'},{'\xd9','\x4f'},{'\xd9','\x43'},{'\xb7','\x5e'},{'\x9a','\x75'}, + {'\xb7','\x55'},{'\xb4','\x72'},{'\xd9','\x41'},{'\xd9','\x50'},{'\x9a','\x76'}, + {'\xb7','\x5d'},{'\xb4','\x70'},{'\xb7','\x4e'},{'\xd9','\x4d'},{'\x82','\xf3'}, + {'\xb4','\x74'},{'\xd9','\x45'},{'\xd8','\xfe'},{'\xb4','\x6a'},{'\xd9','\x42'}, + {'\x00','\x00'},{'\xd9','\x4b'},{'\x9a','\x77'},{'\xb7','\x4d'},{'\xb7','\x52'}, + {'\xb4','\x67'},{'\xd9','\x4c'},{'\x00','\x00'},{'\xb7','\x50'},{'\x82','\xf4'}, + {'\x82','\xf5'},{'\x9a','\x78'},{'\xb4','\x68'},{'\x87','\xd0'},{'\x00','\x00'}, + {'\x8e','\xb6'},{'\xb7','\x5c'},{'\xe1','\xc3'},{'\xdd','\x70'},{'\x00','\x00'}, + {'\xdd','\x68'},{'\xe1','\xc2'},{'\x00','\x00'},{'\xdd','\x6c'},{'\xdd','\x6e'}, + {'\xfc','\x4f'},{'\x00','\x00'},{'\xdd','\x6b'},{'\x00','\x00'},{'\xb7','\x5b'}, + {'\x00','\x00'},{'\xdd','\x6a'},{'\xb7','\x5f'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xe1','\xd2'},{'\x82','\xf6'},{'\x82','\xf7'},{'\xb7','\x5a'}, + {'\xba','\x40'},{'\xdd','\x71'},{'\xe1','\xc4'},{'\xfc','\xc9'},{'\x00','\x00'}, + {'\xb7','\x58'},{'\xdd','\x69'},{'\xdd','\x6d'},{'\xb9','\xfe'},{'\xb7','\x4f'}, + {'\xdd','\x66'},{'\xdd','\x67'},{'\xba','\x41'},{'\xb7','\x57'},{'\xb7','\x59'}, + {'\xb7','\x56'},{'\xdd','\x6f'},{'\x9a','\x79'},{'\x8c','\x72'},{'\xe1','\xc8'}, + {'\xe1','\xc9'},{'\xe1','\xce'},{'\xbc','\x7d'},{'\xe1','\xd5'},{'\x00','\x00'}, + {'\xba','\x47'},{'\xfc','\x52'},{'\xba','\x46'},{'\xe1','\xd0'},{'\xfc','\x54'}, + {'\xbc','\x7c'},{'\xe1','\xc5'},{'\xba','\x45'},{'\x9a','\x7a'},{'\xe1','\xd4'}, + {'\xba','\x43'},{'\xba','\x44'},{'\x95','\xad'},{'\xe1','\xd1'},{'\xe5','\xaa'}, + {'\xbc','\x7a'},{'\xb4','\x6e'},{'\x00','\x00'},{'\xe1','\xd3'},{'\xbc','\xa3'}, + {'\xe1','\xcb'},{'\x00','\x00'},{'\xbc','\x7b'},{'\x95','\x66'},{'\xbc','\xa2'}, + {'\xe1','\xc6'},{'\xe1','\xca'},{'\xe1','\xc7'},{'\xe1','\xcd'},{'\xba','\x48'}, + {'\xbc','\x79'},{'\xba','\x42'},{'\x00','\x00'},{'\xe5','\x7a'},{'\xe1','\xcf'}, + {'\x00','\x00'},{'\xbc','\xa1'},{'\xfc','\x53'},{'\xbc','\xa4'},{'\x00','\x00'}, + {'\xe1','\xcc'},{'\x9a','\x7b'},{'\xbc','\x7e'},{'\xe5','\x79'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x95','\xd1'},{'\x00','\x00'},{'\xe5','\x7e'}, + {'\xbe','\xce'},{'\xe5','\x78'},{'\xe9','\xa3'},{'\xe5','\xa9'},{'\xbc','\xa8'}, + {'\x00','\x00'},{'\xbc','\xa6'},{'\xbe','\xcc'},{'\xe5','\xa6'},{'\xe5','\xa2'}, + {'\xbc','\xac'},{'\x9a','\x7c'},{'\xe9','\x78'},{'\x00','\x00'},{'\x82','\xf8'}, + {'\xfe','\x74'},{'\xbc','\xaa'},{'\xe5','\xa1'},{'\xfc','\x51'},{'\xe9','\x76'}, + {'\x00','\x00'},{'\xe5','\xa5'},{'\x00','\x00'},{'\xe5','\xa8'},{'\xe5','\x7d'}, + {'\x00','\x00'},{'\xbc','\xab'},{'\x00','\x00'},{'\x00','\x00'},{'\xbc','\xa5'}, + {'\xe9','\x77'},{'\xbe','\xcd'},{'\xe5','\xa7'},{'\xbc','\xa7'},{'\xbc','\xa9'}, + {'\xe5','\xa4'},{'\xbc','\xad'},{'\xe5','\xa3'},{'\xe5','\x7c'},{'\xe5','\x7b'}, + {'\xbe','\xcb'},{'\xe5','\xab'},{'\xe9','\x7a'},{'\xec','\xe0'},{'\xbe','\xd0'}, + {'\x82','\xf9'},{'\xe9','\xa2'},{'\x9a','\x7d'},{'\xe9','\x7e'},{'\x00','\x00'}, + {'\xec','\xe1'},{'\x00','\x00'},{'\xbe','\xd1'},{'\xe9','\xa1'},{'\x9a','\x7e'}, + {'\xe9','\x7c'},{'\xc0','\xb4'},{'\xec','\xdf'},{'\x00','\x00'},{'\xe9','\x79'}, + {'\xe9','\x7b'},{'\xc0','\xb5'},{'\xbe','\xd3'},{'\xc0','\xb3'},{'\xbe','\xd2'}, + {'\xc0','\xb7'},{'\xe9','\x7d'},{'\xbe','\xcf'},{'\x00','\x00'},{'\x9a','\xa1'}, + {'\x92','\x5d'},{'\x8a','\xc2'},{'\x8b','\x75'},{'\x9a','\xa2'},{'\x88','\xd9'}, + {'\x00','\x00'},{'\xef','\xcf'},{'\x00','\x00'},{'\xef','\xc7'},{'\x00','\x00'}, + {'\x9a','\xa3'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xec','\xe7'}, + {'\xef','\xc8'},{'\xec','\xe3'},{'\x00','\x00'},{'\xfc','\x56'},{'\xc2','\x56'}, + {'\xec','\xe5'},{'\xec','\xe4'},{'\xc0','\xb6'},{'\xec','\xe2'},{'\xec','\xe6'}, + {'\xef','\xd0'},{'\xef','\xcc'},{'\xef','\xce'},{'\x00','\x00'},{'\xef','\xc9'}, + {'\xef','\xca'},{'\x00','\x00'},{'\xef','\xcd'},{'\xef','\xcb'},{'\xc3','\x67'}, + {'\x00','\x00'},{'\x82','\xfa'},{'\xc3','\x6a'},{'\xc3','\x69'},{'\xc3','\x68'}, + {'\xc4','\x61'},{'\xf4','\x4a'},{'\xc4','\x62'},{'\xf2','\x41'},{'\xc4','\xdf'}, + {'\xf5','\xcc'},{'\xc4','\xe0'},{'\xc5','\x74'},{'\xc5','\xca'},{'\xf7','\xd9'}, + {'\x00','\x00'},{'\xf7','\xda'},{'\xf7','\xdb'},{'\x00','\x00'},{'\x90','\xab'}, + {'\xf9','\xba'},{'\xa4','\xe0'},{'\xc9','\x7c'},{'\xa5','\xb3'},{'\x8d','\xb8'}, + {'\xa6','\xa6'},{'\xa6','\xa7'},{'\xa6','\xa5'},{'\x89','\xda'},{'\xa6','\xa8'}, + {'\xa7','\xda'},{'\xa7','\xd9'},{'\x82','\xfb'},{'\xcc','\xb1'},{'\xa9','\xcf'}, + {'\xa9','\xce'},{'\x8e','\x6d'},{'\x88','\xdb'},{'\xd1','\xaf'},{'\xb1','\xad'}, + {'\xb1','\xae'},{'\x00','\x00'},{'\x82','\xfc'},{'\x82','\xfd'},{'\xb4','\x75'}, + {'\xdd','\x72'},{'\xb7','\x60'},{'\xb7','\x61'},{'\xdd','\x74'},{'\xdd','\x76'}, + {'\xdd','\x75'},{'\x93','\x49'},{'\xe1','\xd7'},{'\x00','\x00'},{'\xe1','\xd6'}, + {'\xba','\x49'},{'\xe1','\xd8'},{'\x8e','\x6c'},{'\xe5','\xac'},{'\xbc','\xae'}, + {'\x92','\x70'},{'\xbe','\xd4'},{'\x00','\x00'},{'\xc0','\xb8'},{'\xc2','\x57'}, + {'\xc0','\xb9'},{'\x00','\x00'},{'\xa4','\xe1'},{'\x82','\xfe'},{'\x90','\xbd'}, + {'\xfc','\x58'},{'\xca','\xe6'},{'\x93','\xec'},{'\x00','\x00'},{'\xcc','\xb2'}, + {'\xa9','\xd1'},{'\xa9','\xd0'},{'\xa9','\xd2'},{'\xab','\xf3'},{'\xce','\xd2'}, + {'\xce','\xd3'},{'\x00','\x00'},{'\x00','\x00'},{'\xd1','\xb0'},{'\xae','\xb0'}, + {'\xb1','\xaf'},{'\xb4','\x76'},{'\xd9','\x51'},{'\xa4','\xe2'},{'\x9c','\xf2'}, + {'\xa4','\x7e'},{'\xa4','\xe3'},{'\x00','\x00'},{'\xc9','\x7d'},{'\xa5','\xb7'}, + {'\xa5','\xb6'},{'\xa5','\xb4'},{'\xa5','\xb5'},{'\x93','\xc1'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa6','\xab'},{'\xc9','\xe9'},{'\xc9','\xeb'},{'\xa6','\xaa'}, + {'\xc9','\xe3'},{'\x00','\x00'},{'\xc9','\xe4'},{'\x00','\x00'},{'\xc9','\xea'}, + {'\xc9','\xe6'},{'\xc9','\xe8'},{'\xa6','\xa9'},{'\xc9','\xe5'},{'\xc9','\xec'}, + {'\xc9','\xe7'},{'\x83','\xf9'},{'\xfc','\x59'},{'\x8a','\xc3'},{'\x84','\x4d'}, + {'\x84','\x4b'},{'\x84','\xe4'},{'\xa7','\xe1'},{'\xa7','\xea'},{'\xa7','\xe8'}, + {'\xca','\xf0'},{'\xca','\xed'},{'\xca','\xf5'},{'\xa7','\xe6'},{'\xca','\xf6'}, + {'\x00','\x00'},{'\xa7','\xdf'},{'\xca','\xf3'},{'\x00','\x00'},{'\xa7','\xe5'}, + {'\xca','\xef'},{'\xca','\xee'},{'\xa7','\xe3'},{'\xca','\xf4'},{'\xa7','\xe4'}, + {'\xa9','\xd3'},{'\xa7','\xde'},{'\xca','\xf1'},{'\xfc','\x5b'},{'\xca','\xe7'}, + {'\xa7','\xdb'},{'\xfc','\x5a'},{'\xa7','\xee'},{'\xca','\xec'},{'\xca','\xf2'}, + {'\xa7','\xe0'},{'\xa7','\xe2'},{'\x00','\x00'},{'\xca','\xe8'},{'\x00','\x00'}, + {'\xca','\xe9'},{'\xca','\xea'},{'\x9a','\xa4'},{'\xa7','\xed'},{'\xa7','\xe7'}, + {'\xa7','\xec'},{'\xca','\xeb'},{'\xa7','\xeb'},{'\xa7','\xdd'},{'\xa7','\xdc'}, + {'\xa7','\xe9'},{'\x00','\x00'},{'\x87','\xd7'},{'\x90','\xbe'},{'\x93','\xbb'}, + {'\xfd','\x57'},{'\x93','\x6a'},{'\x8e','\x6e'},{'\x8e','\x6f'},{'\x84','\x4e'}, + {'\x85','\xcb'},{'\x00','\x00'},{'\x8c','\xa8'},{'\x84','\xd2'},{'\xfc','\x5c'}, + {'\x00','\x00'},{'\xa9','\xe1'},{'\xcc','\xbe'},{'\xcc','\xb7'},{'\xa9','\xdc'}, + {'\xa9','\xef'},{'\xcc','\xb3'},{'\xcc','\xba'},{'\xcc','\xbc'},{'\xcc','\xbf'}, + {'\xa9','\xea'},{'\x00','\x00'},{'\xcc','\xbb'},{'\xcc','\xb4'},{'\xa9','\xe8'}, + {'\xcc','\xb8'},{'\x00','\x00'},{'\xcc','\xc0'},{'\xa9','\xd9'},{'\x00','\x00'}, + {'\xcc','\xbd'},{'\xa9','\xe3'},{'\xa9','\xe2'},{'\xcc','\xb6'},{'\xa9','\xd7'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa9','\xd8'},{'\xfb','\x46'},{'\xa9','\xd6'}, + {'\x88','\xe3'},{'\xa9','\xee'},{'\xa9','\xe6'},{'\xa9','\xe0'},{'\xa9','\xd4'}, + {'\xcc','\xb9'},{'\xa9','\xdf'},{'\xa9','\xd5'},{'\xa9','\xe7'},{'\xa9','\xf0'}, + {'\xce','\xd4'},{'\xa9','\xe4'},{'\xcc','\xb5'},{'\xa9','\xda'},{'\xa9','\xdd'}, + {'\xa9','\xde'},{'\xfc','\x5d'},{'\xa9','\xec'},{'\xa9','\xed'},{'\xa9','\xeb'}, + {'\xa9','\xe5'},{'\xa9','\xe9'},{'\xa9','\xdb'},{'\xab','\xf4'},{'\x93','\xb1'}, + {'\x00','\x00'},{'\x89','\xde'},{'\x92','\x75'},{'\x92','\x5e'},{'\x8b','\x76'}, + {'\x84','\xe1'},{'\x00','\x00'},{'\x88','\xdc'},{'\x8b','\xf6'},{'\x89','\xdd'}, + {'\x87','\xd5'},{'\x88','\xe1'},{'\x00','\x00'},{'\xce','\xda'},{'\xac','\x41'}, + {'\xab','\xf8'},{'\xab','\xfa'},{'\xac','\x40'},{'\xce','\xe6'},{'\xab','\xfd'}, + {'\xd1','\xb1'},{'\xae','\xb1'},{'\xac','\x43'},{'\xce','\xd7'},{'\xce','\xdf'}, + {'\xab','\xfe'},{'\xce','\xde'},{'\xce','\xdb'},{'\xce','\xe3'},{'\xce','\xe5'}, + {'\xab','\xf7'},{'\xab','\xfb'},{'\xac','\x42'},{'\xae','\xb3'},{'\xce','\xe0'}, + {'\xab','\xf9'},{'\xac','\x45'},{'\xce','\xd9'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xab','\xfc'},{'\xae','\xb2'},{'\xab','\xf6'},{'\x00','\x00'}, + {'\xce','\xd6'},{'\xce','\xdd'},{'\xce','\xd5'},{'\xce','\xd8'},{'\xce','\xdc'}, + {'\xd1','\xb2'},{'\xac','\x44'},{'\x00','\x00'},{'\xce','\xe1'},{'\xce','\xe2'}, + {'\xce','\xe4'},{'\xab','\xf5'},{'\x00','\x00'},{'\x94','\xf4'},{'\x92','\x76'}, + {'\x87','\xd2'},{'\x8c','\xf7'},{'\x00','\x00'},{'\x88','\xe4'},{'\x88','\xde'}, + {'\x83','\xb9'},{'\x87','\xd6'},{'\x88','\xdd'},{'\x8e','\xb7'},{'\x84','\x4f'}, + {'\x89','\xdc'},{'\x84','\xe2'},{'\x00','\x00'},{'\x90','\xbf'},{'\xae','\xc1'}, + {'\xd1','\xbe'},{'\xae','\xbf'},{'\xae','\xc0'},{'\xd1','\xb4'},{'\xd1','\xc4'}, + {'\xa0','\x5e'},{'\xae','\xb6'},{'\x00','\x00'},{'\x9a','\xa5'},{'\xd5','\x66'}, + {'\xd1','\xc6'},{'\xd1','\xc0'},{'\xfc','\x5f'},{'\xd1','\xb7'},{'\x9a','\xa7'}, + {'\xd1','\xc9'},{'\xd1','\xba'},{'\xae','\xbc'},{'\xd5','\x7d'},{'\xd1','\xbd'}, + {'\xae','\xbe'},{'\xae','\xb5'},{'\x93','\x56'},{'\xd1','\xcb'},{'\xd1','\xbf'}, + {'\xae','\xb8'},{'\xd1','\xb8'},{'\xd1','\xb5'},{'\xd1','\xb6'},{'\xae','\xb9'}, + {'\xd1','\xc5'},{'\xd1','\xcc'},{'\xae','\xbb'},{'\xd1','\xbc'},{'\xd1','\xbb'}, + {'\xae','\xc3'},{'\xae','\xc2'},{'\xae','\xb4'},{'\xae','\xba'},{'\xae','\xbd'}, + {'\xd1','\xc8'},{'\x00','\x00'},{'\x00','\x00'},{'\xd1','\xc2'},{'\xae','\xb7'}, + {'\xd1','\xb3'},{'\xd1','\xca'},{'\xd1','\xc1'},{'\xd1','\xc3'},{'\xd1','\xc7'}, + {'\x00','\x00'},{'\x93','\x55'},{'\x00','\x00'},{'\x87','\xd4'},{'\x85','\xca'}, + {'\x00','\x00'},{'\x88','\xe2'},{'\x84','\xe3'},{'\x85','\xcc'},{'\xfc','\x5e'}, + {'\xd5','\x67'},{'\x00','\x00'},{'\xb1','\xb7'},{'\xb1','\xcb'},{'\xb1','\xca'}, + {'\x00','\x00'},{'\xb1','\xbf'},{'\x95','\x59'},{'\xd5','\x79'},{'\xd5','\x75'}, + {'\xd5','\x72'},{'\xd5','\xa6'},{'\xb1','\xba'},{'\xb1','\xb2'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd5','\x77'},{'\xb4','\xa8'},{'\xb1','\xb6'},{'\xd5','\xa1'}, + {'\x9a','\xa8'},{'\xb1','\xcc'},{'\xb1','\xc9'},{'\xd5','\x7b'},{'\xd5','\x6a'}, + {'\x00','\x00'},{'\xfc','\x55'},{'\xb1','\xc8'},{'\xd5','\xa3'},{'\xd5','\x69'}, + {'\xb1','\xbd'},{'\xb1','\xc1'},{'\xd5','\xa2'},{'\x00','\x00'},{'\xd5','\x73'}, + {'\xb1','\xc2'},{'\xb1','\xbc'},{'\xd5','\x68'},{'\x9a','\xa9'},{'\xb4','\x78'}, + {'\xd5','\xa5'},{'\xd5','\x71'},{'\xb1','\xc7'},{'\xd5','\x74'},{'\xd5','\xa4'}, + {'\xb1','\xc6'},{'\x00','\x00'},{'\xd9','\x52'},{'\x00','\x00'},{'\xb1','\xb3'}, + {'\xd5','\x6f'},{'\xb1','\xb8'},{'\xb1','\xc3'},{'\x00','\x00'},{'\xb1','\xbe'}, + {'\xd5','\x78'},{'\xd5','\x6e'},{'\xd5','\x6c'},{'\xd5','\x7e'},{'\xb1','\xb0'}, + {'\xb1','\xc4'},{'\xb1','\xb4'},{'\xb4','\x77'},{'\xd5','\x7c'},{'\xb1','\xb5'}, + {'\x00','\x00'},{'\xb1','\xb1'},{'\xb1','\xc0'},{'\xb1','\xbb'},{'\xb1','\xb9'}, + {'\xd5','\x70'},{'\xb1','\xc5'},{'\xd5','\x6d'},{'\xd5','\x7a'},{'\xd5','\x76'}, + {'\xd9','\x54'},{'\xd9','\x53'},{'\x92','\xa9'},{'\x88','\xe0'},{'\x86','\xce'}, + {'\x94','\x77'},{'\x00','\x00'},{'\x8a','\xc4'},{'\x87','\xd8'},{'\xfb','\x57'}, + {'\x86','\xcf'},{'\x90','\xc0'},{'\x8e','\x70'},{'\xd5','\x6b'},{'\xd9','\x64'}, + {'\x00','\x00'},{'\xb4','\x7a'},{'\x9a','\xaa'},{'\xd9','\x6a'},{'\xd9','\x59'}, + {'\xd9','\x67'},{'\xdd','\x77'},{'\xb4','\x7d'},{'\xd9','\x6b'},{'\xd9','\x6e'}, + {'\xb4','\x7c'},{'\xd9','\x5c'},{'\xd9','\x6d'},{'\xd9','\x6c'},{'\xb4','\x7e'}, + {'\xd9','\x55'},{'\xb4','\x79'},{'\xb4','\xa3'},{'\xfd','\x6c'},{'\xb4','\xa1'}, + {'\xd9','\x69'},{'\x00','\x00'},{'\xd9','\x5f'},{'\xb4','\xa5'},{'\xd9','\x70'}, + {'\xd9','\x68'},{'\xd9','\x71'},{'\xb4','\xad'},{'\xb4','\xab'},{'\xd9','\x66'}, + {'\xd9','\x65'},{'\x90','\xc1'},{'\xd9','\x63'},{'\xd9','\x5d'},{'\xb4','\xa4'}, + {'\x9a','\xab'},{'\xb4','\xa2'},{'\xd1','\xb9'},{'\xd9','\x56'},{'\x9a','\xac'}, + {'\xdd','\xb7'},{'\xd9','\x57'},{'\xb4','\x7b'},{'\xb4','\xaa'},{'\xdd','\x79'}, + {'\x00','\x00'},{'\xb4','\xa6'},{'\xb4','\xa7'},{'\xd9','\x58'},{'\xd9','\x6f'}, + {'\xdd','\x78'},{'\xd9','\x60'},{'\xd9','\x5b'},{'\xb4','\xa9'},{'\xd9','\x61'}, + {'\xd9','\x5e'},{'\x00','\x00'},{'\xa0','\x5f'},{'\xb4','\xae'},{'\x90','\xc2'}, + {'\x9a','\xad'},{'\xfb','\x5d'},{'\x8d','\x53'},{'\x9a','\xae'},{'\x87','\xd9'}, + {'\x8b','\xf7'},{'\x89','\xdf'},{'\x86','\xcd'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x8c','\xf8'},{'\xb7','\x70'},{'\x9a','\xaf'},{'\x00','\x00'},{'\xdd','\x7c'}, + {'\xdd','\xb1'},{'\xdd','\xb6'},{'\xdd','\xaa'},{'\xb7','\x6c'},{'\xdd','\xbb'}, + {'\xb7','\x69'},{'\xdd','\x7a'},{'\x00','\x00'},{'\xdd','\x7b'},{'\xb7','\x62'}, + {'\xb7','\x6b'},{'\xdd','\xa4'},{'\xb7','\x6e'},{'\xb7','\x6f'},{'\xdd','\xa5'}, + {'\x00','\x00'},{'\xdd','\xb2'},{'\xdd','\xb8'},{'\xb7','\x6a'},{'\x00','\x00'}, + {'\xb7','\x64'},{'\xdd','\xa3'},{'\xdd','\x7d'},{'\xdd','\xba'},{'\xdd','\xa8'}, + {'\xdd','\xa9'},{'\xdd','\x7e'},{'\xdd','\xb4'},{'\xdd','\xab'},{'\xdd','\xb5'}, + {'\xdd','\xad'},{'\x00','\x00'},{'\xb7','\x65'},{'\xe1','\xd9'},{'\xb7','\x68'}, + {'\xb7','\x66'},{'\xdd','\xb9'},{'\xdd','\xb0'},{'\xdd','\xac'},{'\x00','\x00'}, + {'\x9a','\xb0'},{'\xdd','\xa1'},{'\xba','\x53'},{'\xdd','\xaf'},{'\xb7','\x6d'}, + {'\xdd','\xa7'},{'\x9a','\xb1'},{'\xdd','\xa6'},{'\x8c','\x74'},{'\x9a','\xb2'}, + {'\x00','\x00'},{'\xb7','\x67'},{'\xb7','\x63'},{'\xe1','\xee'},{'\xdd','\xb3'}, + {'\xdd','\xae'},{'\x93','\x45'},{'\xdd','\xa2'},{'\x8c','\x73'},{'\x8f','\x75'}, + {'\x8a','\xc7'},{'\x93','\xda'},{'\x8f','\x52'},{'\x00','\x00'},{'\x8c','\xcf'}, + {'\xe1','\xe9'},{'\x00','\x00'},{'\xe1','\xda'},{'\xe1','\xe5'},{'\x00','\x00'}, + {'\xe1','\xec'},{'\xba','\x51'},{'\xb4','\xac'},{'\xe1','\xea'},{'\xba','\x4c'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xba','\x4b'},{'\xe1','\xf1'}, + {'\x9a','\xb3'},{'\xe1','\xdb'},{'\xe1','\xe8'},{'\xe1','\xdc'},{'\xe1','\xe7'}, + {'\xba','\x4f'},{'\xe1','\xeb'},{'\xd9','\x62'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xe1','\xf2'},{'\xe1','\xe3'},{'\xba','\x52'},{'\xe5','\xba'}, + {'\xbc','\xaf'},{'\x00','\x00'},{'\xe1','\xf0'},{'\xe1','\xef'},{'\xba','\x54'}, + {'\xe5','\xad'},{'\xbc','\xb0'},{'\xe5','\xae'},{'\x9a','\xb4'},{'\xe1','\xdf'}, + {'\xe1','\xe0'},{'\xe1','\xdd'},{'\xe1','\xe2'},{'\xe1','\xde'},{'\xe1','\xf3'}, + {'\xba','\x4e'},{'\xbc','\xb1'},{'\xba','\x50'},{'\xba','\x55'},{'\x9a','\xb5'}, + {'\xe1','\xe1'},{'\x00','\x00'},{'\xe1','\xed'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xe1','\xe6'},{'\x92','\xb0'},{'\x8f','\xda'},{'\xe5','\xb1'},{'\x00','\x00'}, + {'\xba','\x4a'},{'\xbc','\xb4'},{'\xe9','\xaa'},{'\xe5','\xb6'},{'\xe5','\xb5'}, + {'\xe5','\xb7'},{'\x9a','\xb6'},{'\x00','\x00'},{'\xe5','\xb4'},{'\xbc','\xb5'}, + {'\x90','\xc3'},{'\xbc','\xbb'},{'\xbc','\xb8'},{'\x00','\x00'},{'\xbc','\xb9'}, + {'\xe5','\xaf'},{'\xe5','\xb2'},{'\xe5','\xbc'},{'\xbc','\xc1'},{'\xbc','\xbf'}, + {'\x00','\x00'},{'\xe5','\xb3'},{'\xd9','\x5a'},{'\xbc','\xb2'},{'\xe5','\xb9'}, + {'\xe5','\xb0'},{'\x00','\x00'},{'\xbc','\xc2'},{'\xe5','\xb8'},{'\xba','\x4d'}, + {'\xbc','\xb7'},{'\xe1','\xe4'},{'\x00','\x00'},{'\x00','\x00'},{'\xbc','\xba'}, + {'\x00','\x00'},{'\xbc','\xbe'},{'\xbc','\xc0'},{'\xbc','\xbd'},{'\xbc','\xbc'}, + {'\x9a','\xb7'},{'\xbc','\xb6'},{'\xe5','\xbb'},{'\xbc','\xb3'},{'\xbc','\xc3'}, + {'\x9a','\xb8'},{'\x8a','\xc6'},{'\x9a','\xb9'},{'\x8a','\xc9'},{'\x8f','\x76'}, + {'\x82','\x4d'},{'\x8f','\xfe'},{'\xbe','\xd8'},{'\xbe','\xd9'},{'\xe9','\xa9'}, + {'\xbe','\xe2'},{'\xbe','\xdf'},{'\x90','\xc4'},{'\xbe','\xd6'},{'\xbe','\xdd'}, + {'\xe9','\xab'},{'\xbe','\xdb'},{'\xbe','\xd5'},{'\x00','\x00'},{'\xbe','\xdc'}, + {'\x00','\x00'},{'\xe9','\xa8'},{'\xc0','\xbb'},{'\xbe','\xd7'},{'\x00','\x00'}, + {'\xbe','\xde'},{'\xc0','\xba'},{'\xe9','\xa7'},{'\xe9','\xa6'},{'\x00','\x00'}, + {'\xbe','\xe0'},{'\xa0','\x5d'},{'\xbe','\xe1'},{'\x00','\x00'},{'\xe9','\xa5'}, + {'\xe9','\xa4'},{'\xc0','\xbc'},{'\xe9','\xae'},{'\xbe','\xda'},{'\xe9','\xac'}, + {'\x00','\x00'},{'\x9a','\xba'},{'\x8a','\xc8'},{'\x00','\x00'},{'\xc0','\xbd'}, + {'\x90','\xc5'},{'\xc0','\xc2'},{'\xec','\xea'},{'\xec','\xec'},{'\x9a','\xbb'}, + {'\xc0','\xbf'},{'\xfb','\xa3'},{'\xec','\xed'},{'\xec','\xe9'},{'\x95','\xc8'}, + {'\xec','\xeb'},{'\xc0','\xc0'},{'\xc0','\xc3'},{'\x00','\x00'},{'\xec','\xe8'}, + {'\xc0','\xbe'},{'\xc0','\xc1'},{'\xc2','\x59'},{'\xe9','\xad'},{'\xc2','\x58'}, + {'\x00','\x00'},{'\x90','\xc6'},{'\xc2','\x5e'},{'\xef','\xd4'},{'\x00','\x00'}, + {'\xc2','\x5c'},{'\xc2','\x5d'},{'\xef','\xd7'},{'\xef','\xd3'},{'\xc2','\x5a'}, + {'\xef','\xd1'},{'\xc3','\x6b'},{'\xef','\xd5'},{'\x00','\x00'},{'\xef','\xd6'}, + {'\xef','\xd2'},{'\x90','\xc7'},{'\xc2','\x5b'},{'\xf2','\x42'},{'\x00','\x00'}, + {'\xf2','\x45'},{'\x9a','\xbc'},{'\x00','\x00'},{'\xf2','\x46'},{'\xf2','\x44'}, + {'\xf2','\x47'},{'\xc3','\x6c'},{'\xf2','\x43'},{'\x9a','\xbd'},{'\x90','\x57'}, + {'\xf4','\x4e'},{'\xc4','\x64'},{'\xf4','\x4d'},{'\xf4','\x4c'},{'\xf4','\x4b'}, + {'\xc4','\x63'},{'\xc4','\x65'},{'\x00','\x00'},{'\xf5','\xcd'},{'\xc4','\xe2'}, + {'\xc4','\xe1'},{'\xa0','\x60'},{'\x9a','\xbe'},{'\xf6','\xe1'},{'\xf6','\xe0'}, + {'\xf6','\xe3'},{'\xc5','\xcb'},{'\xc5','\x75'},{'\xf7','\xdd'},{'\xf6','\xe2'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xf7','\xdc'},{'\xc5','\xcd'},{'\xc5','\xcc'}, + {'\xc5','\xf3'},{'\xf8','\xa9'},{'\xf8','\xef'},{'\xa4','\xe4'},{'\xfe','\x5b'}, + {'\x00','\x00'},{'\xd9','\x72'},{'\xe9','\xaf'},{'\xc6','\xd2'},{'\x90','\xc8'}, + {'\xa6','\xac'},{'\xca','\xf7'},{'\xa7','\xf1'},{'\xa7','\xef'},{'\x00','\x00'}, + {'\xa7','\xf0'},{'\x00','\x00'},{'\xcc','\xc1'},{'\xa9','\xf1'},{'\xac','\x46'}, + {'\x00','\x00'},{'\xce','\xe7'},{'\x00','\x00'},{'\xce','\xe8'},{'\x00','\x00'}, + {'\xac','\x47'},{'\xd1','\xce'},{'\x00','\x00'},{'\xae','\xc4'},{'\xae','\xc5'}, + {'\xd1','\xcd'},{'\x00','\x00'},{'\x87','\xda'},{'\x95','\xb4'},{'\x90','\xc9'}, + {'\xb1','\xd3'},{'\x00','\x00'},{'\xb1','\xcf'},{'\x00','\x00'},{'\xd5','\xa7'}, + {'\xb1','\xd6'},{'\xb1','\xd5'},{'\xb1','\xce'},{'\xb1','\xd1'},{'\xb1','\xd4'}, + {'\xb1','\xd0'},{'\x00','\x00'},{'\x89','\xe0'},{'\xd9','\x76'},{'\xb1','\xcd'}, + {'\xb4','\xaf'},{'\x9a','\xbf'},{'\x00','\x00'},{'\x00','\x00'},{'\xb4','\xb1'}, + {'\xb4','\xb2'},{'\xd9','\x75'},{'\xd9','\x78'},{'\xb4','\xb0'},{'\xd9','\x73'}, + {'\xd9','\x77'},{'\x00','\x00'},{'\xd9','\x74'},{'\x90','\xca'},{'\xb7','\x71'}, + {'\x9a','\xc0'},{'\x00','\x00'},{'\xdd','\xbc'},{'\x87','\xdb'},{'\x00','\x00'}, + {'\xba','\x56'},{'\xe1','\xf4'},{'\xbe','\xe3'},{'\xbc','\xc4'},{'\xe5','\xbd'}, + {'\xbc','\xc5'},{'\xbc','\xc6'},{'\xe5','\xbf'},{'\xe5','\xbe'},{'\xe5','\xc0'}, + {'\xe9','\xb1'},{'\x00','\x00'},{'\x00','\x00'},{'\xe9','\xb0'},{'\xec','\xef'}, + {'\xec','\xee'},{'\xc0','\xc4'},{'\xc0','\xc5'},{'\xf2','\x48'},{'\xfc','\xb7'}, + {'\x9a','\xc1'},{'\xa4','\xe5'},{'\x90','\xcb'},{'\x93','\x42'},{'\x00','\x00'}, + {'\x8a','\xbc'},{'\xd9','\x79'},{'\x00','\x00'},{'\x92','\xc7'},{'\x00','\x00'}, + {'\xb4','\xb4'},{'\xb4','\xb3'},{'\xdd','\xbd'},{'\x8c','\x75'},{'\xef','\xd8'}, + {'\xc4','\xe3'},{'\xf7','\xde'},{'\xa4','\xe6'},{'\x00','\x00'},{'\xae','\xc6'}, + {'\x00','\x00'},{'\xb1','\xd8'},{'\xb1','\xd7'},{'\xd9','\x7a'},{'\xd9','\x7b'}, + {'\xb7','\x72'},{'\xe1','\xf5'},{'\xba','\x57'},{'\xe9','\xb2'},{'\x00','\x00'}, + {'\xa4','\xe7'},{'\xa5','\xb8'},{'\x00','\x00'},{'\xa9','\xf2'},{'\xcc','\xc2'}, + {'\x84','\x53'},{'\xce','\xe9'},{'\xac','\x48'},{'\xb1','\xd9'},{'\x8a','\xca'}, + {'\xd9','\x7c'},{'\xb4','\xb5'},{'\xb7','\x73'},{'\x00','\x00'},{'\xe5','\xc1'}, + {'\xe5','\xc2'},{'\x00','\x00'},{'\x9a','\xc2'},{'\xec','\xf0'},{'\xc2','\x5f'}, + {'\xf8','\xf0'},{'\xa4','\xe8'},{'\x00','\x00'},{'\xcc','\xc3'},{'\xa9','\xf3'}, + {'\xac','\x49'},{'\x9a','\xc3'},{'\xce','\xea'},{'\x00','\x00'},{'\xae','\xc7'}, + {'\xd1','\xd2'},{'\xd1','\xd0'},{'\xd1','\xd1'},{'\xae','\xc8'},{'\xd1','\xcf'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xb1','\xdb'}, + {'\xb1','\xdc'},{'\xd5','\xa8'},{'\xb1','\xdd'},{'\xb1','\xda'},{'\xd9','\x7d'}, + {'\x9a','\xc4'},{'\xd9','\x7e'},{'\xdd','\xbe'},{'\x9a','\xc5'},{'\x00','\x00'}, + {'\xba','\x59'},{'\xba','\x58'},{'\x00','\x00'},{'\x90','\xcc'},{'\xec','\xf1'}, + {'\xef','\xd9'},{'\x00','\x00'},{'\xf2','\x4a'},{'\xf2','\x49'},{'\xf4','\x4f'}, + {'\xc6','\xd3'},{'\xc9','\x5e'},{'\xac','\x4a'},{'\x9a','\xc6'},{'\x00','\x00'}, + {'\xa4','\xe9'},{'\xa5','\xb9'},{'\x8a','\xf6'},{'\xa6','\xae'},{'\xa6','\xad'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa6','\xaf'},{'\xa6','\xb0'},{'\xc9','\xee'}, + {'\xc9','\xed'},{'\xca','\xf8'},{'\xa7','\xf2'},{'\xca','\xfb'},{'\xca','\xfa'}, + {'\xca','\xf9'},{'\xca','\xfc'},{'\x83','\xba'},{'\x8b','\x77'},{'\x85','\xd0'}, + {'\x00','\x00'},{'\xa9','\xf4'},{'\xcc','\xc9'},{'\xcc','\xc5'},{'\xcc','\xce'}, + {'\x00','\x00'},{'\x9a','\xc7'},{'\xa9','\xfb'},{'\x00','\x00'},{'\xa9','\xf9'}, + {'\xcc','\xca'},{'\xcc','\xc6'},{'\xcc','\xcd'},{'\xa9','\xf8'},{'\xaa','\x40'}, + {'\xcc','\xc8'},{'\xcc','\xc4'},{'\xa9','\xfe'},{'\xcc','\xcb'},{'\xa9','\xf7'}, + {'\xcc','\xcc'},{'\xa9','\xfa'},{'\xa9','\xfc'},{'\xcc','\xd0'},{'\xcc','\xcf'}, + {'\xcc','\xc7'},{'\xa9','\xf6'},{'\xa9','\xf5'},{'\xa9','\xfd'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x9a','\xc8'},{'\x88','\xe8'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xce','\xef'},{'\xce','\xf5'},{'\x90','\xcd'},{'\xac','\x50'},{'\xac','\x4d'}, + {'\xce','\xec'},{'\xce','\xf1'},{'\x9a','\xc9'},{'\xac','\x53'},{'\xac','\x4b'}, + {'\xce','\xf0'},{'\xac','\x4e'},{'\xac','\x51'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xce','\xf3'},{'\x00','\x00'},{'\xac','\x4c'},{'\xce','\xf8'},{'\xac','\x4f'}, + {'\x95','\xfe'},{'\xac','\x52'},{'\xce','\xed'},{'\xce','\xf2'},{'\xce','\xf6'}, + {'\xce','\xee'},{'\xce','\xeb'},{'\x00','\x00'},{'\x00','\x00'},{'\xce','\xf7'}, + {'\xce','\xf4'},{'\x90','\xce'},{'\x84','\x54'},{'\x00','\x00'},{'\x8d','\x46'}, + {'\x90','\xcf'},{'\x00','\x00'},{'\xae','\xd0'},{'\xae','\xc9'},{'\xae','\xcc'}, + {'\x90','\xd0'},{'\xae','\xcf'},{'\x00','\x00'},{'\xd1','\xd5'},{'\xfc','\x62'}, + {'\xae','\xca'},{'\xd1','\xd3'},{'\x83','\xbb'},{'\xae','\xce'},{'\x9d','\x59'}, + {'\x00','\x00'},{'\xae','\xcb'},{'\x00','\x00'},{'\xd1','\xd6'},{'\xae','\xcd'}, + {'\x88','\xe6'},{'\x88','\xe7'},{'\x85','\xcf'},{'\x85','\xce'},{'\x90','\xd1'}, + {'\x00','\x00'},{'\xd5','\xac'},{'\xb1','\xdf'},{'\xd5','\xab'},{'\xd5','\xad'}, + {'\xb1','\xde'},{'\xb1','\xe3'},{'\xd1','\xd4'},{'\x00','\x00'},{'\xd5','\xaa'}, + {'\xd5','\xae'},{'\x9a','\xca'},{'\xb1','\xe0'},{'\xd5','\xa9'},{'\xb1','\xe2'}, + {'\xfc','\x63'},{'\xb1','\xe1'},{'\x90','\xd2'},{'\xd9','\xa7'},{'\x9a','\xcb'}, + {'\xd9','\xa2'},{'\x00','\x00'},{'\xb4','\xb6'},{'\xb4','\xba'},{'\xb4','\xb7'}, + {'\xd9','\xa5'},{'\xd9','\xa8'},{'\x90','\xd3'},{'\xb4','\xb8'},{'\x00','\x00'}, + {'\xb4','\xb9'},{'\xb4','\xbe'},{'\xdd','\xc7'},{'\xd9','\xa6'},{'\xb4','\xbc'}, + {'\xd9','\xa3'},{'\xd9','\xa1'},{'\x9a','\xcc'},{'\xb4','\xbd'},{'\x00','\x00'}, + {'\xd9','\xa4'},{'\x92','\x7d'},{'\x87','\xdc'},{'\x90','\xd4'},{'\xb7','\x79'}, + {'\x9a','\xcd'},{'\xdd','\xbf'},{'\xb7','\x76'},{'\xb7','\x77'},{'\xb7','\x75'}, + {'\xdd','\xc4'},{'\xdd','\xc3'},{'\xdd','\xc0'},{'\xb7','\x7b'},{'\xfe','\x7a'}, + {'\x00','\x00'},{'\xdd','\xc2'},{'\xb4','\xbb'},{'\x9a','\xce'},{'\x00','\x00'}, + {'\xdd','\xc6'},{'\xdd','\xc1'},{'\xb7','\x78'},{'\xb7','\x74'},{'\xb7','\x7a'}, + {'\xdd','\xc5'},{'\x9a','\xcf'},{'\x00','\x00'},{'\x00','\x00'},{'\xba','\x5c'}, + {'\x00','\x00'},{'\xe1','\xf8'},{'\xe1','\xf7'},{'\xe1','\xf6'},{'\xba','\x5a'}, + {'\x00','\x00'},{'\x9a','\xd0'},{'\x00','\x00'},{'\x93','\xef'},{'\x89','\xe2'}, + {'\xba','\x5b'},{'\xe5','\xc5'},{'\xe5','\xc8'},{'\xbc','\xc8'},{'\x00','\x00'}, + {'\x9a','\xd1'},{'\xbc','\xc7'},{'\xe5','\xc9'},{'\xe5','\xc4'},{'\xbc','\xca'}, + {'\xe5','\xc6'},{'\x9a','\xd2'},{'\xbc','\xc9'},{'\xe5','\xc3'},{'\x9a','\xd3'}, + {'\xe5','\xc7'},{'\xbe','\xe9'},{'\xbe','\xe6'},{'\xe9','\xbb'},{'\xe9','\xba'}, + {'\x90','\xd5'},{'\xe9','\xb9'},{'\xe9','\xb4'},{'\x90','\xd6'},{'\xe9','\xb5'}, + {'\x90','\xd7'},{'\x00','\x00'},{'\x00','\x00'},{'\xbe','\xe7'},{'\x00','\x00'}, + {'\xbe','\xe4'},{'\xbe','\xe8'},{'\xe9','\xb3'},{'\xbe','\xe5'},{'\xe9','\xb6'}, + {'\xe9','\xb7'},{'\xe9','\xbc'},{'\x9a','\xd4'},{'\x9a','\xd5'},{'\xe9','\xb8'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xec','\xf2'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xc0','\xc7'},{'\x00','\x00'},{'\xef','\xdc'},{'\xc0','\xc6'}, + {'\xef','\xda'},{'\xef','\xdb'},{'\xc2','\x60'},{'\xc3','\x6e'},{'\xf2','\x4b'}, + {'\x00','\x00'},{'\xc3','\x6d'},{'\x00','\x00'},{'\x00','\x00'},{'\xf4','\x51'}, + {'\xf4','\x52'},{'\x00','\x00'},{'\xc4','\x66'},{'\x9d','\xca'},{'\xf4','\x50'}, + {'\xc4','\xe4'},{'\x00','\x00'},{'\xf7','\xdf'},{'\xc5','\xce'},{'\xf8','\xaa'}, + {'\xf8','\xab'},{'\x00','\x00'},{'\xa4','\xea'},{'\xa0','\x58'},{'\xa6','\xb1'}, + {'\xa6','\xb2'},{'\xa7','\xf3'},{'\x90','\xd8'},{'\xcc','\xd1'},{'\xac','\x54'}, + {'\xae','\xd1'},{'\xb1','\xe4'},{'\x90','\xd9'},{'\x90','\xda'},{'\xb0','\xd2'}, + {'\x93','\xfb'},{'\xb4','\xbf'},{'\xb4','\xc0'},{'\xb3','\xcc'},{'\xd9','\xa9'}, + {'\x9a','\xd6'},{'\xb7','\x7c'},{'\xe1','\xfa'},{'\xe1','\xf9'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa4','\xeb'},{'\xa6','\xb3'},{'\xcc','\xd2'},{'\xaa','\x42'}, + {'\x9a','\xd7'},{'\xaa','\x41'},{'\x90','\xdb'},{'\xce','\xf9'},{'\xce','\xfa'}, + {'\x00','\x00'},{'\xd1','\xd7'},{'\xd1','\xd8'},{'\xae','\xd2'},{'\xae','\xd3'}, + {'\x90','\xdc'},{'\xae','\xd4'},{'\xd5','\xaf'},{'\x9a','\xd8'},{'\x00','\x00'}, + {'\xb1','\xe6'},{'\x00','\x00'},{'\xb4','\xc2'},{'\xfc','\x64'},{'\xb4','\xc1'}, + {'\xdd','\xc8'},{'\xdf','\x7a'},{'\xe1','\xfb'},{'\xe9','\xbd'},{'\x00','\x00'}, + {'\xfe','\x5e'},{'\xc2','\x61'},{'\xc4','\x67'},{'\xa4','\xec'},{'\x91','\xd1'}, + {'\xa5','\xbc'},{'\xa5','\xbd'},{'\xa5','\xbb'},{'\xa5','\xbe'},{'\xa5','\xba'}, + {'\x84','\x7b'},{'\x00','\x00'},{'\xa6','\xb6'},{'\x00','\x00'},{'\xc9','\xf6'}, + {'\xa6','\xb5'},{'\xa6','\xb7'},{'\x95','\x7c'},{'\x90','\xdd'},{'\xc9','\xf1'}, + {'\xc9','\xf0'},{'\xc9','\xf3'},{'\xc9','\xf2'},{'\xc9','\xf5'},{'\xa6','\xb4'}, + {'\xc9','\xef'},{'\xc9','\xf4'},{'\x84','\x59'},{'\x94','\x78'},{'\x8b','\x59'}, + {'\x8c','\xd0'},{'\x9a','\xd9'},{'\xca','\xfd'},{'\xa7','\xfd'},{'\xca','\xfe'}, + {'\xcb','\x43'},{'\xa7','\xfc'},{'\x00','\x00'},{'\xcb','\x47'},{'\xcb','\x42'}, + {'\xcb','\x45'},{'\xa7','\xf5'},{'\xa7','\xf6'},{'\xa7','\xf7'},{'\xa7','\xf8'}, + {'\x00','\x00'},{'\xa8','\x40'},{'\x00','\x00'},{'\xcb','\x41'},{'\xa7','\xfa'}, + {'\xa8','\x41'},{'\x00','\x00'},{'\xcb','\x40'},{'\xcb','\x46'},{'\x00','\x00'}, + {'\xa7','\xf9'},{'\xcb','\x44'},{'\xa7','\xfb'},{'\xa7','\xf4'},{'\xa7','\xfe'}, + {'\x84','\x57'},{'\x94','\x5c'},{'\x94','\x79'},{'\x90','\xde'},{'\x83','\x53'}, + {'\x90','\xdf'},{'\xfb','\xa6'},{'\x85','\xd4'},{'\x8e','\x72'},{'\xaa','\x57'}, + {'\x9a','\xda'},{'\xcc','\xd4'},{'\xaa','\x43'},{'\x9d','\x72'},{'\xaa','\x4d'}, + {'\xaa','\x4e'},{'\xaa','\x46'},{'\xaa','\x58'},{'\xaa','\x48'},{'\xcc','\xdc'}, + {'\xaa','\x53'},{'\xcc','\xd7'},{'\xaa','\x49'},{'\xcc','\xe6'},{'\xcc','\xe7'}, + {'\xcc','\xdf'},{'\xcc','\xd8'},{'\xaa','\x56'},{'\xcc','\xe4'},{'\xaa','\x51'}, + {'\xaa','\x4f'},{'\x00','\x00'},{'\xcc','\xe5'},{'\x00','\x00'},{'\xcc','\xe3'}, + {'\xcc','\xdb'},{'\xcc','\xd3'},{'\xcc','\xda'},{'\xaa','\x4a'},{'\x00','\x00'}, + {'\xaa','\x50'},{'\x00','\x00'},{'\xaa','\x44'},{'\xcc','\xde'},{'\xcc','\xdd'}, + {'\xcc','\xd5'},{'\x9a','\xdb'},{'\xaa','\x52'},{'\xcc','\xe1'},{'\xcc','\xd6'}, + {'\xaa','\x55'},{'\xcc','\xe8'},{'\xaa','\x45'},{'\x00','\x00'},{'\xaa','\x4c'}, + {'\xcc','\xd9'},{'\xcc','\xe2'},{'\xaa','\x54'},{'\x00','\x00'},{'\xaa','\x47'}, + {'\xaa','\x4b'},{'\x87','\xe5'},{'\xcc','\xe0'},{'\x94','\xfd'},{'\x94','\x7a'}, + {'\x87','\xe0'},{'\x84','\xe5'},{'\x9a','\xdc'},{'\x8f','\xdc'},{'\x90','\xe0'}, + {'\x90','\xe1'},{'\x8d','\xdf'},{'\x90','\xe2'},{'\x86','\xd2'},{'\x85','\xd6'}, + {'\xfc','\x66'},{'\x84','\x58'},{'\xcf','\x5b'},{'\xac','\x5c'},{'\xac','\x69'}, + {'\x95','\x45'},{'\xcf','\x56'},{'\xcf','\x4c'},{'\xac','\x62'},{'\xcf','\x4a'}, + {'\xac','\x5b'},{'\xcf','\x45'},{'\xac','\x65'},{'\xcf','\x52'},{'\xce','\xfe'}, + {'\xcf','\x41'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9a','\xdd'}, + {'\xcf','\x44'},{'\xce','\xfb'},{'\xcf','\x51'},{'\xcf','\x61'},{'\xac','\x60'}, + {'\xcf','\x46'},{'\xcf','\x58'},{'\x00','\x00'},{'\xce','\xfd'},{'\xcf','\x5f'}, + {'\xcf','\x60'},{'\xcf','\x63'},{'\xcf','\x5a'},{'\xcf','\x4b'},{'\xcf','\x53'}, + {'\xac','\x66'},{'\xac','\x59'},{'\xac','\x61'},{'\xac','\x6d'},{'\xac','\x56'}, + {'\xac','\x58'},{'\x00','\x00'},{'\x9a','\xde'},{'\x9a','\xdf'},{'\xcf','\x43'}, + {'\xac','\x6a'},{'\xac','\x63'},{'\xcf','\x5d'},{'\xcf','\x40'},{'\xac','\x6c'}, + {'\xac','\x67'},{'\xcf','\x49'},{'\x8a','\xce'},{'\x00','\x00'},{'\xac','\x6b'}, + {'\xcf','\x50'},{'\xcf','\x48'},{'\xac','\x64'},{'\xcf','\x5c'},{'\xcf','\x54'}, + {'\x00','\x00'},{'\xac','\x5e'},{'\xcf','\x62'},{'\xcf','\x47'},{'\xac','\x5a'}, + {'\xcf','\x59'},{'\xcf','\x4f'},{'\xac','\x5f'},{'\xcf','\x55'},{'\xac','\x57'}, + {'\xce','\xfc'},{'\xac','\x68'},{'\xae','\xe3'},{'\xac','\x5d'},{'\xcf','\x4e'}, + {'\xcf','\x4d'},{'\xcf','\x42'},{'\xfc','\x67'},{'\xcf','\x5e'},{'\x90','\xe3'}, + {'\xcf','\x57'},{'\x90','\xe4'},{'\x94','\x5a'},{'\xac','\x55'},{'\x90','\xe5'}, + {'\x90','\xe6'},{'\x94','\x4d'},{'\x94','\x51'},{'\x92','\x48'},{'\x90','\xe7'}, + {'\x00','\x00'},{'\x87','\xe1'},{'\x84','\xe7'},{'\x89','\xe6'},{'\x8f','\xdb'}, + {'\x84','\xe6'},{'\x8f','\xdd'},{'\x9a','\xe1'},{'\x8f','\xba'},{'\x8c','\x77'}, + {'\x9a','\xe2'},{'\x88','\xeb'},{'\xd1','\xec'},{'\xae','\xea'},{'\xd1','\xed'}, + {'\x00','\x00'},{'\xd1','\xe1'},{'\xae','\xdf'},{'\xae','\xeb'},{'\x00','\x00'}, + {'\xd1','\xda'},{'\x9a','\xe3'},{'\xd1','\xe3'},{'\xd1','\xeb'},{'\x90','\xe8'}, + {'\xd1','\xd9'},{'\xd1','\xf4'},{'\xae','\xd5'},{'\xfe','\x45'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd1','\xf3'},{'\xd1','\xee'},{'\x00','\x00'},{'\xd1','\xef'}, + {'\xae','\xdd'},{'\xae','\xe8'},{'\xd1','\xe5'},{'\x00','\x00'},{'\xd1','\xe6'}, + {'\xd1','\xf0'},{'\xd1','\xe7'},{'\x00','\x00'},{'\xd1','\xe2'},{'\xd1','\xdc'}, + {'\xd1','\xdd'},{'\xd1','\xea'},{'\xd1','\xe4'},{'\x9a','\xe4'},{'\x87','\xde'}, + {'\xae','\xd6'},{'\xae','\xda'},{'\xd1','\xf2'},{'\xd1','\xde'},{'\xae','\xe6'}, + {'\xae','\xe2'},{'\x90','\x6a'},{'\x00','\x00'},{'\xae','\xe5'},{'\xae','\xec'}, + {'\xae','\xdb'},{'\xae','\xe7'},{'\xd1','\xe9'},{'\xae','\xe9'},{'\xae','\xd8'}, + {'\x9a','\xe5'},{'\xae','\xd7'},{'\xd1','\xdb'},{'\x90','\xe9'},{'\xd1','\xdf'}, + {'\xae','\xe0'},{'\xd1','\xf1'},{'\xd1','\xe8'},{'\xd1','\xe0'},{'\xae','\xe4'}, + {'\xae','\xe1'},{'\x90','\xea'},{'\xae','\xd9'},{'\xae','\xdc'},{'\x90','\xeb'}, + {'\x9a','\xe6'},{'\x00','\x00'},{'\x00','\x00'},{'\x90','\xec'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x92','\x51'},{'\x82','\x7c'},{'\x00','\x00'},{'\x92','\xcc'}, + {'\x8d','\xde'},{'\x88','\xef'},{'\x85','\xd5'},{'\x89','\xe3'},{'\x8e','\x71'}, + {'\x88','\xed'},{'\x88','\xe9'},{'\x89','\xe5'},{'\x87','\xe3'},{'\x87','\xdf'}, + {'\x00','\x00'},{'\xd5','\xc4'},{'\x00','\x00'},{'\xd5','\xb4'},{'\xd5','\xb5'}, + {'\xd5','\xb9'},{'\x00','\x00'},{'\xd5','\xc8'},{'\xd5','\xc5'},{'\x00','\x00'}, + {'\xd5','\xbe'},{'\xd5','\xbd'},{'\xb1','\xed'},{'\xd5','\xc1'},{'\xd5','\xd0'}, + {'\xd5','\xb0'},{'\x00','\x00'},{'\xd5','\xd1'},{'\xd5','\xc3'},{'\xd5','\xd5'}, + {'\xd5','\xc9'},{'\xb1','\xec'},{'\xd5','\xc7'},{'\xb1','\xe7'},{'\xb1','\xfc'}, + {'\xb1','\xf2'},{'\x9a','\xe7'},{'\xb1','\xf6'},{'\xb1','\xf5'},{'\xd5','\xb1'}, + {'\x9a','\xe8'},{'\xd5','\xce'},{'\xd5','\xd4'},{'\xd5','\xcc'},{'\xd5','\xd3'}, + {'\x90','\xed'},{'\x00','\x00'},{'\xd5','\xc0'},{'\xd5','\xb2'},{'\xd5','\xd2'}, + {'\xd5','\xc2'},{'\xb1','\xea'},{'\xb1','\xf7'},{'\x00','\x00'},{'\xd5','\xcb'}, + {'\xb1','\xf0'},{'\xfb','\x58'},{'\x00','\x00'},{'\x00','\x00'},{'\xd5','\xca'}, + {'\xd5','\xb3'},{'\xb1','\xf8'},{'\x00','\x00'},{'\xb1','\xfa'},{'\xd5','\xcd'}, + {'\xb1','\xfb'},{'\xb1','\xe9'},{'\xd5','\xba'},{'\xd5','\xcf'},{'\x00','\x00'}, + {'\x86','\xbb'},{'\xb1','\xef'},{'\xb1','\xf9'},{'\xd5','\xbc'},{'\xd5','\xc6'}, + {'\xd5','\xb7'},{'\xd5','\xbb'},{'\xb1','\xf4'},{'\xd5','\xb6'},{'\xb1','\xe8'}, + {'\xb1','\xf1'},{'\xb1','\xee'},{'\xd5','\xbf'},{'\xae','\xde'},{'\xd9','\xc0'}, + {'\xb1','\xeb'},{'\xfc','\x68'},{'\x00','\x00'},{'\x00','\x00'},{'\x90','\xee'}, + {'\x94','\x7b'},{'\x00','\x00'},{'\x82','\x6f'},{'\x9a','\xe9'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x89','\xe4'},{'\x00','\x00'},{'\x8c','\x78'},{'\x9a','\xea'}, + {'\xb1','\xf3'},{'\x9a','\xeb'},{'\xd9','\xc3'},{'\xd9','\xd9'},{'\xd9','\xce'}, + {'\xb4','\xd6'},{'\xfc','\x6c'},{'\xb4','\xd1'},{'\xd9','\xbd'},{'\xb4','\xd2'}, + {'\xd9','\xcd'},{'\x90','\xef'},{'\xd9','\xc6'},{'\xd9','\xd3'},{'\xb4','\xce'}, + {'\xd9','\xab'},{'\xd9','\xd5'},{'\xb4','\xc4'},{'\xd9','\xb3'},{'\xb4','\xc7'}, + {'\xb4','\xc6'},{'\x00','\x00'},{'\xb4','\xd7'},{'\x00','\x00'},{'\xd9','\xad'}, + {'\xd9','\xcf'},{'\xd9','\xd0'},{'\xb4','\xc9'},{'\xb4','\xc5'},{'\xd9','\xbb'}, + {'\x00','\x00'},{'\xb4','\xd0'},{'\xd9','\xb6'},{'\x00','\x00'},{'\xd9','\xd1'}, + {'\xb4','\xcc'},{'\xd9','\xc9'},{'\xd9','\xd6'},{'\xd9','\xb0'},{'\xd9','\xb5'}, + {'\xd9','\xaf'},{'\x00','\x00'},{'\xb4','\xcb'},{'\xd9','\xc2'},{'\xdd','\xde'}, + {'\xd9','\xb1'},{'\xb4','\xcf'},{'\xd9','\xba'},{'\xd9','\xd2'},{'\xb4','\xca'}, + {'\xd9','\xb7'},{'\xd9','\xb4'},{'\xd9','\xc5'},{'\xb4','\xcd'},{'\xb4','\xc3'}, + {'\xb4','\xd9'},{'\xd9','\xc8'},{'\xd9','\xc7'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xfc','\x6b'},{'\xfc','\x6a'},{'\x9a','\xec'},{'\x9a','\xed'},{'\xd9','\xac'}, + {'\xb4','\xc8'},{'\xd9','\xd4'},{'\xd9','\xbc'},{'\xd9','\xbe'},{'\x9a','\xee'}, + {'\xd9','\xcb'},{'\xd9','\xca'},{'\xd9','\xaa'},{'\xb4','\xd3'},{'\xb4','\xd5'}, + {'\xd9','\xb2'},{'\xd9','\xb9'},{'\xd9','\xc1'},{'\xb4','\xd4'},{'\xd9','\xb8'}, + {'\xd9','\xc4'},{'\xd9','\xd7'},{'\x00','\x00'},{'\xd9','\xcc'},{'\x9a','\xef'}, + {'\x94','\x49'},{'\xfe','\x4f'},{'\x94','\x41'},{'\x92','\xb6'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x8b','\x79'},{'\x8e','\xb8'},{'\x94','\xa2'},{'\x90','\xf3'}, + {'\x94','\xa1'},{'\x90','\x6b'},{'\xd9','\xd8'},{'\x90','\xf4'},{'\x00','\x00'}, + {'\x94','\x7d'},{'\x00','\x00'},{'\xd9','\xae'},{'\x00','\x00'},{'\xfc','\x69'}, + {'\x88','\xec'},{'\x00','\x00'},{'\xdd','\xf2'},{'\xb7','\xa6'},{'\x00','\x00'}, + {'\xdd','\xf0'},{'\xdd','\xdb'},{'\xdd','\xe0'},{'\xdd','\xd9'},{'\x90','\xfd'}, + {'\xdd','\xec'},{'\xdd','\xcb'},{'\xdd','\xd2'},{'\x00','\x00'},{'\xdd','\xea'}, + {'\xdd','\xf4'},{'\xdd','\xdc'},{'\xfc','\x6f'},{'\xdd','\xcf'},{'\xdd','\xe2'}, + {'\xdd','\xe7'},{'\xdd','\xd3'},{'\x9a','\xf0'},{'\xdd','\xe4'},{'\xdd','\xd0'}, + {'\x9a','\xf1'},{'\x00','\x00'},{'\xdd','\xd7'},{'\xdd','\xd8'},{'\xb7','\xa8'}, + {'\xdd','\xeb'},{'\xdd','\xe9'},{'\x00','\x00'},{'\xdd','\xcc'},{'\xdd','\xee'}, + {'\x00','\x00'},{'\xdd','\xef'},{'\xdd','\xf1'},{'\xb7','\xac'},{'\xb7','\xa4'}, + {'\x82','\x6c'},{'\xd5','\xb8'},{'\xdd','\xd4'},{'\xdd','\xe6'},{'\xdd','\xd5'}, + {'\xb7','\xa1'},{'\xb7','\xb1'},{'\xdd','\xed'},{'\xb7','\xaf'},{'\xb7','\xab'}, + {'\xdd','\xca'},{'\xb7','\xa3'},{'\x90','\xfe'},{'\xdd','\xcd'},{'\xb7','\xb0'}, + {'\x9a','\xf2'},{'\xdd','\xdd'},{'\xdd','\xc9'},{'\x9a','\xf3'},{'\xb7','\xa9'}, + {'\xdd','\xe1'},{'\xdd','\xd1'},{'\xb7','\xaa'},{'\xdd','\xda'},{'\xb7','\x7e'}, + {'\xb4','\xd8'},{'\xdd','\xe3'},{'\xd9','\xbf'},{'\xdd','\xce'},{'\x9a','\xf4'}, + {'\xfc','\x6d'},{'\xdd','\xe8'},{'\xb7','\xa5'},{'\xdd','\xe5'},{'\xb7','\xa2'}, + {'\xdd','\xdf'},{'\xb7','\xad'},{'\xdd','\xd6'},{'\xdd','\xf3'},{'\x87','\xe2'}, + {'\x92','\x62'},{'\x94','\xa3'},{'\x00','\x00'},{'\xfc','\x6e'},{'\x94','\xa4'}, + {'\xb7','\xa7'},{'\xde','\xc6'},{'\x8d','\x6e'},{'\x9a','\xf5'},{'\xb7','\xae'}, + {'\x8b','\xf9'},{'\x8b','\x7a'},{'\x90','\x40'},{'\x94','\x45'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xe2','\x4a'},{'\xe2','\x48'},{'\x00','\x00'},{'\xe2','\x5e'}, + {'\xe2','\x46'},{'\x00','\x00'},{'\xe2','\x58'},{'\xb7','\x7d'},{'\xba','\x5f'}, + {'\xe2','\x42'},{'\xe2','\x5d'},{'\x95','\x67'},{'\xe2','\x47'},{'\xe2','\x55'}, + {'\xba','\x64'},{'\xba','\x5d'},{'\x00','\x00'},{'\xe2','\x5b'},{'\x9a','\xf6'}, + {'\xe2','\x40'},{'\xe2','\x5a'},{'\x9a','\xf7'},{'\xba','\x6f'},{'\xe2','\x51'}, + {'\xe2','\x61'},{'\xba','\x6d'},{'\xe2','\x49'},{'\xba','\x5e'},{'\xe2','\x4b'}, + {'\xe2','\x59'},{'\xba','\x67'},{'\xe2','\x44'},{'\xba','\x6b'},{'\xba','\x61'}, + {'\xe2','\x4d'},{'\xe2','\x43'},{'\xe1','\xfc'},{'\xfc','\x71'},{'\xe2','\x57'}, + {'\xba','\x68'},{'\xe2','\x60'},{'\xe1','\xfd'},{'\xba','\x65'},{'\x00','\x00'}, + {'\xe2','\x53'},{'\x00','\x00'},{'\xba','\x66'},{'\xe2','\x45'},{'\xe2','\x50'}, + {'\xe2','\x4c'},{'\xe2','\x4e'},{'\xfc','\x72'},{'\xba','\x60'},{'\xe2','\x5f'}, + {'\xba','\x6e'},{'\xe2','\x4f'},{'\x00','\x00'},{'\xe2','\x62'},{'\x91','\xee'}, + {'\x00','\x00'},{'\xe1','\xfe'},{'\xe2','\x54'},{'\xba','\x63'},{'\xba','\x6c'}, + {'\xba','\x6a'},{'\xe2','\x41'},{'\xe2','\x56'},{'\xba','\x69'},{'\x9a','\xf8'}, + {'\x00','\x00'},{'\xba','\x62'},{'\xe2','\x52'},{'\x9a','\xf9'},{'\x9a','\xfa'}, + {'\x00','\x00'},{'\x93','\xdb'},{'\xe2','\x5c'},{'\x00','\x00'},{'\x8a','\xcd'}, + {'\x00','\x00'},{'\x94','\xa5'},{'\x96','\x7d'},{'\x8a','\xcb'},{'\x8f','\xb9'}, + {'\x9b','\x41'},{'\xe5','\xd5'},{'\x00','\x00'},{'\xe5','\xd1'},{'\xe5','\xcd'}, + {'\xe5','\xe1'},{'\xe5','\xde'},{'\xbc','\xcd'},{'\xfc','\x75'},{'\x00','\x00'}, + {'\xe5','\xe5'},{'\xe5','\xd4'},{'\xbc','\xd8'},{'\xe5','\xdb'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xe5','\xd0'},{'\xe5','\xda'},{'\xbc','\xd5'},{'\xe5','\xee'}, + {'\x00','\x00'},{'\xe5','\xeb'},{'\xe5','\xdd'},{'\xe5','\xce'},{'\x96','\x7e'}, + {'\xfc','\x74'},{'\xe5','\xe2'},{'\xe5','\xe4'},{'\xbc','\xd1'},{'\xe5','\xd8'}, + {'\xe5','\xd3'},{'\xe5','\xca'},{'\xbc','\xce'},{'\xbc','\xd6'},{'\x9b','\x42'}, + {'\xe5','\xe7'},{'\xbc','\xd7'},{'\xe5','\xcb'},{'\xe5','\xed'},{'\xe5','\xe0'}, + {'\xe5','\xe6'},{'\xbc','\xd4'},{'\xfe','\x54'},{'\x96','\xce'},{'\xe5','\xe3'}, + {'\x00','\x00'},{'\xe5','\xea'},{'\x00','\x00'},{'\xbc','\xd9'},{'\x96','\xeb'}, + {'\xbc','\xd3'},{'\xe5','\xdc'},{'\xe5','\xcf'},{'\xe5','\xef'},{'\xe5','\xcc'}, + {'\xe5','\xe8'},{'\xbc','\xd0'},{'\x9b','\x43'},{'\xe5','\xd6'},{'\x9b','\x44'}, + {'\xe5','\xd7'},{'\xbc','\xcf'},{'\xbc','\xcc'},{'\xe5','\xd2'},{'\xbc','\xd2'}, + {'\x96','\xec'},{'\xbc','\xcb'},{'\x00','\x00'},{'\xe5','\xe9'},{'\xe5','\xec'}, + {'\xe5','\xd9'},{'\xe9','\xca'},{'\x92','\xb7'},{'\x88','\xea'},{'\x94','\x40'}, + {'\x9b','\x45'},{'\x9b','\x46'},{'\x94','\xa6'},{'\x89','\xe7'},{'\x96','\xed'}, + {'\x8c','\x76'},{'\xe9','\xc2'},{'\x9b','\x47'},{'\xe9','\xbe'},{'\xbe','\xf6'}, + {'\x96','\xee'},{'\x00','\x00'},{'\xbe','\xeb'},{'\xbe','\xf0'},{'\xbe','\xec'}, + {'\xe9','\xcc'},{'\xe9','\xd7'},{'\xbe','\xea'},{'\xe9','\xc4'},{'\xe9','\xcd'}, + {'\xe5','\xdf'},{'\xe9','\xce'},{'\x00','\x00'},{'\x9b','\x48'},{'\xbe','\xf1'}, + {'\x9b','\x49'},{'\xe9','\xdd'},{'\xbe','\xf5'},{'\xbe','\xf8'},{'\xe9','\xc0'}, + {'\x00','\x00'},{'\xbe','\xf4'},{'\x9b','\x4a'},{'\xe9','\xdb'},{'\xe9','\xdc'}, + {'\xe9','\xd2'},{'\xe9','\xd1'},{'\xe9','\xc9'},{'\xfc','\x77'},{'\x9b','\x4b'}, + {'\xe9','\xd3'},{'\xe9','\xda'},{'\xe9','\xd9'},{'\x9b','\x4c'},{'\xbe','\xef'}, + {'\xbe','\xed'},{'\xe9','\xcb'},{'\xe9','\xc8'},{'\x00','\x00'},{'\xe9','\xc5'}, + {'\xe9','\xd8'},{'\xbe','\xf7'},{'\xe9','\xd6'},{'\xbe','\xf3'},{'\xbe','\xf2'}, + {'\x9b','\x4d'},{'\xe9','\xd0'},{'\x96','\xef'},{'\xe9','\xbf'},{'\xe9','\xc1'}, + {'\xe9','\xc3'},{'\xe9','\xd5'},{'\xe9','\xcf'},{'\xbe','\xee'},{'\x00','\x00'}, + {'\xe9','\xc6'},{'\x00','\x00'},{'\xe9','\xd4'},{'\x00','\x00'},{'\x8b','\x78'}, + {'\x94','\xa7'},{'\x96','\xf8'},{'\x9b','\x4e'},{'\x00','\x00'},{'\xe9','\xc7'}, + {'\x00','\x00'},{'\x96','\xf9'},{'\x8b','\x7b'},{'\x94','\x7e'},{'\x00','\x00'}, + {'\x96','\xfc'},{'\x00','\x00'},{'\xc0','\xcf'},{'\xed','\x45'},{'\xc0','\xc8'}, + {'\xec','\xf5'},{'\x9b','\x4f'},{'\xed','\x41'},{'\xc0','\xca'},{'\xed','\x48'}, + {'\x00','\x00'},{'\xec','\xfc'},{'\x00','\x00'},{'\xec','\xf7'},{'\x9b','\x50'}, + {'\x00','\x00'},{'\xed','\x49'},{'\xec','\xf3'},{'\xec','\xfe'},{'\x9b','\x51'}, + {'\xc0','\xd1'},{'\xed','\x44'},{'\xed','\x4a'},{'\xec','\xfd'},{'\xc0','\xc9'}, + {'\xed','\x40'},{'\xec','\xf4'},{'\xc0','\xd0'},{'\x00','\x00'},{'\x9b','\x52'}, + {'\xed','\x47'},{'\xec','\xf9'},{'\xc0','\xcc'},{'\xfc','\x78'},{'\xec','\xfb'}, + {'\xec','\xf8'},{'\xc0','\xd2'},{'\xec','\xfa'},{'\xc0','\xcb'},{'\xc0','\xce'}, + {'\xed','\x43'},{'\xec','\xf6'},{'\xed','\x46'},{'\x9b','\x53'},{'\xed','\x42'}, + {'\x96','\xfd'},{'\x96','\xfe'},{'\x99','\xfe'},{'\xc2','\x63'},{'\xef','\xe7'}, + {'\xc2','\x68'},{'\xc2','\x69'},{'\x00','\x00'},{'\x9b','\x54'},{'\xfc','\x76'}, + {'\xc2','\x62'},{'\xef','\xe6'},{'\x9b','\x55'},{'\xef','\xe3'},{'\xef','\xe4'}, + {'\xc2','\x66'},{'\xef','\xde'},{'\xef','\xe2'},{'\xc2','\x65'},{'\x00','\x00'}, + {'\xef','\xdf'},{'\x9b','\x56'},{'\x00','\x00'},{'\x00','\x00'},{'\x9a','\xfe'}, + {'\xc2','\x67'},{'\xc2','\x64'},{'\x00','\x00'},{'\xef','\xdd'},{'\xef','\xe1'}, + {'\xef','\xe5'},{'\x95','\xe3'},{'\x9b','\x57'},{'\xfb','\xdc'},{'\xf2','\x51'}, + {'\xf2','\x4e'},{'\xf2','\x57'},{'\x00','\x00'},{'\xf2','\x56'},{'\xf2','\x54'}, + {'\xf2','\x4f'},{'\x00','\x00'},{'\xc3','\x72'},{'\x9b','\x58'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9b','\x59'},{'\xf2','\x50'},{'\xc3','\x71'}, + {'\xc0','\xcd'},{'\xf2','\x53'},{'\xc3','\x70'},{'\xf2','\x58'},{'\xf2','\x52'}, + {'\xf2','\x4d'},{'\xef','\xe0'},{'\x9c','\xf9'},{'\x00','\x00'},{'\x9d','\xe1'}, + {'\xc3','\x6f'},{'\x00','\x00'},{'\xf2','\x4c'},{'\xf4','\x56'},{'\x00','\x00'}, + {'\xf4','\x55'},{'\xf2','\x55'},{'\xc4','\x68'},{'\x00','\x00'},{'\xf4','\x59'}, + {'\xf4','\x5a'},{'\xf4','\x54'},{'\xf4','\x58'},{'\x00','\x00'},{'\xf4','\x53'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9b','\x5a'},{'\x00','\x00'},{'\xf5','\xd1'}, + {'\xf4','\x57'},{'\xc4','\xe7'},{'\xc4','\xe5'},{'\xf5','\xcf'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xf5','\xd2'},{'\x00','\x00'},{'\xf5','\xce'}, + {'\xf5','\xd0'},{'\xc4','\xe6'},{'\x9d','\xfe'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xf6','\xe5'},{'\xf6','\xe6'},{'\xc5','\x76'},{'\xf6','\xe4'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xf7','\xe2'},{'\xc5','\xcf'},{'\xf7','\xe0'}, + {'\xf7','\xe1'},{'\xf8','\xac'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\x56'}, + {'\xf8','\xf3'},{'\xf8','\xf1'},{'\xf8','\xf2'},{'\xf8','\xf4'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xfc','\x79'},{'\xf9','\xbb'},{'\x94','\xa8'},{'\xa4','\xed'}, + {'\xa6','\xb8'},{'\x8c','\xd1'},{'\xaa','\x59'},{'\x8a','\xcf'},{'\xcc','\xe9'}, + {'\x00','\x00'},{'\x87','\xe6'},{'\xcf','\x64'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd1','\xf5'},{'\xd1','\xf7'},{'\x00','\x00'},{'\xd1','\xf6'}, + {'\x00','\x00'},{'\xd1','\xf8'},{'\xb1','\xfd'},{'\xd5','\xd7'},{'\xd1','\xf9'}, + {'\x95','\xb9'},{'\xd5','\xd6'},{'\xd5','\xd8'},{'\xd5','\xd9'},{'\xd9','\xda'}, + {'\xb4','\xdb'},{'\xd9','\xdb'},{'\xd9','\xdd'},{'\xb4','\xdc'},{'\xb4','\xda'}, + {'\xd9','\xdc'},{'\x00','\x00'},{'\xdd','\xfa'},{'\xdd','\xf8'},{'\xdd','\xf7'}, + {'\x00','\x00'},{'\xdd','\xf6'},{'\xdd','\xf5'},{'\xb7','\xb2'},{'\xdd','\xf9'}, + {'\xba','\x70'},{'\xe2','\x63'},{'\xe2','\x65'},{'\xba','\x71'},{'\xe2','\x64'}, + {'\xbc','\xdb'},{'\x00','\x00'},{'\xbc','\xda'},{'\xe5','\xf0'},{'\xfc','\x7a'}, + {'\x92','\x6c'},{'\xe9','\xdf'},{'\xe9','\xde'},{'\xe9','\xe0'},{'\x9b','\x5b'}, + {'\x00','\x00'},{'\xbe','\xf9'},{'\x00','\x00'},{'\xed','\x4b'},{'\xc0','\xd3'}, + {'\x00','\x00'},{'\xef','\xe8'},{'\xc2','\x6a'},{'\xf2','\x59'},{'\xc5','\x77'}, + {'\xa4','\xee'},{'\xa5','\xbf'},{'\xa6','\xb9'},{'\xa8','\x42'},{'\xaa','\x5a'}, + {'\xaa','\x5b'},{'\x00','\x00'},{'\x93','\xc5'},{'\xac','\x6e'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd1','\xfa'},{'\x00','\x00'},{'\x92','\xd0'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xb7','\xb3'},{'\x92','\xc8'},{'\x93','\xf0'},{'\x00','\x00'}, + {'\xe6','\xd1'},{'\xbe','\xfa'},{'\xc2','\x6b'},{'\xa4','\xef'},{'\x9b','\x5c'}, + {'\xa6','\xba'},{'\x8c','\x79'},{'\x00','\x00'},{'\xcc','\xeb'},{'\xaa','\x5c'}, + {'\xcc','\xea'},{'\x9f','\x4e'},{'\xcf','\x65'},{'\xac','\x6f'},{'\xcf','\x66'}, + {'\x00','\x00'},{'\xac','\x70'},{'\x87','\xe7'},{'\xd1','\xfc'},{'\xae','\xee'}, + {'\xae','\xed'},{'\x92','\xcf'},{'\xd5','\xde'},{'\xd5','\xdc'},{'\xd5','\xdd'}, + {'\xd5','\xdb'},{'\x00','\x00'},{'\xd5','\xda'},{'\x8d','\xb5'},{'\x89','\xe8'}, + {'\xd9','\xde'},{'\xd9','\xe1'},{'\xb4','\xde'},{'\xd9','\xdf'},{'\xb4','\xdd'}, + {'\xd9','\xe0'},{'\x8e','\xe8'},{'\xdd','\xfb'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xe2','\x66'},{'\xe2','\x67'},{'\xe2','\x68'},{'\x8a','\xd1'},{'\xe5','\xf3'}, + {'\xe5','\xf2'},{'\xbc','\xdc'},{'\xe5','\xf1'},{'\xe5','\xf4'},{'\xe9','\xe1'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xe9','\xe2'},{'\xe9','\xe3'},{'\x00','\x00'}, + {'\xed','\x4c'},{'\xc0','\xd4'},{'\xc2','\x6c'},{'\xf2','\x5a'},{'\x9f','\x4f'}, + {'\xc4','\xe8'},{'\xc9','\x5f'},{'\x87','\xe8'},{'\xac','\x71'},{'\xcf','\x67'}, + {'\xae','\xef'},{'\x00','\x00'},{'\x00','\x00'},{'\xb1','\xfe'},{'\x92','\x5f'}, + {'\xb4','\xdf'},{'\xd9','\xe2'},{'\x00','\x00'},{'\xb7','\xb5'},{'\xb7','\xb4'}, + {'\x90','\xb5'},{'\x8a','\x75'},{'\xe2','\x69'},{'\xe2','\x6a'},{'\xbc','\xdd'}, + {'\xbc','\xde'},{'\xe9','\xe5'},{'\xe9','\xe4'},{'\xef','\xe9'},{'\xf7','\xe3'}, + {'\xa4','\xf0'},{'\xc9','\x60'},{'\xa5','\xc0'},{'\x93','\xd1'},{'\xa8','\x43'}, + {'\xcb','\x48'},{'\x00','\x00'},{'\xac','\x72'},{'\xb7','\xb6'},{'\xa4','\xf1'}, + {'\x84','\x65'},{'\xcf','\x68'},{'\xac','\x73'},{'\xcf','\x69'},{'\x89','\xe1'}, + {'\xc0','\xd5'},{'\xa4','\xf2'},{'\x9b','\x5d'},{'\x00','\x00'},{'\xcc','\xec'}, + {'\x94','\xa9'},{'\xcf','\x6a'},{'\x89','\xe9'},{'\xd2','\x42'},{'\xd2','\x41'}, + {'\xd1','\xfe'},{'\x00','\x00'},{'\xd1','\xfd'},{'\xd2','\x43'},{'\xd2','\x40'}, + {'\x00','\x00'},{'\xa0','\x62'},{'\xb2','\x40'},{'\xb2','\x41'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xb4','\xe0'},{'\xd9','\xe3'},{'\x00','\x00'},{'\xd9','\xe4'}, + {'\xd9','\xe5'},{'\x00','\x00'},{'\x8e','\xb9'},{'\x00','\x00'},{'\xde','\x41'}, + {'\xde','\x42'},{'\xde','\x40'},{'\xfc','\x7b'},{'\xdd','\xfd'},{'\xdd','\xfe'}, + {'\xb7','\xb7'},{'\xe2','\x6b'},{'\xe5','\xf7'},{'\xe5','\xf6'},{'\xe5','\xf5'}, + {'\xe5','\xf8'},{'\xe9','\xe7'},{'\xe9','\xe6'},{'\xbe','\xfb'},{'\xe9','\xe8'}, + {'\x8f','\xbb'},{'\xc0','\xd6'},{'\xed','\x4d'},{'\x00','\x00'},{'\xef','\xea'}, + {'\xf2','\x5b'},{'\xf6','\xe7'},{'\x00','\x00'},{'\xa4','\xf3'},{'\xa5','\xc2'}, + {'\xa5','\xc1'},{'\x00','\x00'},{'\xaa','\x5d'},{'\xc9','\x61'},{'\xc9','\x7e'}, + {'\xa6','\xbb'},{'\x92','\x6e'},{'\xc9','\xf7'},{'\xcb','\x49'},{'\xcb','\x4a'}, + {'\xaa','\x5e'},{'\x9b','\x5e'},{'\xcc','\xed'},{'\x00','\x00'},{'\xac','\x74'}, + {'\xcf','\x6b'},{'\xcf','\x6c'},{'\x84','\x5a'},{'\xae','\xf0'},{'\xae','\xf4'}, + {'\xd2','\x44'},{'\xae','\xf3'},{'\xae','\xf1'},{'\xae','\xf2'},{'\x84','\xec'}, + {'\xd5','\xdf'},{'\xb2','\x42'},{'\xb4','\xe3'},{'\x00','\x00'},{'\xb4','\xe1'}, + {'\xb4','\xe2'},{'\xd9','\xe6'},{'\x9b','\x5f'},{'\xa0','\x63'},{'\xba','\x72'}, + {'\xa4','\xf4'},{'\x9c','\xf3'},{'\xc9','\xa1'},{'\x95','\xeb'},{'\xa5','\xc3'}, + {'\xfe','\x40'},{'\x91','\xd2'},{'\xc9','\xa4'},{'\x00','\x00'},{'\xa0','\x64'}, + {'\xa5','\xc6'},{'\xc9','\xa3'},{'\xa5','\xc5'},{'\xa5','\xc4'},{'\xa8','\x44'}, + {'\xc9','\xa2'},{'\x00','\x00'},{'\x00','\x00'},{'\xc9','\xf8'},{'\x85','\xb9'}, + {'\x00','\x00'},{'\x86','\xd5'},{'\xc9','\xfc'},{'\xc9','\xfe'},{'\xca','\x40'}, + {'\xa6','\xc5'},{'\xa6','\xc6'},{'\xc9','\xfb'},{'\xa6','\xc1'},{'\x00','\x00'}, + {'\xc9','\xf9'},{'\x00','\x00'},{'\xc9','\xfd'},{'\xa6','\xc2'},{'\x00','\x00'}, + {'\xa6','\xbd'},{'\x9b','\x60'},{'\xa6','\xbe'},{'\x95','\xea'},{'\xa6','\xc4'}, + {'\xc9','\xfa'},{'\xa6','\xbc'},{'\xa8','\x45'},{'\xa6','\xbf'},{'\xa6','\xc0'}, + {'\xa6','\xc3'},{'\xa0','\x65'},{'\x00','\x00'},{'\x84','\xf1'},{'\xcb','\x5b'}, + {'\xcb','\x59'},{'\xcb','\x4c'},{'\xa8','\x51'},{'\xcb','\x53'},{'\xa8','\x4c'}, + {'\xcb','\x4d'},{'\x00','\x00'},{'\xcb','\x55'},{'\x9b','\x61'},{'\xcb','\x52'}, + {'\xa8','\x4f'},{'\xcb','\x51'},{'\xa8','\x56'},{'\xcb','\x5a'},{'\xa8','\x58'}, + {'\x9b','\x62'},{'\xa8','\x5a'},{'\x00','\x00'},{'\xcb','\x4b'},{'\x83','\x6e'}, + {'\xa8','\x4d'},{'\xcb','\x5c'},{'\x00','\x00'},{'\xa8','\x54'},{'\xa8','\x57'}, + {'\x9b','\x63'},{'\xcd','\x45'},{'\xa8','\x47'},{'\xa8','\x5e'},{'\xa8','\x55'}, + {'\xcb','\x4e'},{'\xa8','\x4a'},{'\xa8','\x59'},{'\xcb','\x56'},{'\xa8','\x48'}, + {'\xa8','\x49'},{'\xcd','\x43'},{'\xcb','\x4f'},{'\xa8','\x50'},{'\xa8','\x5b'}, + {'\xcb','\x5d'},{'\xcb','\x50'},{'\xa8','\x4e'},{'\x00','\x00'},{'\xa8','\x53'}, + {'\xcc','\xee'},{'\xa8','\x5c'},{'\xcb','\x57'},{'\xa8','\x52'},{'\x00','\x00'}, + {'\xa8','\x5d'},{'\xa8','\x46'},{'\xcb','\x54'},{'\xa8','\x4b'},{'\xcb','\x58'}, + {'\xcd','\x44'},{'\x00','\x00'},{'\x85','\xd8'},{'\x00','\x00'},{'\x95','\xca'}, + {'\x93','\x6b'},{'\x88','\xf4'},{'\x8e','\x75'},{'\x8b','\x7e'},{'\x84','\x5f'}, + {'\x85','\xdc'},{'\x00','\x00'},{'\x8d','\xe0'},{'\x86','\xdb'},{'\xaa','\x6a'}, + {'\xaa','\x7a'},{'\xcc','\xf5'},{'\xaa','\x71'},{'\x9b','\x64'},{'\xcd','\x4b'}, + {'\xaa','\x62'},{'\xa0','\x66'},{'\xaa','\x65'},{'\xcd','\x42'},{'\x00','\x00'}, + {'\xcc','\xf3'},{'\xcc','\xf7'},{'\xaa','\x6d'},{'\xaa','\x6f'},{'\xcc','\xfa'}, + {'\xaa','\x76'},{'\xaa','\x68'},{'\xaa','\x66'},{'\xaa','\x67'},{'\xaa','\x75'}, + {'\xcd','\x47'},{'\xaa','\x70'},{'\xcc','\xf9'},{'\xcc','\xfb'},{'\xaa','\x6e'}, + {'\xaa','\x73'},{'\xcc','\xfc'},{'\xcd','\x4a'},{'\x00','\x00'},{'\xac','\x75'}, + {'\xaa','\x79'},{'\x9b','\x65'},{'\xaa','\x63'},{'\xcd','\x49'},{'\xfc','\x7d'}, + {'\xcd','\x4d'},{'\xcc','\xf8'},{'\xcd','\x4f'},{'\xcd','\x40'},{'\xaa','\x6c'}, + {'\xcc','\xf4'},{'\xaa','\x6b'},{'\xaa','\x7d'},{'\xaa','\x72'},{'\x00','\x00'}, + {'\xcc','\xf2'},{'\xcf','\x75'},{'\xaa','\x78'},{'\xaa','\x7c'},{'\xcd','\x41'}, + {'\xcd','\x46'},{'\x9b','\x66'},{'\xaa','\x7e'},{'\xaa','\x77'},{'\xaa','\x69'}, + {'\xaa','\x5f'},{'\x00','\x00'},{'\xaa','\x64'},{'\x00','\x00'},{'\xcc','\xf6'}, + {'\xaa','\x60'},{'\xcd','\x4e'},{'\x84','\x5e'},{'\xcc','\xf0'},{'\xcc','\xef'}, + {'\xcc','\xfd'},{'\xcc','\xf1'},{'\xaa','\x7b'},{'\xae','\xf5'},{'\xaa','\x74'}, + {'\xcc','\xfe'},{'\xaa','\x61'},{'\x00','\x00'},{'\xac','\xa6'},{'\x8f','\x54'}, + {'\x8f','\xbc'},{'\x8b','\xa2'},{'\xcd','\x4c'},{'\x8f','\x77'},{'\x8a','\xd2'}, + {'\x87','\xea'},{'\x88','\xf2'},{'\x83','\xbd'},{'\x9b','\x67'},{'\xcf','\x7c'}, + {'\xcf','\xa1'},{'\x9b','\x68'},{'\xcf','\xa4'},{'\xcf','\x77'},{'\x9b','\x69'}, + {'\x9b','\x6a'},{'\xcf','\xa7'},{'\xcf','\xaa'},{'\xcf','\xac'},{'\xcf','\x74'}, + {'\xac','\x76'},{'\xac','\x7b'},{'\xd2','\x49'},{'\xac','\xad'},{'\xcf','\xa5'}, + {'\xcf','\xad'},{'\xcf','\x7b'},{'\xcf','\x73'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd2','\x64'},{'\xac','\x7e'},{'\xcf','\xa2'},{'\xcf','\x78'}, + {'\xcf','\x7a'},{'\xac','\xa5'},{'\x00','\x00'},{'\xcf','\x7d'},{'\xac','\x7d'}, + {'\xcf','\x70'},{'\xcf','\xa8'},{'\x00','\x00'},{'\xcf','\xab'},{'\x00','\x00'}, + {'\x95','\xb0'},{'\xac','\x7a'},{'\x9b','\x6b'},{'\xac','\xa8'},{'\xcf','\x6d'}, + {'\xac','\xaa'},{'\xac','\x78'},{'\xac','\xae'},{'\xcf','\xa9'},{'\xcf','\x6f'}, + {'\xac','\xab'},{'\xd2','\x5e'},{'\xcd','\x48'},{'\xac','\x7c'},{'\xac','\x77'}, + {'\xcf','\x76'},{'\xcf','\x6e'},{'\xac','\xac'},{'\xac','\xa4'},{'\xcf','\xa3'}, + {'\xac','\xa9'},{'\xac','\xa7'},{'\xcf','\x79'},{'\xac','\xa1'},{'\xcf','\x71'}, + {'\xac','\xa2'},{'\xac','\xa3'},{'\xcf','\x72'},{'\xcf','\xa6'},{'\xac','\x79'}, + {'\xcf','\x7e'},{'\x83','\xbe'},{'\x92','\xea'},{'\x93','\x48'},{'\x87','\xe9'}, + {'\x87','\xec'},{'\x8d','\xe1'},{'\x00','\x00'},{'\x88','\xf3'},{'\x84','\xf2'}, + {'\x00','\x00'},{'\x8e','\xe9'},{'\x89','\xec'},{'\x8a','\xd7'},{'\x00','\x00'}, + {'\x84','\xf3'},{'\x8e','\x74'},{'\x88','\xf1'},{'\x87','\xf0'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x9b','\x6c'},{'\xd2','\x4c'},{'\xae','\xfd'},{'\xaf','\x43'}, + {'\x9b','\x6d'},{'\x93','\xbd'},{'\x00','\x00'},{'\xd2','\x55'},{'\xd2','\x5b'}, + {'\xd2','\x57'},{'\xd2','\x4a'},{'\xd2','\x4d'},{'\xd2','\x46'},{'\xd2','\x47'}, + {'\xaf','\x4a'},{'\xae','\xfa'},{'\xd2','\x56'},{'\xd2','\x5f'},{'\xaf','\x45'}, + {'\xae','\xf6'},{'\x00','\x00'},{'\xaf','\x40'},{'\xd2','\x4e'},{'\xaf','\x42'}, + {'\xd2','\x4f'},{'\xd2','\x59'},{'\x9b','\x6e'},{'\xfb','\xa7'},{'\x00','\x00'}, + {'\xaf','\x44'},{'\xd2','\x68'},{'\xd2','\x48'},{'\xae','\xfc'},{'\xae','\xfb'}, + {'\xaf','\x48'},{'\xd2','\x45'},{'\xd2','\x66'},{'\xd2','\x5a'},{'\xd2','\x67'}, + {'\xd2','\x61'},{'\xd2','\x53'},{'\xd2','\x62'},{'\x9b','\x6f'},{'\xd2','\x5c'}, + {'\xd2','\x65'},{'\xd2','\x63'},{'\xaf','\x49'},{'\xd2','\x54'},{'\xae','\xf9'}, + {'\xae','\xf8'},{'\xaf','\x41'},{'\xaf','\x47'},{'\xd2','\x60'},{'\xaf','\x46'}, + {'\xd2','\x51'},{'\xb2','\x43'},{'\x9b','\x70'},{'\xd2','\x69'},{'\xd2','\x50'}, + {'\xd2','\x4b'},{'\xae','\xfe'},{'\xaf','\x4b'},{'\xae','\xf7'},{'\xfe','\x5c'}, + {'\xd2','\x58'},{'\xd2','\x5d'},{'\x93','\xe8'},{'\x00','\x00'},{'\x89','\xed'}, + {'\x82','\x71'},{'\x8e','\xbb'},{'\x8d','\xcf'},{'\x86','\xda'},{'\x8e','\xbd'}, + {'\x84','\xf0'},{'\x00','\x00'},{'\x84','\xf4'},{'\x86','\xde'},{'\x9b','\x71'}, + {'\x87','\xee'},{'\x87','\xef'},{'\x86','\xd9'},{'\x89','\xef'},{'\xb2','\x65'}, + {'\xd5','\xe1'},{'\xd5','\xe5'},{'\x00','\x00'},{'\xb2','\x52'},{'\xb2','\x50'}, + {'\x00','\x00'},{'\x9b','\x72'},{'\xb2','\x47'},{'\xd5','\xe3'},{'\xd5','\xe2'}, + {'\xb2','\x5b'},{'\x00','\x00'},{'\xd5','\xe8'},{'\xb2','\x55'},{'\xfc','\xa1'}, + {'\xd5','\xfa'},{'\xd6','\x47'},{'\xb2','\x44'},{'\xd5','\xf7'},{'\xd5','\xf0'}, + {'\xb2','\x67'},{'\xd5','\xe0'},{'\x00','\x00'},{'\xd5','\xfc'},{'\x00','\x00'}, + {'\xb2','\x64'},{'\xb2','\x58'},{'\xb2','\x63'},{'\xb2','\x4e'},{'\xd5','\xec'}, + {'\xd5','\xfe'},{'\xd5','\xf6'},{'\xb2','\x4f'},{'\xb2','\x49'},{'\xd6','\x45'}, + {'\x00','\x00'},{'\xd5','\xfd'},{'\xd6','\x40'},{'\xb2','\x51'},{'\xb2','\x59'}, + {'\xd6','\x42'},{'\xd5','\xea'},{'\xd5','\xfb'},{'\xd5','\xef'},{'\xd6','\x44'}, + {'\xb2','\x5e'},{'\xb2','\x46'},{'\xb2','\x5c'},{'\xd5','\xf4'},{'\xd5','\xf2'}, + {'\xd5','\xf3'},{'\xb2','\x53'},{'\xd5','\xee'},{'\xd5','\xed'},{'\xb2','\x48'}, + {'\xd5','\xe7'},{'\xd6','\x46'},{'\xb2','\x4a'},{'\xd5','\xf1'},{'\xb2','\x68'}, + {'\x00','\x00'},{'\xb2','\x62'},{'\xd5','\xe6'},{'\xb2','\x5f'},{'\xb2','\x5d'}, + {'\xb2','\x66'},{'\xd5','\xf8'},{'\xb2','\x61'},{'\xd2','\x52'},{'\xd5','\xf9'}, + {'\xb2','\x60'},{'\xd6','\x41'},{'\xb2','\x45'},{'\xd5','\xf5'},{'\xb2','\x57'}, + {'\xd5','\xe9'},{'\xb2','\x56'},{'\xa0','\x67'},{'\xb2','\x54'},{'\xb2','\x4c'}, + {'\xb2','\x4b'},{'\xd9','\xe7'},{'\xd6','\x43'},{'\x9b','\x73'},{'\x00','\x00'}, + {'\xd5','\xeb'},{'\x00','\x00'},{'\x9b','\x74'},{'\xd9','\xfc'},{'\x9b','\x75'}, + {'\xb2','\x4d'},{'\x00','\x00'},{'\x92','\x64'},{'\x92','\xc6'},{'\x92','\xe4'}, + {'\x84','\x5d'},{'\x92','\xdd'},{'\x8d','\xd0'},{'\x86','\xd4'},{'\x8a','\xd5'}, + {'\x9b','\x76'},{'\x86','\xd8'},{'\x88','\xf6'},{'\x00','\x00'},{'\x92','\xaa'}, + {'\x86','\xdc'},{'\x94','\xaa'},{'\x8a','\xd3'},{'\x86','\xdd'},{'\x9b','\x77'}, + {'\xb5','\x41'},{'\xb2','\x5a'},{'\xb4','\xee'},{'\xd9','\xf6'},{'\xb4','\xfc'}, + {'\x00','\x00'},{'\xd9','\xea'},{'\xb4','\xeb'},{'\xb4','\xe7'},{'\xda','\x49'}, + {'\xb4','\xed'},{'\xb4','\xf1'},{'\xb4','\xec'},{'\xb4','\xf5'},{'\xda','\x4d'}, + {'\xda','\x44'},{'\xa0','\x68'},{'\x9b','\x78'},{'\xd9','\xf1'},{'\xb4','\xfa'}, + {'\xb4','\xf4'},{'\xd9','\xfd'},{'\xb4','\xe4'},{'\xda','\x4a'},{'\xda','\x43'}, + {'\xb4','\xe8'},{'\xd9','\xf7'},{'\xb4','\xf7'},{'\xda','\x55'},{'\xda','\x56'}, + {'\x00','\x00'},{'\xb4','\xe5'},{'\xda','\x48'},{'\xb4','\xf9'},{'\xd9','\xfb'}, + {'\xd9','\xed'},{'\xd9','\xee'},{'\xb4','\xfd'},{'\xd9','\xf2'},{'\xd9','\xf9'}, + {'\xd9','\xf3'},{'\x00','\x00'},{'\xb4','\xfb'},{'\xb5','\x44'},{'\xd9','\xef'}, + {'\xd9','\xe8'},{'\xd9','\xe9'},{'\x00','\x00'},{'\xd9','\xeb'},{'\xb4','\xea'}, + {'\xd9','\xf8'},{'\x00','\x00'},{'\xb4','\xf8'},{'\xb5','\x42'},{'\xfc','\x7e'}, + {'\x9b','\x79'},{'\xd9','\xfa'},{'\xda','\x53'},{'\xda','\x4b'},{'\xb4','\xe6'}, + {'\xda','\x51'},{'\xb4','\xf2'},{'\x9d','\xcb'},{'\xb4','\xf0'},{'\x9b','\x7a'}, + {'\xda','\x57'},{'\xb4','\xef'},{'\xda','\x41'},{'\xd9','\xf4'},{'\xd9','\xfe'}, + {'\xb5','\x47'},{'\xda','\x45'},{'\xda','\x42'},{'\xd9','\xf0'},{'\xb5','\x43'}, + {'\xda','\x4f'},{'\xda','\x4c'},{'\xda','\x54'},{'\xb4','\xe9'},{'\xda','\x40'}, + {'\xb5','\x46'},{'\x00','\x00'},{'\xda','\x47'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb4','\xf3'},{'\xb4','\xf6'},{'\x00','\x00'},{'\xda','\x46'},{'\xb5','\x45'}, + {'\xd9','\xf5'},{'\xd5','\xe4'},{'\x00','\x00'},{'\xa0','\x69'},{'\xda','\x50'}, + {'\xda','\x4e'},{'\xda','\x52'},{'\x00','\x00'},{'\x00','\x00'},{'\x95','\xcb'}, + {'\x00','\x00'},{'\x8d','\x6f'},{'\x85','\xda'},{'\x93','\xd2'},{'\x00','\x00'}, + {'\xa0','\x6a'},{'\x87','\xed'},{'\x00','\x00'},{'\x8a','\xd6'},{'\xa0','\x6b'}, + {'\x00','\x00'},{'\xd9','\xec'},{'\xb5','\x40'},{'\x00','\x00'},{'\xfe','\x6a'}, + {'\x82','\x78'},{'\xde','\x61'},{'\xde','\x60'},{'\xde','\x46'},{'\xb7','\xbd'}, + {'\x00','\x00'},{'\xde','\x5f'},{'\xde','\x49'},{'\xde','\x4a'},{'\x00','\x00'}, + {'\xb7','\xc7'},{'\xde','\x68'},{'\xb7','\xc2'},{'\xde','\x5e'},{'\x9b','\x7b'}, + {'\xde','\x43'},{'\xb7','\xc8'},{'\xb7','\xbe'},{'\xde','\x52'},{'\xde','\x48'}, + {'\xde','\x4b'},{'\xde','\x63'},{'\xb7','\xb8'},{'\xde','\x6a'},{'\xde','\x62'}, + {'\xb7','\xc1'},{'\xde','\x57'},{'\xb7','\xcc'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb7','\xcb'},{'\xb7','\xc5'},{'\x00','\x00'},{'\x00','\x00'},{'\xde','\x69'}, + {'\xb7','\xb9'},{'\xde','\x55'},{'\xde','\x4c'},{'\xde','\x59'},{'\xde','\x65'}, + {'\xb7','\xcd'},{'\x9b','\x7c'},{'\xb7','\xbb'},{'\xde','\x54'},{'\x9b','\x7d'}, + {'\xde','\x4d'},{'\xb7','\xc4'},{'\xa0','\x6c'},{'\xb7','\xc3'},{'\xde','\x50'}, + {'\xde','\x5a'},{'\xde','\x64'},{'\xde','\x47'},{'\xde','\x51'},{'\xb7','\xbc'}, + {'\xde','\x5b'},{'\xb7','\xc9'},{'\xb7','\xc0'},{'\xde','\x4e'},{'\xb7','\xbf'}, + {'\xde','\x45'},{'\xde','\x53'},{'\xde','\x67'},{'\xb4','\xfe'},{'\xba','\xb0'}, + {'\xde','\x56'},{'\xe2','\x6c'},{'\xde','\x58'},{'\xde','\x66'},{'\xb7','\xc6'}, + {'\xde','\x4f'},{'\xb7','\xba'},{'\xb7','\xca'},{'\xbc','\xf0'},{'\xde','\x44'}, + {'\x8e','\xbe'},{'\xde','\x5d'},{'\x95','\x50'},{'\x86','\xd3'},{'\x9b','\x7e'}, + {'\xde','\x5c'},{'\x93','\x69'},{'\x86','\xd7'},{'\xa0','\x6d'},{'\x90','\x41'}, + {'\x86','\xd6'},{'\xa0','\x6e'},{'\x00','\x00'},{'\x8a','\xd4'},{'\x89','\xee'}, + {'\x8d','\x7b'},{'\x00','\x00'},{'\x89','\xeb'},{'\x8c','\xd2'},{'\x00','\x00'}, + {'\xe2','\xaa'},{'\xba','\xad'},{'\xe2','\x7d'},{'\xe2','\xa4'},{'\xba','\xa2'}, + {'\x00','\x00'},{'\xe2','\x6e'},{'\xba','\xaf'},{'\x00','\x00'},{'\xba','\x77'}, + {'\xe2','\x6d'},{'\xe2','\xb0'},{'\xba','\xb1'},{'\xe2','\x71'},{'\xe2','\xa3'}, + {'\x9b','\xa1'},{'\xe2','\x73'},{'\xe2','\xb3'},{'\xe2','\xaf'},{'\xba','\x75'}, + {'\xba','\xa1'},{'\xe6','\x53'},{'\xba','\xae'},{'\xba','\x7d'},{'\xe2','\x6f'}, + {'\x9b','\xa2'},{'\xe2','\xae'},{'\xba','\xa3'},{'\xe2','\xab'},{'\xe2','\xb8'}, + {'\xe2','\x75'},{'\xe2','\x7e'},{'\x9b','\xa3'},{'\x9b','\xa4'},{'\xe2','\xb6'}, + {'\xe2','\xac'},{'\xba','\x7c'},{'\x00','\x00'},{'\xa0','\x6f'},{'\xe2','\x7c'}, + {'\xba','\x76'},{'\xba','\x74'},{'\xba','\xa8'},{'\x9b','\xa5'},{'\x9b','\xa6'}, + {'\xe2','\x7a'},{'\xe2','\x77'},{'\xe2','\x78'},{'\x00','\x00'},{'\xe2','\xb2'}, + {'\x00','\x00'},{'\xe2','\xb7'},{'\xe2','\xb5'},{'\xba','\x7a'},{'\xe2','\xb9'}, + {'\xba','\x7e'},{'\xba','\xa7'},{'\xa0','\x70'},{'\xe2','\x70'},{'\xe5','\xfa'}, + {'\xe2','\x79'},{'\x00','\x00'},{'\xba','\x78'},{'\xba','\xac'},{'\xba','\xa9'}, + {'\xba','\x7b'},{'\xe2','\xa5'},{'\xe2','\x74'},{'\xba','\xaa'},{'\xe2','\xa7'}, + {'\xba','\xa4'},{'\xba','\xa6'},{'\xba','\x73'},{'\x9b','\xa7'},{'\xe2','\xa9'}, + {'\xe2','\xa1'},{'\xe2','\x72'},{'\xba','\xa5'},{'\xe2','\xb1'},{'\xe2','\xb4'}, + {'\xe2','\x7b'},{'\xe2','\xa8'},{'\x9b','\xa8'},{'\xba','\x79'},{'\xbc','\xdf'}, + {'\xe2','\xa6'},{'\xe5','\xf9'},{'\x00','\x00'},{'\xe2','\xad'},{'\xfc','\xa2'}, + {'\x82','\x50'},{'\x8f','\xbd'},{'\x8b','\x7c'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x8b','\xfb'},{'\x00','\x00'},{'\x89','\xf0'},{'\xe2','\x76'}, + {'\xe6','\x44'},{'\xe6','\x4e'},{'\xbc','\xe2'},{'\xe6','\x4d'},{'\xe6','\x59'}, + {'\xbc','\xe4'},{'\xe6','\x4b'},{'\x9b','\xa9'},{'\xe6','\x4f'},{'\xbc','\xef'}, + {'\x00','\x00'},{'\xe6','\x46'},{'\xbc','\xe7'},{'\x90','\xb9'},{'\xe6','\x52'}, + {'\xe9','\xf0'},{'\xbc','\xf3'},{'\xbc','\xf2'},{'\xe6','\x54'},{'\xe6','\x43'}, + {'\xe6','\x5e'},{'\xbc','\xed'},{'\x00','\x00'},{'\xbc','\xe3'},{'\xe6','\x57'}, + {'\x00','\x00'},{'\xe6','\x5b'},{'\xe6','\x60'},{'\xe6','\x55'},{'\xe6','\x49'}, + {'\xbc','\xe6'},{'\xbc','\xe9'},{'\xbc','\xf1'},{'\xbc','\xec'},{'\x00','\x00'}, + {'\xe6','\x4c'},{'\xe2','\xa2'},{'\xa0','\x71'},{'\x00','\x00'},{'\xe6','\x48'}, + {'\xe6','\x5f'},{'\xbc','\xe8'},{'\x9b','\xaa'},{'\xbc','\xeb'},{'\xe6','\x61'}, + {'\xbc','\xe0'},{'\xe6','\x56'},{'\xe5','\xfb'},{'\xe6','\x5c'},{'\xc0','\xdf'}, + {'\x95','\x6b'},{'\xe6','\x4a'},{'\x00','\x00'},{'\xbc','\xe1'},{'\xe6','\x45'}, + {'\xbc','\xe5'},{'\xe5','\xfc'},{'\xba','\xab'},{'\xe6','\x41'},{'\x9b','\xab'}, + {'\xe6','\x5a'},{'\xe6','\x42'},{'\xe6','\x40'},{'\xbc','\xea'},{'\x00','\x00'}, + {'\xe6','\x58'},{'\xa0','\x72'},{'\xe5','\xfe'},{'\xe6','\x51'},{'\xe6','\x50'}, + {'\xe6','\x5d'},{'\xe6','\x47'},{'\xbc','\xee'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x8b','\xfa'},{'\x9b','\xac'},{'\xe9','\xf3'}, + {'\x9b','\xad'},{'\xbf','\x49'},{'\xbe','\xfe'},{'\xea','\x40'},{'\xe9','\xeb'}, + {'\xbf','\x41'},{'\xe9','\xf7'},{'\xbf','\x48'},{'\xbf','\x43'},{'\xe9','\xf5'}, + {'\xed','\x4f'},{'\xe9','\xfb'},{'\xea','\x42'},{'\xe9','\xfa'},{'\xe9','\xe9'}, + {'\xe9','\xf8'},{'\xea','\x44'},{'\xea','\x46'},{'\xbe','\xfd'},{'\xea','\x45'}, + {'\xbf','\x44'},{'\xbf','\x4a'},{'\xa0','\x73'},{'\xbf','\x47'},{'\x00','\x00'}, + {'\xe9','\xfe'},{'\xbf','\x46'},{'\xe9','\xf9'},{'\x9b','\xae'},{'\xe9','\xed'}, + {'\xe9','\xf2'},{'\x9b','\xaf'},{'\xe9','\xfd'},{'\xbf','\x45'},{'\xbf','\x42'}, + {'\xbe','\xfc'},{'\xbf','\x40'},{'\xe9','\xf1'},{'\x00','\x00'},{'\xe5','\xfd'}, + {'\xe9','\xec'},{'\xe9','\xef'},{'\xea','\x41'},{'\xe9','\xf4'},{'\xe9','\xea'}, + {'\xed','\x4e'},{'\xea','\x43'},{'\xe9','\xee'},{'\xe9','\xfc'},{'\x00','\x00'}, + {'\x8b','\x7d'},{'\x8b','\xa1'},{'\x9b','\xb0'},{'\xed','\x51'},{'\xc0','\xe3'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc0','\xd7'},{'\x9b','\xb1'},{'\xfc','\xa4'}, + {'\xc0','\xdb'},{'\xed','\x53'},{'\xed','\x59'},{'\xed','\x57'},{'\xc0','\xd9'}, + {'\xc0','\xda'},{'\xc0','\xe1'},{'\xed','\x5a'},{'\xed','\x52'},{'\xc0','\xdc'}, + {'\x00','\x00'},{'\xed','\x56'},{'\xed','\x55'},{'\xed','\x5b'},{'\xc0','\xe2'}, + {'\x00','\x00'},{'\xc0','\xdd'},{'\xc0','\xe0'},{'\xed','\x54'},{'\xc0','\xe4'}, + {'\xc0','\xde'},{'\xc0','\xe5'},{'\xc0','\xd8'},{'\xed','\x58'},{'\xa0','\x74'}, + {'\xed','\x50'},{'\xa0','\x75'},{'\x95','\xc6'},{'\xef','\xf7'},{'\x9b','\xb2'}, + {'\x00','\x00'},{'\xc2','\x71'},{'\xef','\xf4'},{'\xef','\xf6'},{'\x00','\x00'}, + {'\xc2','\x6f'},{'\xef','\xf2'},{'\xef','\xf3'},{'\xef','\xee'},{'\x00','\x00'}, + {'\x9b','\xb3'},{'\xe9','\xf6'},{'\xef','\xef'},{'\xc2','\x70'},{'\xef','\xeb'}, + {'\x00','\x00'},{'\xc2','\x6d'},{'\xef','\xf8'},{'\xc2','\x6e'},{'\xef','\xec'}, + {'\xef','\xed'},{'\xef','\xf1'},{'\xc2','\x73'},{'\x00','\x00'},{'\xc2','\x72'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xef','\xf0'},{'\xc3','\x78'},{'\xf2','\x5f'}, + {'\xf2','\x65'},{'\xc3','\x79'},{'\xf2','\x5c'},{'\xc3','\x76'},{'\xc3','\x73'}, + {'\xf2','\x67'},{'\xc3','\x77'},{'\xfe','\xa1'},{'\xc3','\x74'},{'\xf2','\x5e'}, + {'\xf2','\x61'},{'\xf2','\x62'},{'\xf2','\x63'},{'\xf2','\x66'},{'\x00','\x00'}, + {'\xef','\xf5'},{'\xf2','\x5d'},{'\xc3','\x75'},{'\xf2','\x64'},{'\xf2','\x68'}, + {'\xf2','\x60'},{'\x93','\x40'},{'\x00','\x00'},{'\x00','\x00'},{'\xf4','\x5d'}, + {'\xc4','\x6a'},{'\xf4','\x60'},{'\xc4','\x6b'},{'\xf4','\x68'},{'\xf4','\x5f'}, + {'\xf4','\x5c'},{'\x00','\x00'},{'\xf4','\x5e'},{'\xf4','\x62'},{'\xf4','\x65'}, + {'\xf4','\x64'},{'\xf4','\x67'},{'\xf4','\x5b'},{'\x00','\x00'},{'\xc4','\x69'}, + {'\xf4','\x63'},{'\xf4','\x66'},{'\xf4','\x69'},{'\xf4','\x61'},{'\xf5','\xd3'}, + {'\xf5','\xd4'},{'\xf5','\xd8'},{'\xf5','\xd9'},{'\x00','\x00'},{'\xf5','\xd6'}, + {'\xf5','\xd7'},{'\xf5','\xd5'},{'\x9b','\xb4'},{'\xc4','\xe9'},{'\x9b','\xb5'}, + {'\x00','\x00'},{'\x90','\x76'},{'\x9b','\xb6'},{'\xc5','\x78'},{'\xf6','\xeb'}, + {'\x00','\x00'},{'\x9b','\xb7'},{'\xf6','\xe8'},{'\xf6','\xe9'},{'\xf6','\xea'}, + {'\xc5','\x79'},{'\x00','\x00'},{'\xf7','\xe5'},{'\xf7','\xe4'},{'\x9b','\xb8'}, + {'\xf8','\xaf'},{'\xc5','\xf4'},{'\xf8','\xad'},{'\xf8','\xb0'},{'\xf8','\xae'}, + {'\xf8','\xf5'},{'\xc6','\x57'},{'\xc6','\x65'},{'\xf9','\xa3'},{'\xf9','\x6c'}, + {'\x9b','\xb9'},{'\xf9','\xa2'},{'\xf9','\xd0'},{'\xf9','\xd1'},{'\xa4','\xf5'}, + {'\x9c','\xf6'},{'\x85','\xd9'},{'\x00','\x00'},{'\x88','\xf9'},{'\xa6','\xc7'}, + {'\xca','\x41'},{'\x00','\x00'},{'\x00','\x00'},{'\xcb','\x5e'},{'\x8d','\x5f'}, + {'\xa8','\x5f'},{'\x9b','\xba'},{'\xa8','\x62'},{'\x9b','\xbb'},{'\xcb','\x5f'}, + {'\x00','\x00'},{'\xa8','\x60'},{'\xa8','\x61'},{'\x83','\x4d'},{'\x89','\xf2'}, + {'\x85','\xdf'},{'\xfc','\xa5'},{'\xcd','\x58'},{'\xcd','\x5a'},{'\xcd','\x55'}, + {'\xcd','\x52'},{'\xcd','\x54'},{'\x00','\x00'},{'\x00','\x00'},{'\x93','\xf4'}, + {'\xaa','\xa4'},{'\x9b','\xbc'},{'\x00','\x00'},{'\xfe','\xa3'},{'\xaa','\xa2'}, + {'\x9b','\xbd'},{'\x00','\x00'},{'\xcd','\x56'},{'\xaa','\xa3'},{'\xcd','\x53'}, + {'\xcd','\x50'},{'\xaa','\xa1'},{'\xcd','\x57'},{'\x00','\x00'},{'\xcd','\x51'}, + {'\xaa','\xa5'},{'\xcd','\x59'},{'\x00','\x00'},{'\x8e','\x45'},{'\x8e','\x76'}, + {'\x00','\x00'},{'\xcf','\xaf'},{'\x9b','\xbe'},{'\xcf','\xb3'},{'\x00','\x00'}, + {'\x9b','\xbf'},{'\xac','\xb7'},{'\x9b','\xc0'},{'\x9b','\xc1'},{'\x9b','\xc2'}, + {'\x00','\x00'},{'\xcf','\xb6'},{'\x00','\x00'},{'\xac','\xaf'},{'\xac','\xb2'}, + {'\xac','\xb4'},{'\xac','\xb6'},{'\xac','\xb3'},{'\xcf','\xb2'},{'\xcf','\xb1'}, + {'\x00','\x00'},{'\xac','\xb1'},{'\xcf','\xb4'},{'\xcf','\xb5'},{'\x00','\x00'}, + {'\xcf','\xae'},{'\xac','\xb5'},{'\x8a','\xbb'},{'\xac','\xb0'},{'\xa0','\x76'}, + {'\x85','\xde'},{'\x88','\xf7'},{'\xcf','\xb0'},{'\x00','\x00'},{'\xa0','\x77'}, + {'\x8b','\xa3'},{'\x8c','\x7a'},{'\x8d','\xd1'},{'\x9b','\xc3'},{'\xd2','\x77'}, + {'\xd2','\x78'},{'\xd2','\x79'},{'\xaf','\x50'},{'\x00','\x00'},{'\xaf','\x4c'}, + {'\xd2','\x6e'},{'\x9b','\xc4'},{'\xd2','\x76'},{'\xd2','\x7b'},{'\xaf','\x51'}, + {'\x9b','\xc5'},{'\xd2','\x6c'},{'\xd2','\x72'},{'\xd2','\x6b'},{'\xd2','\x75'}, + {'\xfc','\x57'},{'\x9b','\xc6'},{'\xd2','\x71'},{'\xaf','\x4d'},{'\xaf','\x4f'}, + {'\xd2','\x7a'},{'\x89','\xf3'},{'\xd2','\x6a'},{'\xd2','\x6d'},{'\xd2','\x73'}, + {'\x95','\xaf'},{'\xd2','\x74'},{'\xd2','\x7c'},{'\xd2','\x70'},{'\x00','\x00'}, + {'\xaf','\x4e'},{'\x00','\x00'},{'\x85','\xdd'},{'\x88','\xf8'},{'\x8e','\xea'}, + {'\x89','\xf4'},{'\x00','\x00'},{'\x88','\xfa'},{'\x8a','\xd8'},{'\x87','\xf1'}, + {'\x00','\x00'},{'\xb2','\x6d'},{'\xd6','\x4e'},{'\x95','\x49'},{'\x00','\x00'}, + {'\xd6','\x50'},{'\xd6','\x4c'},{'\x9c','\x40'},{'\xd6','\x58'},{'\xd6','\x4a'}, + {'\xd6','\x57'},{'\xb2','\x69'},{'\xd6','\x48'},{'\xda','\x5b'},{'\xd6','\x52'}, + {'\xb2','\x6c'},{'\x9c','\x4b'},{'\xd6','\x53'},{'\xd6','\x56'},{'\x00','\x00'}, + {'\xd6','\x5a'},{'\x00','\x00'},{'\xd6','\x4f'},{'\x9c','\x4c'},{'\xd6','\x54'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb2','\x6a'},{'\xb2','\x6b'},{'\xd6','\x59'}, + {'\xd6','\x4d'},{'\xd6','\x49'},{'\xd6','\x5b'},{'\xa0','\x78'},{'\xd6','\x51'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xd6','\x55'},{'\x82','\x44'},{'\x85','\xe0'}, + {'\x88','\xfb'},{'\xd6','\x4b'},{'\x8a','\xd9'},{'\xb5','\x48'},{'\xb5','\x49'}, + {'\xda','\x65'},{'\xb5','\x4f'},{'\x9c','\x4d'},{'\xda','\x59'},{'\xda','\x62'}, + {'\xda','\x58'},{'\xb5','\x4c'},{'\xda','\x60'},{'\xda','\x5e'},{'\x00','\x00'}, + {'\xda','\x5f'},{'\xb5','\x4a'},{'\x00','\x00'},{'\xda','\x63'},{'\x9c','\x4e'}, + {'\x00','\x00'},{'\x9c','\x4f'},{'\x9c','\x50'},{'\x00','\x00'},{'\xda','\x5c'}, + {'\xda','\x5a'},{'\xb5','\x4b'},{'\xda','\x5d'},{'\xda','\x61'},{'\x9c','\x51'}, + {'\xfc','\xa7'},{'\x9c','\x52'},{'\xb5','\x4d'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xda','\x64'},{'\x9c','\x53'},{'\x92','\xe5'},{'\x00','\x00'}, + {'\x9c','\x54'},{'\xfe','\x76'},{'\x9c','\x55'},{'\xde','\x70'},{'\xde','\x77'}, + {'\xde','\x79'},{'\xde','\xa1'},{'\xfb','\x66'},{'\xb7','\xda'},{'\xde','\x6b'}, + {'\x00','\x00'},{'\xb7','\xd2'},{'\x95','\x4f'},{'\xde','\x7a'},{'\xb7','\xd7'}, + {'\xde','\xa2'},{'\xb7','\xce'},{'\x9c','\x56'},{'\xde','\x7d'},{'\x95','\x5f'}, + {'\xde','\x6d'},{'\xde','\x7e'},{'\xde','\x6c'},{'\xa0','\x7a'},{'\xb7','\xdc'}, + {'\x9d','\xcd'},{'\xde','\x78'},{'\xb7','\xcf'},{'\xde','\xa3'},{'\x00','\x00'}, + {'\xb7','\xd4'},{'\xde','\x71'},{'\xb7','\xd9'},{'\xde','\x7c'},{'\xde','\x6f'}, + {'\xde','\x76'},{'\xde','\x72'},{'\xde','\x6e'},{'\xb7','\xd1'},{'\xb7','\xd8'}, + {'\xb7','\xd6'},{'\xb7','\xd3'},{'\xb7','\xdb'},{'\xb7','\xd0'},{'\xde','\x75'}, + {'\x9c','\x57'},{'\xb7','\xd5'},{'\x00','\x00'},{'\xb5','\x4e'},{'\x00','\x00'}, + {'\xde','\x7b'},{'\xfe','\x53'},{'\xde','\x73'},{'\xa0','\x7b'},{'\x00','\x00'}, + {'\x9c','\x58'},{'\xfc','\xa9'},{'\x9c','\x59'},{'\xde','\x74'},{'\x00','\x00'}, + {'\xa0','\x7c'},{'\xe2','\xc1'},{'\x9c','\x5a'},{'\xba','\xb4'},{'\x9c','\x5b'}, + {'\x00','\x00'},{'\xe2','\xbd'},{'\xe2','\xc3'},{'\xe2','\xbf'},{'\x00','\x00'}, + {'\xba','\xb6'},{'\xe2','\xbe'},{'\xe2','\xc2'},{'\xe2','\xba'},{'\xa0','\xd8'}, + {'\xe2','\xbc'},{'\xba','\xb5'},{'\x00','\x00'},{'\x9c','\x5c'},{'\x00','\x00'}, + {'\x9c','\x5d'},{'\xe2','\xc0'},{'\xe2','\xbb'},{'\x9c','\x5e'},{'\xba','\xb7'}, + {'\x00','\x00'},{'\xba','\xb2'},{'\x94','\xab'},{'\x9c','\x5f'},{'\xe2','\xc4'}, + {'\xa0','\xe7'},{'\xba','\xb3'},{'\xe6','\x67'},{'\xe6','\x64'},{'\xe6','\x70'}, + {'\xe6','\x6a'},{'\xe6','\x6c'},{'\xbc','\xf4'},{'\xe6','\x66'},{'\xe6','\x6e'}, + {'\x9c','\x60'},{'\x9c','\x61'},{'\xe6','\x6d'},{'\xe6','\x6b'},{'\x00','\x00'}, + {'\xe6','\x71'},{'\xbc','\xf7'},{'\xe6','\x68'},{'\xe6','\x6f'},{'\x00','\x00'}, + {'\xbc','\xf5'},{'\x9c','\x62'},{'\x00','\x00'},{'\xe6','\x63'},{'\xe6','\x65'}, + {'\xbc','\xf6'},{'\xe6','\x62'},{'\xe6','\x72'},{'\x9c','\x63'},{'\xe6','\x69'}, + {'\x00','\x00'},{'\x9c','\x64'},{'\xea','\x4a'},{'\xbf','\x51'},{'\x9c','\x65'}, + {'\x00','\x00'},{'\xea','\x55'},{'\xea','\x53'},{'\xbf','\x4b'},{'\xea','\x49'}, + {'\xea','\x4c'},{'\xea','\x4d'},{'\xea','\x48'},{'\xbf','\x55'},{'\xbf','\x56'}, + {'\xea','\x47'},{'\xea','\x56'},{'\xea','\x51'},{'\xbf','\x4f'},{'\xbf','\x4c'}, + {'\xea','\x50'},{'\xea','\x4e'},{'\x00','\x00'},{'\x00','\x00'},{'\xbf','\x52'}, + {'\xea','\x52'},{'\xbf','\x4d'},{'\x9c','\x66'},{'\xbf','\x4e'},{'\x00','\x00'}, + {'\xea','\x4f'},{'\xbf','\x50'},{'\xea','\x4b'},{'\xa0','\xe8'},{'\xea','\x54'}, + {'\xbf','\x53'},{'\xea','\x57'},{'\xea','\x58'},{'\xbf','\x54'},{'\x9c','\x67'}, + {'\x00','\x00'},{'\xc0','\xe7'},{'\xc0','\xee'},{'\xed','\x5c'},{'\xed','\x62'}, + {'\x00','\x00'},{'\xed','\x60'},{'\xc0','\xea'},{'\xc0','\xe9'},{'\xc0','\xe6'}, + {'\xed','\x5e'},{'\x00','\x00'},{'\x00','\x00'},{'\x9c','\x68'},{'\xc0','\xec'}, + {'\xc0','\xeb'},{'\xc0','\xe8'},{'\x00','\x00'},{'\xed','\x61'},{'\xed','\x5d'}, + {'\xed','\x5f'},{'\x00','\x00'},{'\xc0','\xed'},{'\xa0','\xf5'},{'\xfb','\x70'}, + {'\x00','\x00'},{'\xc2','\x77'},{'\xef','\xfb'},{'\x00','\x00'},{'\xc2','\x74'}, + {'\xc2','\x75'},{'\xef','\xfd'},{'\xc2','\x76'},{'\xef','\xfa'},{'\x9c','\x69'}, + {'\xef','\xf9'},{'\xf2','\x6c'},{'\xef','\xfc'},{'\x00','\x00'},{'\xf2','\x6d'}, + {'\xc3','\x7a'},{'\xf2','\x6b'},{'\x00','\x00'},{'\x9c','\x6a'},{'\xf2','\x6a'}, + {'\x00','\x00'},{'\xf2','\x69'},{'\xc3','\x7b'},{'\x9c','\x6b'},{'\x9c','\x6c'}, + {'\xc4','\x6c'},{'\x00','\x00'},{'\x00','\x00'},{'\xf4','\x6a'},{'\xf4','\x6b'}, + {'\xfc','\xac'},{'\x9c','\x6d'},{'\x9c','\x6e'},{'\x00','\x00'},{'\xf5','\xdc'}, + {'\xf5','\xdb'},{'\xc4','\xea'},{'\x00','\x00'},{'\xf5','\xda'},{'\xf6','\xec'}, + {'\xf6','\xed'},{'\x00','\x00'},{'\x00','\x00'},{'\xf7','\xe6'},{'\xf8','\xb1'}, + {'\x9c','\x6f'},{'\x9d','\x5a'},{'\xf8','\xf6'},{'\xf9','\xbc'},{'\xc6','\x79'}, + {'\xf9','\xc6'},{'\xa4','\xf6'},{'\x91','\xc9'},{'\xaa','\xa6'},{'\xaa','\xa7'}, + {'\x9c','\x71'},{'\x00','\x00'},{'\xac','\xb8'},{'\x85','\xc6'},{'\xfa','\x64'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc0','\xef'},{'\xa4','\xf7'},{'\x85','\xe1'}, + {'\xaa','\xa8'},{'\xaf','\x52'},{'\xb7','\xdd'},{'\xa4','\xf8'},{'\xfa','\x65'}, + {'\xb2','\x6e'},{'\xba','\xb8'},{'\xc9','\x62'},{'\x95','\xa7'},{'\xcf','\xb7'}, + {'\xd2','\x7d'},{'\x00','\x00'},{'\xe2','\xc5'},{'\x00','\x00'},{'\xc0','\xf0'}, + {'\xa4','\xf9'},{'\xaa','\xa9'},{'\xcf','\xb8'},{'\xcf','\xb9'},{'\xda','\x66'}, + {'\xb5','\x50'},{'\x8b','\xa4'},{'\x00','\x00'},{'\xde','\xa4'},{'\xfc','\xad'}, + {'\x00','\x00'},{'\xb7','\xde'},{'\xe2','\xc6'},{'\x00','\x00'},{'\x95','\x6e'}, + {'\xbc','\xf8'},{'\x9c','\x73'},{'\xc3','\x7c'},{'\xa4','\xfa'},{'\xda','\x67'}, + {'\xa4','\xfb'},{'\x9c','\x74'},{'\xa6','\xc9'},{'\xca','\x42'},{'\xa6','\xc8'}, + {'\xa8','\x65'},{'\xa8','\x64'},{'\xa8','\x63'},{'\xcb','\x60'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xfa','\x66'},{'\xaa','\xaa'},{'\x00','\x00'},{'\xaa','\xab'}, + {'\xcd','\x5b'},{'\x00','\x00'},{'\xcf','\xba'},{'\x00','\x00'},{'\xcf','\xbd'}, + {'\xac','\xba'},{'\xcf','\xbb'},{'\x00','\x00'},{'\xac','\xb9'},{'\xcf','\xbc'}, + {'\xac','\xbb'},{'\x84','\x61'},{'\xd2','\xa2'},{'\xd2','\xa1'},{'\xd2','\x7e'}, + {'\xaf','\x53'},{'\x8c','\x7b'},{'\xd6','\x5d'},{'\xd6','\x5e'},{'\xb2','\x6f'}, + {'\xd6','\x5c'},{'\xd6','\x5f'},{'\xb5','\x52'},{'\xb2','\x70'},{'\xfa','\x67'}, + {'\x00','\x00'},{'\xb5','\x51'},{'\xda','\x6b'},{'\xda','\x6a'},{'\xfc','\xae'}, + {'\xda','\x68'},{'\xda','\x69'},{'\x8b','\xa5'},{'\xda','\x6c'},{'\xde','\xa6'}, + {'\xde','\xa5'},{'\xde','\xa9'},{'\xfa','\x68'},{'\xde','\xa8'},{'\xde','\xa7'}, + {'\xba','\xb9'},{'\xe2','\xc9'},{'\x9c','\x75'},{'\xe2','\xc8'},{'\xba','\xba'}, + {'\xe2','\xc7'},{'\xe6','\x73'},{'\x00','\x00'},{'\xe6','\x74'},{'\xbc','\xf9'}, + {'\x00','\x00'},{'\xea','\x59'},{'\xea','\x5a'},{'\xfa','\x69'},{'\x92','\x71'}, + {'\xf2','\x72'},{'\xc3','\x7d'},{'\xf2','\x71'},{'\xf2','\x70'},{'\xf2','\x6e'}, + {'\xf2','\x6f'},{'\xc4','\xeb'},{'\xf4','\x6c'},{'\xf6','\xee'},{'\xf8','\xf7'}, + {'\x00','\x00'},{'\xa4','\xfc'},{'\xfa','\x6a'},{'\xc9','\xa5'},{'\xa5','\xc7'}, + {'\xc9','\xa6'},{'\xfa','\x6b'},{'\xfc','\xb0'},{'\x00','\x00'},{'\xca','\x43'}, + {'\xca','\x44'},{'\x83','\x5d'},{'\x8a','\xda'},{'\xfa','\x6c'},{'\x84','\xf6'}, + {'\xcb','\x66'},{'\x00','\x00'},{'\x00','\x00'},{'\xcb','\x62'},{'\xfa','\x6d'}, + {'\xcb','\x61'},{'\xaa','\xac'},{'\xcb','\x65'},{'\xa8','\x67'},{'\xcb','\x63'}, + {'\xa8','\x66'},{'\xcb','\x67'},{'\xcb','\x64'},{'\x00','\x00'},{'\x83','\xc1'}, + {'\xcd','\x5f'},{'\xcf','\xbe'},{'\xcd','\x5d'},{'\xcd','\x64'},{'\xfa','\x6e'}, + {'\xaa','\xad'},{'\x00','\x00'},{'\xaa','\xb0'},{'\xcd','\x65'},{'\xcd','\x61'}, + {'\x00','\x00'},{'\xcd','\x62'},{'\x00','\x00'},{'\xcd','\x5c'},{'\xaa','\xaf'}, + {'\xcd','\x5e'},{'\xaa','\xae'},{'\xcd','\x63'},{'\xfa','\x6f'},{'\xcd','\x60'}, + {'\x00','\x00'},{'\x89','\xf6'},{'\xcf','\xc2'},{'\xac','\xbd'},{'\xac','\xbe'}, + {'\xfc','\xb1'},{'\xcf','\xc5'},{'\xcf','\xbf'},{'\x00','\x00'},{'\xcf','\xc4'}, + {'\x00','\x00'},{'\xcf','\xc0'},{'\xac','\xbc'},{'\xcf','\xc3'},{'\xcf','\xc1'}, + {'\x88','\xfc'},{'\x83','\xc0'},{'\x85','\xe2'},{'\x8e','\xec'},{'\x84','\x62'}, + {'\x86','\xe2'},{'\x8e','\x47'},{'\xd2','\xa8'},{'\xd2','\xa5'},{'\x00','\x00'}, + {'\xd2','\xa7'},{'\xaf','\x58'},{'\xaf','\x57'},{'\xaf','\x55'},{'\xd2','\xa4'}, + {'\xd2','\xa9'},{'\xaf','\x54'},{'\xaf','\x56'},{'\xd2','\xa6'},{'\xd6','\x67'}, + {'\xd2','\xa3'},{'\xd2','\xaa'},{'\xfc','\xb2'},{'\x8e','\xeb'},{'\x9c','\x76'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xd6','\x62'},{'\xd6','\x66'},{'\x00','\x00'}, + {'\xd6','\x65'},{'\xda','\x6e'},{'\xda','\x79'},{'\x00','\x00'},{'\x8a','\xdb'}, + {'\xd6','\x68'},{'\x9c','\x77'},{'\xd6','\x63'},{'\xda','\x6d'},{'\xb2','\x74'}, + {'\x00','\x00'},{'\x8f','\x55'},{'\xb2','\x73'},{'\xd6','\x61'},{'\xd6','\x64'}, + {'\xb2','\x75'},{'\x00','\x00'},{'\xb2','\x72'},{'\xb2','\x71'},{'\xd6','\x60'}, + {'\xd6','\x69'},{'\x93','\xe6'},{'\x00','\x00'},{'\x8c','\xd3'},{'\xda','\x70'}, + {'\xda','\x77'},{'\xfa','\x70'},{'\xb5','\x54'},{'\xda','\x76'},{'\xda','\x73'}, + {'\xfc','\xb4'},{'\xb5','\x56'},{'\x95','\xbd'},{'\x95','\xbc'},{'\xfc','\xaf'}, + {'\xda','\x75'},{'\x95','\x52'},{'\xfa','\x71'},{'\xda','\x6f'},{'\xda','\x71'}, + {'\xda','\x74'},{'\xda','\x72'},{'\xb5','\x55'},{'\xda','\x78'},{'\xb5','\x53'}, + {'\xb7','\xdf'},{'\xfa','\x72'},{'\xfa','\x73'},{'\xde','\xad'},{'\xde','\xac'}, + {'\xde','\xaa'},{'\x00','\x00'},{'\xb7','\xe2'},{'\xb7','\xe1'},{'\xde','\xae'}, + {'\x9c','\x78'},{'\xde','\xab'},{'\xe2','\xca'},{'\xba','\xbb'},{'\xb7','\xe0'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xfc','\xb3'},{'\xde','\xb0'},{'\xde','\xaf'}, + {'\x00','\x00'},{'\xe2','\xcd'},{'\xe2','\xcb'},{'\xbc','\xfa'},{'\xfc','\xb5'}, + {'\xba','\xbc'},{'\xe2','\xcc'},{'\xe6','\x76'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xbc','\xfb'},{'\xe6','\x75'},{'\xe6','\x7e'}, + {'\xe6','\x7d'},{'\xe6','\x7b'},{'\x00','\x00'},{'\xe6','\x7a'},{'\xe6','\x77'}, + {'\xe6','\x78'},{'\xe6','\x79'},{'\xe6','\x7c'},{'\xe6','\xa1'},{'\x92','\xde'}, + {'\x00','\x00'},{'\xea','\x5f'},{'\xea','\x5c'},{'\xea','\x5d'},{'\xbf','\x57'}, + {'\xea','\x5b'},{'\xea','\x61'},{'\xea','\x60'},{'\xea','\x5e'},{'\x8b','\xa7'}, + {'\xed','\x64'},{'\xed','\x65'},{'\xc0','\xf1'},{'\xfc','\xb6'},{'\xc0','\xf2'}, + {'\xed','\x63'},{'\x9c','\x79'},{'\xc2','\x79'},{'\xef','\xfe'},{'\xc2','\x78'}, + {'\xc3','\x7e'},{'\x00','\x00'},{'\xc3','\xa1'},{'\xc4','\x6d'},{'\xf4','\x6e'}, + {'\xf4','\x6d'},{'\xf5','\xdd'},{'\xf6','\xef'},{'\xc5','\x7a'},{'\xf7','\xe8'}, + {'\xf7','\xe7'},{'\xf7','\xe9'},{'\xa5','\xc8'},{'\xcf','\xc6'},{'\xaf','\x59'}, + {'\xb2','\x76'},{'\xd6','\x6a'},{'\xa5','\xc9'},{'\xc9','\xa7'},{'\xa4','\xfd'}, + {'\x9c','\x7a'},{'\x00','\x00'},{'\xca','\x45'},{'\x9c','\x7b'},{'\x00','\x00'}, + {'\x88','\xfd'},{'\xcb','\x6c'},{'\xcb','\x6a'},{'\xcb','\x6b'},{'\xcb','\x68'}, + {'\xa8','\x68'},{'\xcb','\x69'},{'\x9c','\x7c'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x86','\xe4'},{'\x9c','\x7d'},{'\xcd','\x6d'},{'\x9c','\x7e'},{'\xaa','\xb3'}, + {'\xcd','\x6b'},{'\xcd','\x67'},{'\xcd','\x6a'},{'\x00','\x00'},{'\xcd','\x66'}, + {'\xaa','\xb5'},{'\xcd','\x69'},{'\x9c','\xa1'},{'\xaa','\xb2'},{'\xaa','\xb1'}, + {'\x9c','\xa2'},{'\xaa','\xb4'},{'\xcd','\x6c'},{'\xcd','\x68'},{'\x8e','\x48'}, + {'\x89','\xf8'},{'\x84','\x63'},{'\x00','\x00'},{'\xac','\xc2'},{'\xac','\xc5'}, + {'\xcf','\xce'},{'\xcf','\xcd'},{'\xcf','\xcc'},{'\xac','\xbf'},{'\xcf','\xd5'}, + {'\xcf','\xcb'},{'\x8b','\xa8'},{'\xac','\xc1'},{'\xd2','\xaf'},{'\xfa','\x74'}, + {'\xcf','\xd2'},{'\xcf','\xd0'},{'\xac','\xc4'},{'\x00','\x00'},{'\xcf','\xc8'}, + {'\xcf','\xd3'},{'\x00','\x00'},{'\xcf','\xca'},{'\xcf','\xd4'},{'\xcf','\xd1'}, + {'\xcf','\xc9'},{'\x95','\xbe'},{'\xac','\xc0'},{'\xcf','\xd6'},{'\xcf','\xc7'}, + {'\xac','\xc3'},{'\xfa','\x75'},{'\x95','\xb6'},{'\x90','\xb2'},{'\x8b','\xfd'}, + {'\xd2','\xb4'},{'\xd2','\xab'},{'\xd2','\xb6'},{'\x9c','\xa3'},{'\xd2','\xae'}, + {'\xd2','\xb9'},{'\xd2','\xba'},{'\xd2','\xac'},{'\xd2','\xb8'},{'\xd2','\xb5'}, + {'\xd2','\xb3'},{'\xd2','\xb7'},{'\xaf','\x5f'},{'\x00','\x00'},{'\xaf','\x5d'}, + {'\x9c','\xa4'},{'\x9c','\xa5'},{'\xd2','\xb1'},{'\x9c','\xa6'},{'\xd2','\xad'}, + {'\x9c','\xa7'},{'\xd2','\xb0'},{'\xd2','\xbb'},{'\xd2','\xb2'},{'\xaf','\x5e'}, + {'\xcf','\xcf'},{'\x00','\x00'},{'\xaf','\x5a'},{'\xaf','\x5c'},{'\x9c','\xa8'}, + {'\x00','\x00'},{'\xfa','\x76'},{'\x85','\xe4'},{'\x9c','\xa9'},{'\xd6','\x78'}, + {'\xd6','\x6d'},{'\xd6','\x6b'},{'\xfe','\xaa'},{'\xd6','\x6c'},{'\x9c','\xab'}, + {'\xd6','\x73'},{'\x9c','\xac'},{'\xd6','\x74'},{'\xd6','\x70'},{'\xb2','\x7b'}, + {'\xd6','\x75'},{'\xd6','\x72'},{'\xd6','\x6f'},{'\x9c','\xad'},{'\xb2','\x79'}, + {'\xd6','\x6e'},{'\xb2','\x77'},{'\xb2','\x7a'},{'\xd6','\x71'},{'\xd6','\x79'}, + {'\xaf','\x5b'},{'\xb2','\x78'},{'\xd6','\x77'},{'\xd6','\x76'},{'\xb2','\x7c'}, + {'\x00','\x00'},{'\x8e','\xbf'},{'\x86','\xe3'},{'\x9c','\xae'},{'\x9c','\xaf'}, + {'\x00','\x00'},{'\x9c','\xb0'},{'\x9c','\xb1'},{'\xda','\x7e'},{'\x9c','\xb2'}, + {'\x00','\x00'},{'\x9c','\xb3'},{'\xda','\xa1'},{'\xb5','\x60'},{'\x9c','\xb4'}, + {'\xda','\xa7'},{'\x9c','\xb5'},{'\x9c','\xb6'},{'\xda','\xa9'},{'\xda','\xa2'}, + {'\xb5','\x5a'},{'\xda','\xa6'},{'\xda','\xa5'},{'\xb5','\x5b'},{'\xb5','\x61'}, + {'\x00','\x00'},{'\xb5','\x62'},{'\xda','\xa8'},{'\xb5','\x58'},{'\xda','\x7d'}, + {'\xda','\x7b'},{'\xda','\xa3'},{'\xda','\x7a'},{'\xb5','\x5f'},{'\xda','\x7c'}, + {'\xda','\xa4'},{'\xda','\xaa'},{'\xb5','\x59'},{'\xb5','\x5e'},{'\xb5','\x5c'}, + {'\xb5','\x5d'},{'\x9c','\xb7'},{'\x9c','\xb8'},{'\x9c','\xb9'},{'\xb5','\x57'}, + {'\x00','\x00'},{'\x8b','\xa9'},{'\x00','\x00'},{'\x00','\x00'},{'\xb7','\xe9'}, + {'\xde','\xb7'},{'\xb7','\xe8'},{'\xde','\xbb'},{'\x9c','\xba'},{'\xde','\xb1'}, + {'\x9c','\xbb'},{'\xde','\xbc'},{'\x9c','\xbc'},{'\x9c','\xbd'},{'\x9c','\xbe'}, + {'\xde','\xb2'},{'\xde','\xb3'},{'\x00','\x00'},{'\xde','\xbd'},{'\xde','\xba'}, + {'\xde','\xb8'},{'\xde','\xb9'},{'\xde','\xb5'},{'\xde','\xb4'},{'\x9c','\xbf'}, + {'\xde','\xbe'},{'\xb7','\xe5'},{'\x9c','\xc0'},{'\xde','\xb6'},{'\x00','\x00'}, + {'\xb7','\xea'},{'\xb7','\xe4'},{'\xb7','\xeb'},{'\xb7','\xec'},{'\xfc','\xb9'}, + {'\xb7','\xe7'},{'\xb7','\xe6'},{'\xfe','\x75'},{'\x9d','\x73'},{'\xe2','\xce'}, + {'\xba','\xbe'},{'\xba','\xbd'},{'\x9c','\xc1'},{'\x00','\x00'},{'\xe2','\xd3'}, + {'\xfe','\xac'},{'\xbc','\xfc'},{'\xba','\xbf'},{'\x9c','\xc2'},{'\x9c','\xc3'}, + {'\xba','\xc1'},{'\xe2','\xd4'},{'\xb7','\xe3'},{'\xba','\xc0'},{'\xe2','\xd0'}, + {'\xe2','\xd2'},{'\xe2','\xcf'},{'\x9c','\xc4'},{'\xe2','\xd1'},{'\xfa','\x77'}, + {'\x89','\xf9'},{'\x00','\x00'},{'\xe6','\xab'},{'\x9c','\xc5'},{'\x00','\x00'}, + {'\xe6','\xaa'},{'\xe6','\xa7'},{'\xbd','\x40'},{'\xea','\x62'},{'\xbd','\x41'}, + {'\xe6','\xa6'},{'\x9c','\xc6'},{'\xbc','\xfe'},{'\x00','\x00'},{'\xe6','\xa8'}, + {'\xe6','\xa5'},{'\xe6','\xa2'},{'\xe6','\xa9'},{'\xe6','\xa3'},{'\xe6','\xa4'}, + {'\xbc','\xfd'},{'\x81','\xd0'},{'\x81','\xd1'},{'\x8c','\x7d'},{'\x00','\x00'}, + {'\xed','\x69'},{'\x00','\x00'},{'\xea','\x66'},{'\x00','\x00'},{'\xea','\x65'}, + {'\xea','\x67'},{'\x00','\x00'},{'\xed','\x66'},{'\xbf','\x5a'},{'\x81','\xd2'}, + {'\xea','\x63'},{'\x81','\xd3'},{'\xbf','\x58'},{'\x9d','\x74'},{'\xbf','\x5c'}, + {'\xbf','\x5b'},{'\xea','\x64'},{'\xea','\x68'},{'\xfa','\x78'},{'\xbf','\x59'}, + {'\x81','\xd4'},{'\xed','\x6d'},{'\xc0','\xf5'},{'\xc2','\x7a'},{'\xc0','\xf6'}, + {'\xc0','\xf3'},{'\xed','\x6a'},{'\xed','\x68'},{'\x00','\x00'},{'\xed','\x6b'}, + {'\x00','\x00'},{'\xed','\x6e'},{'\xc0','\xf4'},{'\xed','\x6c'},{'\xed','\x67'}, + {'\x00','\x00'},{'\x81','\xd5'},{'\xf0','\x42'},{'\xf0','\x45'},{'\xf2','\x75'}, + {'\xf0','\x40'},{'\x81','\xd6'},{'\xf4','\x6f'},{'\xf0','\x46'},{'\x00','\x00'}, + {'\xc3','\xa2'},{'\xf0','\x44'},{'\xc2','\x7b'},{'\xf0','\x41'},{'\xf0','\x43'}, + {'\xf0','\x47'},{'\xf2','\x76'},{'\x00','\x00'},{'\xf2','\x74'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x81','\xd7'},{'\x00','\x00'},{'\xc3','\xa3'},{'\xf2','\x73'}, + {'\x81','\xd8'},{'\x00','\x00'},{'\x00','\x00'},{'\xc4','\x6e'},{'\x81','\xd9'}, + {'\x00','\x00'},{'\x8c','\xf9'},{'\x81','\xda'},{'\xc4','\xed'},{'\xf6','\xf1'}, + {'\xc4','\xec'},{'\xf6','\xf3'},{'\xf6','\xf0'},{'\xf6','\xf2'},{'\xc5','\xd0'}, + {'\xf8','\xb2'},{'\xa5','\xca'},{'\xcd','\x6e'},{'\xd2','\xbc'},{'\xd2','\xbd'}, + {'\xb2','\x7d'},{'\xde','\xbf'},{'\xbf','\x5d'},{'\xc3','\xa4'},{'\xc5','\x7b'}, + {'\xf8','\xb3'},{'\xa5','\xcb'},{'\x94','\xac'},{'\xcd','\x6f'},{'\xa2','\x60'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xcf','\xd7'},{'\x00','\x00'},{'\xcf','\xd8'}, + {'\x88','\xfe'},{'\x94','\xae'},{'\x94','\xaf'},{'\x94','\xad'},{'\x00','\x00'}, + {'\xd2','\xbe'},{'\xd2','\xbf'},{'\xb2','\x7e'},{'\xb2','\xa1'},{'\x94','\xb0'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xda','\xab'},{'\x00','\x00'},{'\xde','\xc2'}, + {'\xde','\xc1'},{'\xde','\xc0'},{'\xe2','\xd5'},{'\xfa','\x79'},{'\xe2','\xd6'}, + {'\xe2','\xd7'},{'\xba','\xc2'},{'\x94','\xb1'},{'\x00','\x00'},{'\xe6','\xad'}, + {'\xe6','\xac'},{'\x00','\x00'},{'\x00','\x00'},{'\xea','\x69'},{'\xbf','\x5e'}, + {'\xbf','\x5f'},{'\x95','\xc2'},{'\xed','\x72'},{'\xed','\x6f'},{'\xed','\x70'}, + {'\xed','\x71'},{'\xf0','\x49'},{'\xf0','\x48'},{'\xc2','\x7c'},{'\xf2','\x77'}, + {'\xf5','\xde'},{'\xa5','\xcc'},{'\xfa','\x7a'},{'\xac','\xc6'},{'\x00','\x00'}, + {'\xb2','\xa2'},{'\xde','\xc3'},{'\xfc','\xbb'},{'\xa5','\xcd'},{'\x00','\x00'}, + {'\xd2','\xc0'},{'\xb2','\xa3'},{'\xfa','\x7b'},{'\x00','\x00'},{'\xb5','\x63'}, + {'\xb5','\x64'},{'\x00','\x00'},{'\xa5','\xce'},{'\xa5','\xcf'},{'\xca','\x46'}, + {'\xa8','\x6a'},{'\xa8','\x69'},{'\xac','\xc7'},{'\xcf','\xd9'},{'\xda','\xac'}, + {'\xa5','\xd0'},{'\xa5','\xd1'},{'\xa5','\xd2'},{'\xa5','\xd3'},{'\xa0','\x59'}, + {'\x86','\x7a'},{'\x00','\x00'},{'\xa8','\x6b'},{'\xa8','\x6c'},{'\xcb','\x6e'}, + {'\xcb','\x6d'},{'\x84','\xf8'},{'\xfa','\x7c'},{'\xaa','\xb6'},{'\xcd','\x72'}, + {'\xcd','\x70'},{'\xcd','\x71'},{'\x00','\x00'},{'\x81','\xdb'},{'\x00','\x00'}, + {'\xfa','\x7d'},{'\x86','\xd0'},{'\xfb','\xd1'},{'\xcf','\xda'},{'\xcf','\xdb'}, + {'\xfa','\x7e'},{'\x95','\xbf'},{'\xac','\xcb'},{'\xac','\xc9'},{'\xfa','\xa1'}, + {'\xac','\xca'},{'\xac','\xc8'},{'\x00','\x00'},{'\x94','\x55'},{'\x00','\x00'}, + {'\xfc','\xbc'},{'\xaf','\x60'},{'\x81','\xdc'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xaf','\x64'},{'\xaf','\x63'},{'\xd2','\xc1'},{'\xaf','\x62'}, + {'\xaf','\x61'},{'\x00','\x00'},{'\xd2','\xc2'},{'\x94','\x56'},{'\x00','\x00'}, + {'\xb2','\xa6'},{'\xd6','\x7b'},{'\xd6','\x7a'},{'\xb2','\xa4'},{'\xb2','\xa5'}, + {'\x95','\xcc'},{'\x00','\x00'},{'\x94','\xb2'},{'\xb5','\x66'},{'\xb5','\x65'}, + {'\xda','\xae'},{'\xfa','\xa2'},{'\x81','\xdd'},{'\xda','\xad'},{'\xb2','\xa7'}, + {'\x00','\x00'},{'\x8d','\xe2'},{'\x92','\xec'},{'\x8b','\xaa'},{'\x00','\x00'}, + {'\xb7','\xed'},{'\xde','\xc5'},{'\xb7','\xee'},{'\xde','\xc4'},{'\xfc','\xbd'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xe2','\xd8'},{'\xe6','\xae'},{'\xbd','\x42'}, + {'\xea','\x6a'},{'\x00','\x00'},{'\xfa','\xa3'},{'\xfa','\xa4'},{'\xed','\x73'}, + {'\x00','\x00'},{'\xc3','\xa6'},{'\xc3','\xa5'},{'\x00','\x00'},{'\xfa','\xa5'}, + {'\xc5','\x7c'},{'\xa5','\xd4'},{'\xcd','\x73'},{'\x81','\xde'},{'\x93','\x51'}, + {'\xb2','\xa8'},{'\xe2','\xd9'},{'\xba','\xc3'},{'\xc6','\xd4'},{'\x00','\x00'}, + {'\xcb','\x6f'},{'\xcb','\x70'},{'\x8f','\x78'},{'\x89','\xfb'},{'\xcd','\x74'}, + {'\xaa','\xb8'},{'\xaa','\xb9'},{'\x00','\x00'},{'\x00','\x00'},{'\xaa','\xb7'}, + {'\x81','\xdf'},{'\x86','\xe5'},{'\x8a','\xdd'},{'\x86','\xe6'},{'\xac','\xcf'}, + {'\xac','\xd0'},{'\xac','\xcd'},{'\xac','\xce'},{'\x00','\x00'},{'\xcf','\xdc'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xcf','\xdd'},{'\xac','\xcc'},{'\xfa','\xa6'}, + {'\x00','\x00'},{'\x87','\xf4'},{'\x86','\xe7'},{'\xd2','\xc3'},{'\xfe','\x51'}, + {'\xaf','\x68'},{'\xaf','\x69'},{'\xfb','\x5c'},{'\xb2','\xab'},{'\xd2','\xc9'}, + {'\x00','\x00'},{'\xaf','\x6e'},{'\xaf','\x6c'},{'\xd2','\xca'},{'\xd2','\xc5'}, + {'\xaf','\x6b'},{'\xaf','\x6a'},{'\xaf','\x65'},{'\xd2','\xc8'},{'\xd2','\xc7'}, + {'\xd2','\xc4'},{'\xaf','\x6d'},{'\xfc','\xd3'},{'\xd2','\xc6'},{'\xaf','\x66'}, + {'\x00','\x00'},{'\xaf','\x67'},{'\x8f','\xfd'},{'\x84','\xf9'},{'\xb2','\xac'}, + {'\xd6','\xa1'},{'\xd6','\xa2'},{'\xb2','\xad'},{'\xd6','\x7c'},{'\xd6','\x7e'}, + {'\xd6','\xa4'},{'\xd6','\xa3'},{'\xd6','\x7d'},{'\x00','\x00'},{'\xb2','\xa9'}, + {'\xb2','\xaa'},{'\xfa','\xa7'},{'\xda','\xb6'},{'\xb5','\x6b'},{'\xb5','\x6a'}, + {'\xda','\xb0'},{'\xb5','\x68'},{'\x81','\xe0'},{'\xda','\xb3'},{'\xb5','\x6c'}, + {'\xda','\xb4'},{'\xb5','\x6d'},{'\xda','\xb1'},{'\xb5','\x67'},{'\xb5','\x69'}, + {'\xda','\xb5'},{'\x00','\x00'},{'\xda','\xb2'},{'\xda','\xaf'},{'\x89','\xfa'}, + {'\xfa','\xa8'},{'\x86','\xe8'},{'\x8f','\x58'},{'\x00','\x00'},{'\xde','\xd2'}, + {'\x00','\x00'},{'\xde','\xc7'},{'\xb7','\xf0'},{'\xb7','\xf3'},{'\xb7','\xf2'}, + {'\xb7','\xf7'},{'\xb7','\xf6'},{'\xde','\xd3'},{'\xde','\xd1'},{'\xde','\xca'}, + {'\xde','\xce'},{'\xde','\xcd'},{'\xb7','\xf4'},{'\xde','\xd0'},{'\xde','\xcc'}, + {'\xde','\xd4'},{'\xde','\xcb'},{'\xb7','\xf5'},{'\xb7','\xef'},{'\xb7','\xf1'}, + {'\xfc','\xd5'},{'\xde','\xc9'},{'\x00','\x00'},{'\x8f','\x57'},{'\x00','\x00'}, + {'\xfc','\xd4'},{'\xe2','\xdb'},{'\xba','\xc7'},{'\xe2','\xdf'},{'\xba','\xc6'}, + {'\xe2','\xdc'},{'\xba','\xc5'},{'\x00','\x00'},{'\xde','\xc8'},{'\xde','\xcf'}, + {'\xe2','\xde'},{'\x00','\x00'},{'\xba','\xc8'},{'\xe2','\xe0'},{'\xe2','\xdd'}, + {'\xe2','\xda'},{'\x8e','\xc1'},{'\x89','\x40'},{'\xe6','\xb1'},{'\xe6','\xb5'}, + {'\xe6','\xb7'},{'\xe6','\xb3'},{'\xe6','\xb2'},{'\xe6','\xb0'},{'\xbd','\x45'}, + {'\xbd','\x43'},{'\xbd','\x48'},{'\xbd','\x49'},{'\xe6','\xb4'},{'\xbd','\x46'}, + {'\xe6','\xaf'},{'\xbd','\x47'},{'\xba','\xc4'},{'\xe6','\xb6'},{'\xbd','\x44'}, + {'\x8b','\xab'},{'\x8d','\x54'},{'\x81','\xe1'},{'\xea','\x6c'},{'\x00','\x00'}, + {'\xea','\x6b'},{'\xea','\x73'},{'\xea','\x6d'},{'\xea','\x72'},{'\xea','\x6f'}, + {'\xbf','\x60'},{'\xea','\x71'},{'\x00','\x00'},{'\x00','\x00'},{'\xbf','\x61'}, + {'\x00','\x00'},{'\xbf','\x62'},{'\x95','\xa9'},{'\xea','\x70'},{'\xea','\x6e'}, + {'\x8c','\xd5'},{'\x90','\x58'},{'\xfa','\xa9'},{'\x00','\x00'},{'\xc0','\xf8'}, + {'\xed','\x74'},{'\x00','\x00'},{'\x00','\x00'},{'\xc0','\xf7'},{'\xed','\x77'}, + {'\xed','\x75'},{'\xed','\x76'},{'\x00','\x00'},{'\x00','\x00'},{'\xc0','\xf9'}, + {'\xfa','\xaa'},{'\x95','\x6f'},{'\x81','\xe2'},{'\xf0','\x4d'},{'\x81','\xe3'}, + {'\xc2','\xa1'},{'\xf0','\x4e'},{'\xfa','\xab'},{'\x00','\x00'},{'\xc2','\x7d'}, + {'\xf0','\x4f'},{'\xc2','\x7e'},{'\xf0','\x4c'},{'\xf0','\x50'},{'\x00','\x00'}, + {'\xf0','\x4a'},{'\x00','\x00'},{'\x8c','\x7e'},{'\xc3','\xa7'},{'\xf2','\x78'}, + {'\xc3','\xa8'},{'\xc4','\x6f'},{'\x8c','\xd6'},{'\xf0','\x4b'},{'\xc4','\x70'}, + {'\xfb','\x76'},{'\xfc','\xd7'},{'\xfa','\xac'},{'\xc4','\xee'},{'\xf5','\xdf'}, + {'\x8d','\x55'},{'\xc5','\x7e'},{'\xf6','\xf4'},{'\xc5','\x7d'},{'\xfc','\xd8'}, + {'\xf7','\xea'},{'\xc5','\xf5'},{'\xc5','\xf6'},{'\x81','\xe4'},{'\x81','\xe5'}, + {'\xf9','\xcc'},{'\xc6','\xd5'},{'\x00','\x00'},{'\xac','\xd1'},{'\xcf','\xde'}, + {'\x93','\xb9'},{'\xb5','\x6e'},{'\xb5','\x6f'},{'\xa5','\xd5'},{'\xa6','\xca'}, + {'\xca','\x47'},{'\xfa','\xad'},{'\xcb','\x71'},{'\xa8','\x6d'},{'\xfa','\xae'}, + {'\xaa','\xba'},{'\x00','\x00'},{'\xac','\xd2'},{'\xac','\xd3'},{'\xac','\xd4'}, + {'\xd6','\xa6'},{'\xd2','\xcb'},{'\xaf','\x6f'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb2','\xae'},{'\xd6','\xa5'},{'\xfa','\xaf'},{'\x87','\xf5'},{'\xda','\xb8'}, + {'\xb5','\x71'},{'\x00','\x00'},{'\xda','\xb7'},{'\xb5','\x70'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xde','\xd5'},{'\xbd','\x4a'},{'\xe6','\xbb'},{'\xe6','\xb8'}, + {'\xe6','\xb9'},{'\xe6','\xba'},{'\x00','\x00'},{'\x00','\x00'},{'\xfc','\xbe'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xed','\x78'},{'\x81','\xe6'},{'\xf0','\x51'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xf4','\x71'},{'\xf4','\x70'}, + {'\x00','\x00'},{'\xf6','\xf5'},{'\xa5','\xd6'},{'\xcd','\x75'},{'\xaf','\x70'}, + {'\x87','\xf6'},{'\x8e','\x77'},{'\x00','\x00'},{'\xb5','\x72'},{'\xde','\xd6'}, + {'\x00','\x00'},{'\xfa','\xb0'},{'\xe2','\xe1'},{'\xfa','\xb1'},{'\xbd','\x4b'}, + {'\xea','\x74'},{'\x00','\x00'},{'\xf0','\x52'},{'\xf4','\x72'},{'\xa5','\xd7'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xaa','\xbb'},{'\xac','\xd7'},{'\xcf','\xdf'}, + {'\xac','\xd8'},{'\xac','\xd6'},{'\x00','\x00'},{'\xac','\xd5'},{'\xd2','\xcc'}, + {'\xaf','\x71'},{'\x00','\x00'},{'\xfc','\xbf'},{'\xaf','\x72'},{'\xaf','\x73'}, + {'\x85','\xe6'},{'\x8d','\x69'},{'\x86','\xea'},{'\xb2','\xb0'},{'\xd6','\xa7'}, + {'\xb2','\xaf'},{'\x00','\x00'},{'\x87','\x49'},{'\x84','\xfb'},{'\x87','\xf7'}, + {'\x81','\xe7'},{'\xda','\xb9'},{'\xb2','\xb1'},{'\xb5','\x73'},{'\xde','\xd7'}, + {'\xb7','\xf8'},{'\xb7','\xf9'},{'\x00','\x00'},{'\xba','\xc9'},{'\x00','\x00'}, + {'\xba','\xca'},{'\xbd','\x4c'},{'\xbf','\x64'},{'\xea','\x75'},{'\xbf','\x63'}, + {'\x00','\x00'},{'\xed','\x79'},{'\xc0','\xfa'},{'\x00','\x00'},{'\xf0','\x53'}, + {'\xf4','\x73'},{'\xa5','\xd8'},{'\xa8','\x6e'},{'\xcd','\x78'},{'\xcd','\x77'}, + {'\xaa','\xbc'},{'\xcd','\x76'},{'\xaa','\xbd'},{'\xcd','\x79'},{'\x00','\x00'}, + {'\xcf','\xe5'},{'\xac','\xdb'},{'\xac','\xda'},{'\xcf','\xe7'},{'\xcf','\xe6'}, + {'\xac','\xdf'},{'\x00','\x00'},{'\xac','\xde'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xac','\xd9'},{'\x00','\x00'},{'\xcf','\xe1'},{'\xcf','\xe2'},{'\xcf','\xe3'}, + {'\x00','\x00'},{'\xac','\xe0'},{'\xcf','\xe0'},{'\xac','\xdc'},{'\xcf','\xe4'}, + {'\xac','\xdd'},{'\x92','\xb1'},{'\xfa','\xb2'},{'\x81','\xe8'},{'\x81','\xe9'}, + {'\xd2','\xcf'},{'\xd2','\xd3'},{'\xd2','\xd1'},{'\xd2','\xd0'},{'\x00','\x00'}, + {'\xd2','\xd4'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xd2','\xd5'}, + {'\xd2','\xd6'},{'\xd2','\xce'},{'\x00','\x00'},{'\xd2','\xcd'},{'\xfa','\xb3'}, + {'\xaf','\x75'},{'\xaf','\x76'},{'\x00','\x00'},{'\xd2','\xd7'},{'\xd2','\xd2'}, + {'\xfc','\xc0'},{'\xd6','\xb0'},{'\x8d','\xd2'},{'\xd2','\xd8'},{'\xaf','\x77'}, + {'\xaf','\x74'},{'\x00','\x00'},{'\xfc','\xc1'},{'\x00','\x00'},{'\xd6','\xaa'}, + {'\x00','\x00'},{'\xd6','\xa9'},{'\x00','\x00'},{'\xd6','\xab'},{'\xd6','\xac'}, + {'\xd6','\xae'},{'\xd6','\xad'},{'\xd6','\xb2'},{'\xb2','\xb5'},{'\xb2','\xb2'}, + {'\xb2','\xb6'},{'\xd6','\xa8'},{'\xb2','\xb7'},{'\xd6','\xb1'},{'\xb2','\xb4'}, + {'\xd6','\xaf'},{'\xb2','\xb3'},{'\x00','\x00'},{'\x95','\x4d'},{'\x85','\xe8'}, + {'\x00','\x00'},{'\xfa','\xb4'},{'\xda','\xbc'},{'\xda','\xbe'},{'\xda','\xba'}, + {'\xda','\xbb'},{'\x00','\x00'},{'\x00','\x00'},{'\xda','\xbf'},{'\xda','\xc1'}, + {'\xda','\xc2'},{'\xda','\xbd'},{'\xda','\xc0'},{'\xb5','\x74'},{'\x85','\xe7'}, + {'\x8a','\xde'},{'\xde','\xdb'},{'\x00','\x00'},{'\xde','\xe0'},{'\xde','\xd8'}, + {'\xde','\xdc'},{'\x00','\x00'},{'\x81','\xea'},{'\xde','\xe1'},{'\xde','\xdd'}, + {'\xb7','\xfa'},{'\xb8','\x43'},{'\x00','\x00'},{'\xb7','\xfd'},{'\xde','\xd9'}, + {'\xde','\xda'},{'\xba','\xce'},{'\xb8','\x46'},{'\xb7','\xfe'},{'\x00','\x00'}, + {'\xb8','\x44'},{'\xb7','\xfc'},{'\xde','\xdf'},{'\xb8','\x45'},{'\xde','\xde'}, + {'\xb8','\x41'},{'\xb7','\xfb'},{'\xb8','\x42'},{'\xde','\xe2'},{'\xe2','\xe6'}, + {'\xe2','\xe8'},{'\x00','\x00'},{'\x00','\x00'},{'\x81','\xeb'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x81','\xec'},{'\x81','\xed'}, + {'\xb8','\x40'},{'\x81','\xee'},{'\x81','\xef'},{'\xe2','\xe3'},{'\xba','\xcc'}, + {'\xe2','\xe9'},{'\xba','\xcd'},{'\xe2','\xe7'},{'\xe2','\xe2'},{'\xe2','\xe5'}, + {'\xe2','\xea'},{'\xba','\xcb'},{'\xe2','\xe4'},{'\x00','\x00'},{'\xbd','\x4e'}, + {'\xe6','\xbf'},{'\xe6','\xbe'},{'\x00','\x00'},{'\xbd','\x51'},{'\xbd','\x4f'}, + {'\xe6','\xbc'},{'\xbd','\x4d'},{'\xe6','\xbd'},{'\x00','\x00'},{'\xbd','\x50'}, + {'\x89','\x42'},{'\xfb','\x6b'},{'\x00','\x00'},{'\xea','\x7d'},{'\x00','\x00'}, + {'\xea','\xa1'},{'\x81','\xf0'},{'\xea','\x7e'},{'\xea','\x76'},{'\xea','\x7a'}, + {'\xea','\x79'},{'\xea','\x77'},{'\xbf','\x66'},{'\xbf','\x67'},{'\xbf','\x65'}, + {'\xea','\x78'},{'\xea','\x7b'},{'\xea','\x7c'},{'\x00','\x00'},{'\xbf','\x68'}, + {'\x00','\x00'},{'\xc1','\x40'},{'\xed','\xa3'},{'\x8d','\x7c'},{'\xc0','\xfc'}, + {'\xed','\x7b'},{'\xc0','\xfe'},{'\xc1','\x41'},{'\x00','\x00'},{'\x81','\xf1'}, + {'\xc0','\xfd'},{'\xed','\xa2'},{'\xed','\x7c'},{'\xc0','\xfb'},{'\xed','\xa1'}, + {'\xed','\x7a'},{'\xed','\x7e'},{'\xed','\x7d'},{'\x00','\x00'},{'\xfe','\x5a'}, + {'\xf0','\x55'},{'\xc2','\xa4'},{'\xc2','\xa5'},{'\xc2','\xa2'},{'\x81','\xf2'}, + {'\xc2','\xa3'},{'\x00','\x00'},{'\x00','\x00'},{'\xf0','\x54'},{'\x81','\xf3'}, + {'\xf2','\x7b'},{'\x81','\xf4'},{'\x00','\x00'},{'\xc3','\xa9'},{'\x00','\x00'}, + {'\xf2','\x79'},{'\xf2','\x7a'},{'\x81','\xf5'},{'\xf4','\x74'},{'\xf4','\x77'}, + {'\xf4','\x75'},{'\xf4','\x76'},{'\xf5','\xe0'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc4','\xef'},{'\xf7','\xeb'},{'\xf8','\xb4'},{'\x00','\x00'},{'\xc5','\xf7'}, + {'\xf8','\xf8'},{'\xf8','\xf9'},{'\xc6','\x66'},{'\xa5','\xd9'},{'\xac','\xe1'}, + {'\x81','\xf6'},{'\xda','\xc3'},{'\x00','\x00'},{'\xde','\xe3'},{'\x00','\x00'}, + {'\xa5','\xda'},{'\xa8','\x6f'},{'\x00','\x00'},{'\xaa','\xbe'},{'\x81','\xf7'}, + {'\xcf','\xe8'},{'\xcf','\xe9'},{'\xaf','\x78'},{'\x00','\x00'},{'\x89','\xfc'}, + {'\xda','\xc4'},{'\xb5','\x75'},{'\xb8','\x47'},{'\xc1','\x42'},{'\xed','\xa4'}, + {'\xf2','\x7c'},{'\xf4','\x78'},{'\xa5','\xdb'},{'\x81','\xf8'},{'\x00','\x00'}, + {'\x89','\xfe'},{'\xcd','\xa1'},{'\xcd','\x7a'},{'\xcd','\x7c'},{'\xcd','\x7e'}, + {'\xcd','\x7d'},{'\xcd','\x7b'},{'\xaa','\xbf'},{'\x8c','\x41'},{'\x8b','\xfe'}, + {'\x8e','\x78'},{'\x87','\xf9'},{'\xac','\xe2'},{'\xcf','\xf2'},{'\x00','\x00'}, + {'\xcf','\xed'},{'\xcf','\xea'},{'\x00','\x00'},{'\x96','\x41'},{'\xcf','\xf1'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xac','\xe4'},{'\xac','\xe5'},{'\xcf','\xf0'}, + {'\xcf','\xef'},{'\xcf','\xee'},{'\xcf','\xeb'},{'\xcf','\xec'},{'\xcf','\xf3'}, + {'\xac','\xe3'},{'\x92','\xc5'},{'\x89','\x43'},{'\x8d','\xe3'},{'\xfa','\xb5'}, + {'\x00','\x00'},{'\x84','\xfc'},{'\x00','\x00'},{'\xfa','\xb6'},{'\xaf','\x7c'}, + {'\x81','\xf9'},{'\xaf','\xa4'},{'\xaf','\xa3'},{'\xd2','\xe1'},{'\xd2','\xdb'}, + {'\xd2','\xd9'},{'\x00','\x00'},{'\xaf','\xa1'},{'\xd6','\xb9'},{'\xaf','\x7a'}, + {'\xd2','\xde'},{'\xd2','\xe2'},{'\xd2','\xe4'},{'\xd2','\xe0'},{'\xd2','\xda'}, + {'\xaf','\xa2'},{'\xd2','\xdf'},{'\xd2','\xdd'},{'\xaf','\x79'},{'\xd2','\xe5'}, + {'\xaf','\xa5'},{'\xd2','\xe3'},{'\xaf','\x7d'},{'\xd2','\xdc'},{'\x00','\x00'}, + {'\xaf','\x7e'},{'\xaf','\x7b'},{'\xfa','\xb7'},{'\x8c','\x40'},{'\x90','\x42'}, + {'\xfa','\xb8'},{'\x81','\xfa'},{'\x8c','\x42'},{'\x82','\x5f'},{'\x8a','\xdf'}, + {'\x00','\x00'},{'\x81','\xfb'},{'\xb2','\xb9'},{'\x81','\xfc'},{'\xd6','\xba'}, + {'\x00','\x00'},{'\xfa','\xb9'},{'\xd6','\xb3'},{'\xd6','\xb5'},{'\xd6','\xb7'}, + {'\x81','\xfd'},{'\xd6','\xb8'},{'\xd6','\xb6'},{'\xb2','\xba'},{'\x00','\x00'}, + {'\xd6','\xbb'},{'\x81','\xfe'},{'\xd6','\xb4'},{'\xfc','\xc3'},{'\x96','\x4b'}, + {'\x86','\xeb'},{'\xfa','\xba'},{'\x8f','\x59'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xda','\xc8'},{'\xb5','\x76'},{'\xda','\xd0'}, + {'\x00','\x00'},{'\xda','\xc5'},{'\x00','\x00'},{'\xda','\xd1'},{'\x00','\x00'}, + {'\xda','\xc6'},{'\xda','\xc7'},{'\x96','\x4c'},{'\x00','\x00'},{'\xda','\xcf'}, + {'\xda','\xce'},{'\xda','\xcb'},{'\xb2','\xb8'},{'\xb5','\x77'},{'\xda','\xc9'}, + {'\xda','\xcc'},{'\xb5','\x78'},{'\xda','\xcd'},{'\xda','\xca'},{'\x94','\x54'}, + {'\x00','\x00'},{'\x94','\xb4'},{'\x00','\x00'},{'\x00','\x00'},{'\x8d','\x68'}, + {'\x00','\x00'},{'\xde','\xee'},{'\xfa','\xbb'},{'\xde','\xf2'},{'\xb8','\x4e'}, + {'\x00','\x00'},{'\xe2','\xf0'},{'\xb8','\x51'},{'\xde','\xf0'},{'\xf9','\xd6'}, + {'\x00','\x00'},{'\xde','\xed'},{'\xde','\xe8'},{'\xde','\xea'},{'\xde','\xeb'}, + {'\xde','\xe4'},{'\x96','\x4d'},{'\xb8','\x4d'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb8','\x4c'},{'\x8b','\xac'},{'\xb8','\x48'},{'\xde','\xe7'},{'\x00','\x00'}, + {'\xb8','\x4f'},{'\x00','\x00'},{'\xb8','\x50'},{'\xde','\xe6'},{'\xde','\xe9'}, + {'\xde','\xf1'},{'\xb8','\x4a'},{'\xb8','\x4b'},{'\xde','\xef'},{'\xde','\xe5'}, + {'\x89','\x44'},{'\x8e','\xed'},{'\x00','\x00'},{'\xe2','\xf2'},{'\xba','\xd0'}, + {'\xe2','\xf4'},{'\xde','\xec'},{'\xe2','\xf6'},{'\xba','\xd4'},{'\xe2','\xf7'}, + {'\xe2','\xf3'},{'\x00','\x00'},{'\xba','\xd1'},{'\xe2','\xef'},{'\xba','\xd3'}, + {'\xe2','\xec'},{'\xe2','\xf1'},{'\xe2','\xf5'},{'\xe2','\xee'},{'\x00','\x00'}, + {'\xfc','\xc7'},{'\xb8','\x49'},{'\x95','\xf0'},{'\xe2','\xeb'},{'\xba','\xd2'}, + {'\xe2','\xed'},{'\xfa','\xbc'},{'\x96','\x4e'},{'\x00','\x00'},{'\x96','\xcd'}, + {'\xfa','\xbd'},{'\xbd','\x54'},{'\xe6','\xc1'},{'\xbd','\x58'},{'\x00','\x00'}, + {'\xbd','\x56'},{'\x00','\x00'},{'\x00','\x00'},{'\xba','\xcf'},{'\x00','\x00'}, + {'\xe6','\xc8'},{'\xe6','\xc9'},{'\xbd','\x53'},{'\xfa','\xbe'},{'\x96','\x4f'}, + {'\xe6','\xc7'},{'\xe6','\xca'},{'\xbd','\x55'},{'\xbd','\x52'},{'\xe6','\xc3'}, + {'\xe6','\xc0'},{'\xe6','\xc5'},{'\xe6','\xc2'},{'\xbd','\x59'},{'\xe6','\xc4'}, + {'\x96','\x50'},{'\xfc','\xc4'},{'\xe6','\xc6'},{'\xbd','\x57'},{'\x00','\x00'}, + {'\x96','\x51'},{'\xfc','\xc5'},{'\xfa','\xbf'},{'\xbf','\x6a'},{'\xea','\xa8'}, + {'\x00','\x00'},{'\xea','\xa2'},{'\xea','\xa6'},{'\xea','\xac'},{'\xea','\xad'}, + {'\xea','\xa9'},{'\xea','\xaa'},{'\xea','\xa7'},{'\x96','\x54'},{'\xea','\xa4'}, + {'\x00','\x00'},{'\xbf','\x6c'},{'\xbf','\x69'},{'\xea','\xa3'},{'\xea','\xa5'}, + {'\x00','\x00'},{'\xbf','\x6b'},{'\xea','\xab'},{'\x96','\x55'},{'\xc1','\x46'}, + {'\x96','\x56'},{'\x96','\x57'},{'\xed','\xaa'},{'\xed','\xa5'},{'\xc1','\x45'}, + {'\x96','\x58'},{'\x00','\x00'},{'\xc1','\x43'},{'\x00','\x00'},{'\xed','\xac'}, + {'\xc1','\x44'},{'\xed','\xa8'},{'\xed','\xa9'},{'\xed','\xa6'},{'\xed','\xad'}, + {'\xf0','\x56'},{'\x00','\x00'},{'\xc1','\x47'},{'\xed','\xa7'},{'\x00','\x00'}, + {'\xed','\xae'},{'\xed','\xab'},{'\xfb','\xa8'},{'\xfa','\xc0'},{'\x00','\x00'}, + {'\xf0','\x5a'},{'\x00','\x00'},{'\x00','\x00'},{'\xf0','\x57'},{'\x00','\x00'}, + {'\xc2','\xa6'},{'\x00','\x00'},{'\xf0','\x5b'},{'\xf0','\x5d'},{'\xf0','\x5c'}, + {'\xf0','\x58'},{'\xf0','\x59'},{'\x00','\x00'},{'\x00','\x00'},{'\xf2','\xa3'}, + {'\x00','\x00'},{'\xc3','\xaa'},{'\x00','\x00'},{'\xf2','\x7e'},{'\xf2','\xa2'}, + {'\xf2','\x7d'},{'\xf2','\xa4'},{'\x00','\x00'},{'\x00','\x00'},{'\xf2','\xa1'}, + {'\x00','\x00'},{'\xf4','\x7a'},{'\xf4','\x7d'},{'\xf4','\x79'},{'\xc4','\x71'}, + {'\xf4','\x7b'},{'\xf4','\x7c'},{'\xf4','\x7e'},{'\xc4','\x72'},{'\xc4','\x74'}, + {'\xc4','\x73'},{'\xf5','\xe1'},{'\xfe','\x77'},{'\xf5','\xe3'},{'\xfa','\xc1'}, + {'\xf5','\xe2'},{'\x96','\x59'},{'\x96','\x5a'},{'\xfa','\xc2'},{'\xf6','\xf6'}, + {'\x96','\x5b'},{'\x00','\x00'},{'\xf8','\xb5'},{'\xf8','\xfa'},{'\xa5','\xdc'}, + {'\xfa','\xc3'},{'\x8a','\xe0'},{'\xcb','\x72'},{'\xaa','\xc0'},{'\xcd','\xa3'}, + {'\xaa','\xc1'},{'\xaa','\xc2'},{'\xcd','\xa2'},{'\x00','\x00'},{'\xcf','\xf8'}, + {'\xcf','\xf7'},{'\xac','\xe6'},{'\xac','\xe9'},{'\xac','\xe8'},{'\xac','\xe7'}, + {'\xcf','\xf4'},{'\xcf','\xf6'},{'\xcf','\xf5'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xd2','\xe8'},{'\xaf','\xa7'},{'\xd2','\xec'},{'\xd2','\xeb'},{'\xd2','\xea'}, + {'\xd2','\xe6'},{'\xaf','\xa6'},{'\xaf','\xaa'},{'\xaf','\xad'},{'\x96','\x5c'}, + {'\x96','\x5e'},{'\xaf','\xae'},{'\xd2','\xe7'},{'\xd2','\xe9'},{'\xaf','\xac'}, + {'\xaf','\xab'},{'\xaf','\xa9'},{'\xaf','\xa8'},{'\xd6','\xc2'},{'\x8f','\xbe'}, + {'\xd6','\xc0'},{'\xd6','\xbc'},{'\xb2','\xbb'},{'\x00','\x00'},{'\xd6','\xbd'}, + {'\xb2','\xbc'},{'\xd6','\xbe'},{'\xd6','\xbf'},{'\xd6','\xc1'},{'\x00','\x00'}, + {'\xb2','\xbd'},{'\x00','\x00'},{'\x86','\xec'},{'\xda','\xd5'},{'\x96','\x5f'}, + {'\xda','\xd4'},{'\xda','\xd3'},{'\xda','\xd2'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x82','\x70'},{'\x86','\xed'},{'\xde','\xf6'},{'\xb8','\x52'},{'\x00','\x00'}, + {'\xde','\xf3'},{'\xde','\xf5'},{'\x96','\x60'},{'\xb8','\x53'},{'\xfa','\xc4'}, + {'\xb8','\x54'},{'\xde','\xf4'},{'\x96','\x61'},{'\x82','\x77'},{'\x93','\x50'}, + {'\x96','\x62'},{'\x96','\x63'},{'\xe3','\x41'},{'\x00','\x00'},{'\xe2','\xf9'}, + {'\xe2','\xfa'},{'\x00','\x00'},{'\xba','\xd7'},{'\xba','\xd5'},{'\xba','\xd6'}, + {'\xe3','\x43'},{'\x96','\x64'},{'\xe3','\x42'},{'\xe2','\xfe'},{'\xe2','\xfd'}, + {'\xe2','\xfc'},{'\xe2','\xfb'},{'\xe3','\x40'},{'\xe2','\xf8'},{'\x96','\x65'}, + {'\xe6','\xcb'},{'\xe6','\xd0'},{'\xe6','\xce'},{'\xfa','\xc5'},{'\x00','\x00'}, + {'\x96','\x66'},{'\xe6','\xcd'},{'\xe6','\xcc'},{'\xe6','\xcf'},{'\x00','\x00'}, + {'\xea','\xae'},{'\x96','\x67'},{'\xbf','\x6d'},{'\xc1','\x48'},{'\xed','\xb0'}, + {'\xfc','\xca'},{'\xc1','\x49'},{'\xed','\xaf'},{'\xf0','\x5f'},{'\xf0','\x5e'}, + {'\xc2','\xa7'},{'\x00','\x00'},{'\xf2','\xa5'},{'\xc3','\xab'},{'\xf4','\xa1'}, + {'\xc5','\xa1'},{'\xf6','\xf7'},{'\x00','\x00'},{'\xf8','\xb7'},{'\xf8','\xb6'}, + {'\xc9','\xa8'},{'\xac','\xea'},{'\xac','\xeb'},{'\xd6','\xc3'},{'\x00','\x00'}, + {'\xb8','\x56'},{'\xa5','\xdd'},{'\xa8','\x72'},{'\xa8','\x71'},{'\xa8','\x70'}, + {'\x00','\x00'},{'\xfa','\xc6'},{'\xfb','\xa9'},{'\xcd','\xa4'},{'\x84','\xfd'}, + {'\x00','\x00'},{'\xaa','\xc4'},{'\xaa','\xc3'},{'\x9d','\xce'},{'\xac','\xee'}, + {'\xfc','\xa6'},{'\xcf','\xfa'},{'\xcf','\xfd'},{'\xcf','\xfb'},{'\x00','\x00'}, + {'\xac','\xec'},{'\xac','\xed'},{'\x00','\x00'},{'\xfc','\xcc'},{'\xcf','\xf9'}, + {'\xcf','\xfc'},{'\x00','\x00'},{'\xaf','\xb5'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd2','\xf3'},{'\xd2','\xf5'},{'\xd2','\xf4'},{'\xaf','\xb2'}, + {'\xd2','\xef'},{'\xfa','\xc7'},{'\x96','\x68'},{'\xaf','\xb0'},{'\xaf','\xaf'}, + {'\x00','\x00'},{'\xaf','\xb3'},{'\xaf','\xb1'},{'\x00','\x00'},{'\xaf','\xb4'}, + {'\xd2','\xf2'},{'\xd2','\xed'},{'\xd2','\xee'},{'\xd2','\xf1'},{'\xd2','\xf0'}, + {'\x85','\xb8'},{'\x86','\xef'},{'\x96','\x69'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x96','\x6a'},{'\x00','\x00'},{'\xd6','\xc6'},{'\xd6','\xc7'},{'\xd6','\xc5'}, + {'\x00','\x00'},{'\xd6','\xc4'},{'\xb2','\xbe'},{'\x00','\x00'},{'\x8a','\xe2'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb5','\x7d'},{'\x00','\x00'},{'\xda','\xd6'}, + {'\xda','\xd8'},{'\xda','\xda'},{'\xb5','\x7c'},{'\xfa','\xc8'},{'\x00','\x00'}, + {'\xb5','\x7a'},{'\x00','\x00'},{'\xda','\xd7'},{'\xb5','\x7b'},{'\xda','\xd9'}, + {'\xb5','\x79'},{'\xfa','\xc9'},{'\x00','\x00'},{'\xdf','\x41'},{'\xde','\xf7'}, + {'\xde','\xfa'},{'\xde','\xfe'},{'\xb8','\x5a'},{'\xde','\xfc'},{'\x00','\x00'}, + {'\xde','\xfb'},{'\xde','\xf8'},{'\xde','\xf9'},{'\xb8','\x58'},{'\xdf','\x40'}, + {'\xb8','\x57'},{'\x00','\x00'},{'\xb8','\x5c'},{'\xb8','\x5b'},{'\xb8','\x59'}, + {'\x00','\x00'},{'\xde','\xfd'},{'\x89','\x47'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xe3','\x49'},{'\x00','\x00'},{'\xe3','\x48'},{'\x00','\x00'},{'\x96','\x6b'}, + {'\xe3','\x44'},{'\x00','\x00'},{'\xfc','\xce'},{'\xba','\xd8'},{'\xe3','\x47'}, + {'\xe3','\x46'},{'\xba','\xd9'},{'\x93','\xa6'},{'\x8b','\xae'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xbd','\x5e'},{'\x00','\x00'},{'\xe6','\xd2'}, + {'\x96','\x6c'},{'\xbd','\x5f'},{'\xbd','\x5b'},{'\xbd','\x5d'},{'\xfc','\xcf'}, + {'\xbd','\x5a'},{'\xbd','\x5c'},{'\x00','\x00'},{'\x92','\xf9'},{'\xfa','\xca'}, + {'\xea','\xaf'},{'\x96','\x6d'},{'\xbf','\x70'},{'\xea','\xb1'},{'\xea','\xb0'}, + {'\xfc','\xd0'},{'\xe3','\x45'},{'\xbf','\x72'},{'\xbf','\x71'},{'\xbf','\x6e'}, + {'\xbf','\x6f'},{'\x92','\x53'},{'\xfa','\xcb'},{'\x8a','\xe1'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xed','\xb5'},{'\x00','\x00'},{'\xed','\xb3'},{'\xc1','\x4a'}, + {'\xed','\xb4'},{'\x00','\x00'},{'\xed','\xb6'},{'\xed','\xb2'},{'\xed','\xb1'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xf0','\x60'},{'\xc2','\xaa'},{'\xc2','\xa8'}, + {'\xc2','\xa9'},{'\x82','\x67'},{'\x00','\x00'},{'\x96','\x6e'},{'\x00','\x00'}, + {'\xf2','\xa6'},{'\xf2','\xa7'},{'\xc3','\xad'},{'\x00','\x00'},{'\xc3','\xac'}, + {'\xf4','\xa3'},{'\xf4','\xa4'},{'\xf4','\xa2'},{'\x00','\x00'},{'\xf6','\xf8'}, + {'\xf6','\xf9'},{'\x00','\x00'},{'\x00','\x00'},{'\xa5','\xde'},{'\xca','\x48'}, + {'\xa8','\x73'},{'\x87','\xfb'},{'\xcd','\xa5'},{'\xaa','\xc6'},{'\xaa','\xc5'}, + {'\xcd','\xa6'},{'\x00','\x00'},{'\xfc','\x42'},{'\xd0','\x40'},{'\xac','\xef'}, + {'\xcf','\xfe'},{'\xac','\xf0'},{'\x00','\x00'},{'\x8c','\xfa'},{'\xaf','\xb6'}, + {'\xd2','\xf8'},{'\xd2','\xf6'},{'\xd2','\xfc'},{'\xaf','\xb7'},{'\xd2','\xf7'}, + {'\xd2','\xfb'},{'\xd2','\xf9'},{'\xd2','\xfa'},{'\x8a','\xe4'},{'\x00','\x00'}, + {'\xd6','\xc8'},{'\xd6','\xca'},{'\x87','\xfa'},{'\xb2','\xbf'},{'\x93','\x58'}, + {'\xd6','\xc9'},{'\xb2','\xc0'},{'\xb5','\xa2'},{'\xb5','\xa1'},{'\xb5','\x7e'}, + {'\xda','\xdb'},{'\x00','\x00'},{'\x00','\x00'},{'\x8a','\xe3'},{'\x86','\xf1'}, + {'\xdf','\x44'},{'\xb8','\x5d'},{'\xb8','\x5e'},{'\x00','\x00'},{'\xdf','\x43'}, + {'\xdf','\x42'},{'\x00','\x00'},{'\x89','\x48'},{'\x8c','\x43'},{'\x00','\x00'}, + {'\xe3','\x4a'},{'\xba','\xdb'},{'\xba','\xda'},{'\xe3','\x4b'},{'\xe3','\x4c'}, + {'\x8e','\xee'},{'\xbd','\x61'},{'\xbd','\x60'},{'\xfe','\xa7'},{'\xea','\xb5'}, + {'\xe6','\xd3'},{'\xe6','\xd5'},{'\xe6','\xd4'},{'\xea','\xb4'},{'\xea','\xb2'}, + {'\xea','\xb6'},{'\xea','\xb3'},{'\x00','\x00'},{'\xbf','\x73'},{'\xfc','\x44'}, + {'\x96','\x6f'},{'\x00','\x00'},{'\xed','\xb7'},{'\xc1','\x4b'},{'\xed','\xb8'}, + {'\xed','\xb9'},{'\x96','\x70'},{'\xfa','\xcc'},{'\xc2','\xab'},{'\xc2','\xac'}, + {'\x00','\x00'},{'\xc4','\x75'},{'\xfd','\xe5'},{'\x96','\x71'},{'\xc5','\xd1'}, + {'\xa5','\xdf'},{'\x00','\x00'},{'\x94','\xb5'},{'\x00','\x00'},{'\x94','\xb6'}, + {'\x00','\x00'},{'\xd0','\x41'},{'\xfa','\xcd'},{'\x94','\xb8'},{'\x00','\x00'}, + {'\x94','\xb7'},{'\x88','\x67'},{'\x00','\x00'},{'\xd2','\xfd'},{'\xaf','\xb8'}, + {'\xfc','\xd2'},{'\x96','\x72'},{'\x93','\xe2'},{'\xfc','\xd1'},{'\x8c','\x44'}, + {'\xb3','\xba'},{'\xb3','\xb9'},{'\x94','\xb9'},{'\xfa','\xce'},{'\xb5','\xa4'}, + {'\xda','\xdd'},{'\xb5','\xa3'},{'\xda','\xdc'},{'\xfa','\xcf'},{'\x00','\x00'}, + {'\x96','\x73'},{'\x82','\x6d'},{'\xdf','\x45'},{'\x00','\x00'},{'\xba','\xdc'}, + {'\xe3','\x4d'},{'\xba','\xdd'},{'\x94','\xba'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc4','\x76'},{'\xf4','\xa5'}, + {'\xfa','\xd0'},{'\xa6','\xcb'},{'\xaa','\xc7'},{'\xcd','\xa7'},{'\x00','\x00'}, + {'\xac','\xf2'},{'\x96','\x74'},{'\xac','\xf1'},{'\xd0','\x42'},{'\xd0','\x43'}, + {'\x94','\xbb'},{'\x89','\x49'},{'\xd3','\x40'},{'\xd3','\x42'},{'\xaf','\xb9'}, + {'\x00','\x00'},{'\xd3','\x44'},{'\xd3','\x47'},{'\xd3','\x45'},{'\x85','\x41'}, + {'\x96','\x75'},{'\x00','\x00'},{'\xd3','\x46'},{'\xd3','\x43'},{'\xd2','\xfe'}, + {'\xaf','\xba'},{'\xd3','\x48'},{'\xd3','\x41'},{'\x85','\x40'},{'\x85','\xec'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xd6','\xd3'},{'\xb2','\xc6'},{'\xd6','\xdc'}, + {'\xb2','\xc3'},{'\x00','\x00'},{'\xd6','\xd5'},{'\xb2','\xc7'},{'\xfc','\xdc'}, + {'\xb2','\xc1'},{'\x00','\x00'},{'\xd6','\xd0'},{'\xd6','\xdd'},{'\xd6','\xd1'}, + {'\xd6','\xce'},{'\xb2','\xc5'},{'\x96','\x76'},{'\xb2','\xc2'},{'\x96','\x77'}, + {'\xd6','\xd4'},{'\xd6','\xd7'},{'\xb2','\xc4'},{'\xd6','\xd8'},{'\xb2','\xc8'}, + {'\xd6','\xd9'},{'\xd6','\xcf'},{'\xd6','\xd6'},{'\xd6','\xda'},{'\xd6','\xd2'}, + {'\xd6','\xcd'},{'\xd6','\xcb'},{'\xfa','\xd1'},{'\x00','\x00'},{'\xd6','\xdb'}, + {'\xfe','\x64'},{'\x86','\xf2'},{'\xda','\xdf'},{'\x8c','\xd7'},{'\x00','\x00'}, + {'\x90','\x7a'},{'\x00','\x00'},{'\xda','\xe4'},{'\x00','\x00'},{'\x96','\x78'}, + {'\x96','\x79'},{'\xda','\xe0'},{'\xda','\xe6'},{'\xb5','\xa7'},{'\xd6','\xcc'}, + {'\xda','\xe1'},{'\xb5','\xa5'},{'\xda','\xde'},{'\xb5','\xac'},{'\xda','\xe2'}, + {'\xb5','\xab'},{'\xda','\xe3'},{'\xb5','\xad'},{'\xb5','\xa8'},{'\xb5','\xae'}, + {'\xb5','\xa9'},{'\x00','\x00'},{'\xb5','\xaa'},{'\x96','\x7a'},{'\xb5','\xa6'}, + {'\x00','\x00'},{'\xda','\xe5'},{'\x00','\x00'},{'\x8f','\x5b'},{'\x89','\x4a'}, + {'\x00','\x00'},{'\x86','\xf3'},{'\x00','\x00'},{'\x00','\x00'},{'\xb8','\x61'}, + {'\xdf','\x50'},{'\xfa','\xd2'},{'\xdf','\x53'},{'\xdf','\x47'},{'\xdf','\x4c'}, + {'\xdf','\x46'},{'\xb8','\x63'},{'\x00','\x00'},{'\xdf','\x4a'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xfa','\xd3'},{'\xdf','\x48'},{'\xb8','\x62'},{'\x96','\x7b'}, + {'\xdf','\x4f'},{'\xdf','\x4e'},{'\xdf','\x4b'},{'\xdf','\x4d'},{'\xdf','\x49'}, + {'\xba','\xe1'},{'\xdf','\x52'},{'\xb8','\x5f'},{'\xdf','\x51'},{'\x8c','\x45'}, + {'\xfa','\xd4'},{'\xfa','\xd5'},{'\x00','\x00'},{'\x00','\x00'},{'\x8b','\xaf'}, + {'\x00','\x00'},{'\x8a','\xe9'},{'\x00','\x00'},{'\xe3','\x5d'},{'\x00','\x00'}, + {'\xba','\xe8'},{'\xe3','\x58'},{'\x82','\x7a'},{'\xba','\xe7'},{'\xe3','\x4e'}, + {'\x00','\x00'},{'\xe3','\x50'},{'\xba','\xe0'},{'\xe3','\x55'},{'\xe3','\x54'}, + {'\xe3','\x57'},{'\xba','\xe5'},{'\xe3','\x52'},{'\xe3','\x51'},{'\xfc','\xdd'}, + {'\x00','\x00'},{'\xba','\xe4'},{'\xba','\xdf'},{'\xe3','\x53'},{'\xba','\xe2'}, + {'\xe3','\x59'},{'\xe3','\x5b'},{'\xfa','\xd6'},{'\xe3','\x56'},{'\xe3','\x4f'}, + {'\xba','\xe3'},{'\xfa','\xd7'},{'\xfa','\xd8'},{'\xbd','\x69'},{'\xba','\xde'}, + {'\xfa','\xd9'},{'\xfc','\xde'},{'\xe3','\x5c'},{'\x00','\x00'},{'\x8f','\x5a'}, + {'\xfa','\xda'},{'\x90','\x59'},{'\x8d','\x71'},{'\x8a','\xe7'},{'\x8a','\xe5'}, + {'\xe6','\xd9'},{'\xbd','\x62'},{'\x00','\x00'},{'\xe6','\xdb'},{'\x00','\x00'}, + {'\xbd','\x63'},{'\x96','\x7c'},{'\x00','\x00'},{'\xbd','\x65'},{'\xe6','\xde'}, + {'\x00','\x00'},{'\xe6','\xd6'},{'\xba','\xe6'},{'\xe6','\xdc'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xe6','\xd8'},{'\x00','\x00'}, + {'\xb8','\x60'},{'\xbd','\x68'},{'\x00','\x00'},{'\x00','\x00'},{'\xbd','\x64'}, + {'\x00','\x00'},{'\xbd','\x66'},{'\xbd','\x67'},{'\x00','\x00'},{'\xbf','\x76'}, + {'\xe6','\xdd'},{'\xe6','\xd7'},{'\xbd','\x6a'},{'\x00','\x00'},{'\xe6','\xda'}, + {'\xfc','\xdf'},{'\x96','\xd0'},{'\x8a','\xe8'},{'\x00','\x00'},{'\x8a','\x40'}, + {'\xea','\xc0'},{'\xea','\xbb'},{'\x00','\x00'},{'\x00','\x00'},{'\xea','\xc5'}, + {'\xbf','\x74'},{'\xea','\xbd'},{'\xbf','\x78'},{'\xea','\xc3'},{'\xea','\xba'}, + {'\xea','\xb7'},{'\xea','\xc6'},{'\xc1','\x51'},{'\xbf','\x79'},{'\xea','\xc2'}, + {'\xea','\xb8'},{'\xbf','\x77'},{'\xea','\xbc'},{'\xbf','\x7b'},{'\xea','\xb9'}, + {'\xea','\xbe'},{'\xbf','\x7a'},{'\xea','\xc1'},{'\xea','\xc4'},{'\x96','\xd1'}, + {'\x82','\xa1'},{'\x8c','\x46'},{'\x00','\x00'},{'\xed','\xcb'},{'\xed','\xcc'}, + {'\xed','\xbc'},{'\xed','\xc3'},{'\xed','\xc1'},{'\x00','\x00'},{'\xfa','\xdb'}, + {'\xc1','\x4f'},{'\xed','\xc8'},{'\xea','\xbf'},{'\x96','\xd2'},{'\xed','\xbf'}, + {'\xfc','\xe1'},{'\xed','\xc9'},{'\xc1','\x4e'},{'\xed','\xbe'},{'\xed','\xbd'}, + {'\xed','\xc7'},{'\xed','\xc4'},{'\xed','\xc6'},{'\x00','\x00'},{'\xed','\xba'}, + {'\xed','\xca'},{'\xc1','\x4c'},{'\x00','\x00'},{'\xed','\xc5'},{'\xed','\xce'}, + {'\xed','\xc2'},{'\xc1','\x50'},{'\xc1','\x4d'},{'\xed','\xc0'},{'\xed','\xbb'}, + {'\xed','\xcd'},{'\xbf','\x75'},{'\xfa','\xdc'},{'\x94','\xbc'},{'\xfa','\xdd'}, + {'\x96','\xd3'},{'\x90','\x77'},{'\x94','\xbd'},{'\x00','\x00'},{'\xf0','\x63'}, + {'\x00','\x00'},{'\x96','\xd4'},{'\xf0','\x61'},{'\xf0','\x67'},{'\xc2','\xb0'}, + {'\xf0','\x65'},{'\xf0','\x64'},{'\xc2','\xb2'},{'\xf0','\x6a'},{'\xc2','\xb1'}, + {'\x00','\x00'},{'\xf0','\x6b'},{'\xf0','\x68'},{'\xc2','\xae'},{'\xf0','\x69'}, + {'\xf0','\x62'},{'\xc2','\xaf'},{'\xc2','\xad'},{'\xf2','\xab'},{'\xf0','\x66'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xf0','\x6c'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xf2','\xa8'},{'\x00','\x00'},{'\x96','\xd5'},{'\x00','\x00'},{'\xc3','\xb2'}, + {'\xc3','\xb0'},{'\xf2','\xaa'},{'\x00','\x00'},{'\xf2','\xac'},{'\xf2','\xa9'}, + {'\xc3','\xb1'},{'\xc3','\xae'},{'\xc3','\xaf'},{'\xc3','\xb3'},{'\x8c','\xd8'}, + {'\xfc','\xe2'},{'\xc4','\x78'},{'\x96','\xd6'},{'\xf4','\xaa'},{'\x00','\x00'}, + {'\xf4','\xa9'},{'\xf4','\xa7'},{'\xf4','\xa6'},{'\xf4','\xa8'},{'\x00','\x00'}, + {'\xc4','\x77'},{'\xc4','\x79'},{'\x00','\x00'},{'\xfa','\xde'},{'\xc4','\xf0'}, + {'\xfc','\xe3'},{'\x00','\x00'},{'\xf5','\xe5'},{'\xf5','\xe4'},{'\x00','\x00'}, + {'\xfa','\xdf'},{'\xf6','\xfa'},{'\xfa','\xe0'},{'\xf6','\xfc'},{'\xf6','\xfe'}, + {'\xf6','\xfd'},{'\xf6','\xfb'},{'\xfc','\xe4'},{'\x00','\x00'},{'\xc5','\xa3'}, + {'\xc5','\xa2'},{'\x00','\x00'},{'\x00','\x00'},{'\xc5','\xd3'},{'\xc5','\xd2'}, + {'\xc5','\xd4'},{'\xf7','\xed'},{'\xf7','\xec'},{'\x00','\x00'},{'\xf8','\xfb'}, + {'\xf8','\xb8'},{'\xf8','\xfc'},{'\xc6','\x58'},{'\x96','\xd7'},{'\xc6','\x59'}, + {'\xf9','\x6d'},{'\xfc','\xe5'},{'\x00','\x00'},{'\xc6','\x7e'},{'\xa6','\xcc'}, + {'\x90','\x5a'},{'\xcd','\xa8'},{'\x00','\x00'},{'\x00','\x00'},{'\xd0','\x45'}, + {'\xd0','\x46'},{'\xd0','\x44'},{'\x8b','\xdd'},{'\x83','\x5e'},{'\xac','\xf3'}, + {'\xfc','\xe6'},{'\xd0','\x47'},{'\xd0','\x48'},{'\xd0','\x49'},{'\x94','\x43'}, + {'\xfc','\xe8'},{'\xd3','\x49'},{'\xd3','\x4f'},{'\xfc','\xe7'},{'\x00','\x00'}, + {'\xd3','\x4d'},{'\xaf','\xbb'},{'\xd3','\x4b'},{'\x92','\xf7'},{'\xd3','\x4c'}, + {'\xd3','\x4e'},{'\x96','\xd8'},{'\x00','\x00'},{'\x94','\xbe'},{'\xd3','\x4a'}, + {'\xb2','\xc9'},{'\x00','\x00'},{'\xd6','\xde'},{'\xb2','\xcb'},{'\xd6','\xe0'}, + {'\xb2','\xca'},{'\xd6','\xdf'},{'\x00','\x00'},{'\x00','\x00'},{'\x92','\xe0'}, + {'\x90','\x7b'},{'\x90','\x43'},{'\xda','\xe8'},{'\xb5','\xaf'},{'\x00','\x00'}, + {'\xda','\xea'},{'\xda','\xe7'},{'\xd6','\xe1'},{'\x85','\xed'},{'\xb5','\xb0'}, + {'\xfe','\x63'},{'\xf9','\xdb'},{'\xda','\xe9'},{'\x00','\x00'},{'\x8a','\x41'}, + {'\xfa','\xe1'},{'\xfc','\xe9'},{'\x94','\xbf'},{'\x8a','\xea'},{'\xdf','\x56'}, + {'\x00','\x00'},{'\xb8','\x64'},{'\xdf','\x54'},{'\xb8','\x65'},{'\xdf','\x55'}, + {'\xb8','\x66'},{'\x00','\x00'},{'\x00','\x00'},{'\x96','\xd9'},{'\xba','\xe9'}, + {'\xe3','\x61'},{'\xe3','\x5e'},{'\xe3','\x60'},{'\xba','\xea'},{'\xba','\xeb'}, + {'\xe3','\x5f'},{'\x94','\xc0'},{'\x8a','\x43'},{'\xfc','\xeb'},{'\x96','\xda'}, + {'\x00','\x00'},{'\xe6','\xdf'},{'\x00','\x00'},{'\xfc','\xea'},{'\xe6','\xe0'}, + {'\x95','\xb2'},{'\xbd','\x6b'},{'\xe6','\xe2'},{'\xe6','\xe1'},{'\xa0','\x54'}, + {'\xa2','\x61'},{'\x00','\x00'},{'\xea','\xca'},{'\xea','\xcb'},{'\xea','\xc7'}, + {'\xfb','\x7e'},{'\xea','\xc8'},{'\xbf','\x7c'},{'\xbf','\x7d'},{'\xea','\xc9'}, + {'\x94','\xc1'},{'\xc1','\x57'},{'\xfc','\xed'},{'\x00','\x00'},{'\xc1','\x53'}, + {'\xc1','\x58'},{'\xc1','\x54'},{'\xc1','\x56'},{'\xc1','\x52'},{'\x00','\x00'}, + {'\xc1','\x55'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x96','\xdb'}, + {'\xc2','\xb3'},{'\xed','\xcf'},{'\x00','\x00'},{'\xf2','\xae'},{'\x00','\x00'}, + {'\xf2','\xad'},{'\x96','\xdc'},{'\xf4','\xab'},{'\xc4','\x7a'},{'\xc4','\x7b'}, + {'\xf7','\x41'},{'\xf5','\xe6'},{'\x96','\xdd'},{'\xf7','\x40'},{'\x96','\xde'}, + {'\xf8','\xfd'},{'\xf9','\xa4'},{'\xa6','\xcd'},{'\x96','\xdf'},{'\xfa','\xe2'}, + {'\xa8','\x74'},{'\x96','\xe1'},{'\xcd','\xa9'},{'\xaa','\xc8'},{'\x00','\x00'}, + {'\xac','\xf6'},{'\xd0','\x4c'},{'\xac','\xf4'},{'\xd0','\x4a'},{'\xac','\xf9'}, + {'\xac','\xf5'},{'\xac','\xfa'},{'\xac','\xf8'},{'\xd0','\x4b'},{'\xac','\xf7'}, + {'\xaf','\xbf'},{'\xaf','\xbe'},{'\xd3','\x5a'},{'\xaf','\xc7'},{'\xd3','\x53'}, + {'\xd3','\x59'},{'\xaf','\xc3'},{'\xd3','\x52'},{'\xd3','\x58'},{'\xd3','\x56'}, + {'\xaf','\xc2'},{'\xaf','\xc4'},{'\xd3','\x55'},{'\xaf','\xbd'},{'\xd3','\x54'}, + {'\xaf','\xc8'},{'\xaf','\xc5'},{'\xaf','\xc9'},{'\xaf','\xc6'},{'\xd3','\x51'}, + {'\xd3','\x50'},{'\xd3','\x57'},{'\xaf','\xc0'},{'\xaf','\xbc'},{'\xaf','\xc1'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x95','\xe2'},{'\x00','\x00'},{'\x86','\xfa'}, + {'\xd6','\xf0'},{'\xd6','\xe9'},{'\x00','\x00'},{'\xb5','\xb5'},{'\xd6','\xe8'}, + {'\x00','\x00'},{'\xb2','\xcf'},{'\xb2','\xd6'},{'\xb2','\xd3'},{'\xb2','\xd9'}, + {'\xb2','\xd8'},{'\xb2','\xd4'},{'\x00','\x00'},{'\xd6','\xe2'},{'\xd6','\xe5'}, + {'\x00','\x00'},{'\xd6','\xe4'},{'\xb2','\xd0'},{'\xd6','\xe6'},{'\xd6','\xef'}, + {'\xb2','\xd1'},{'\xd6','\xe3'},{'\xd6','\xec'},{'\xd6','\xed'},{'\xb2','\xd2'}, + {'\xd6','\xea'},{'\xb2','\xd7'},{'\xb2','\xcd'},{'\xb2','\xd5'},{'\xd6','\xe7'}, + {'\xb2','\xcc'},{'\xd6','\xeb'},{'\xfa','\xe3'},{'\x00','\x00'},{'\xd6','\xee'}, + {'\xfa','\xe4'},{'\x92','\xab'},{'\xfc','\xef'},{'\xda','\xfb'},{'\xda','\xf2'}, + {'\xb5','\xb2'},{'\xda','\xf9'},{'\xda','\xf6'},{'\xda','\xee'},{'\xda','\xf7'}, + {'\xb5','\xb4'},{'\xda','\xef'},{'\x00','\x00'},{'\xda','\xeb'},{'\x00','\x00'}, + {'\xfc','\xf0'},{'\xb8','\x6c'},{'\xda','\xf4'},{'\xfe','\x60'},{'\xb5','\xb1'}, + {'\xda','\xfa'},{'\x00','\x00'},{'\xb5','\xb8'},{'\xb5','\xba'},{'\xda','\xed'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb5','\xb9'},{'\xda','\xf0'},{'\xb5','\xb3'}, + {'\xda','\xf8'},{'\xda','\xf1'},{'\xda','\xf5'},{'\x00','\x00'},{'\xda','\xf3'}, + {'\xb5','\xb6'},{'\xda','\xec'},{'\xb5','\xbb'},{'\xb2','\xce'},{'\xb5','\xb7'}, + {'\xb5','\xbc'},{'\x00','\x00'},{'\x92','\x5b'},{'\x93','\x46'},{'\xfa','\xe5'}, + {'\x00','\x00'},{'\xb8','\x68'},{'\xdf','\x5d'},{'\xdf','\x5f'},{'\xdf','\x61'}, + {'\xdf','\x65'},{'\x00','\x00'},{'\xdf','\x5b'},{'\xdf','\x59'},{'\xb8','\x6a'}, + {'\x00','\x00'},{'\xdf','\x60'},{'\xdf','\x64'},{'\xdf','\x5c'},{'\xdf','\x58'}, + {'\x00','\x00'},{'\xdf','\x57'},{'\x95','\x68'},{'\x00','\x00'},{'\x96','\xe2'}, + {'\xdf','\x62'},{'\xdf','\x5a'},{'\xdf','\x5e'},{'\xb8','\x6b'},{'\x00','\x00'}, + {'\xb8','\x69'},{'\xdf','\x66'},{'\xb8','\x67'},{'\xdf','\x63'},{'\x9d','\xb9'}, + {'\xe3','\x72'},{'\x96','\xe3'},{'\x00','\x00'},{'\x92','\xae'},{'\x93','\x64'}, + {'\x94','\xc2'},{'\xba','\xee'},{'\xe3','\x6a'},{'\xbd','\x78'},{'\xe3','\x74'}, + {'\xba','\xf1'},{'\xe3','\x78'},{'\xba','\xf7'},{'\xe3','\x65'},{'\x96','\xe4'}, + {'\x00','\x00'},{'\xe3','\x75'},{'\xe3','\x62'},{'\x96','\xe5'},{'\xe3','\x77'}, + {'\xe3','\x66'},{'\x95','\x56'},{'\xba','\xfe'},{'\xba','\xfb'},{'\xe3','\x76'}, + {'\xe3','\x70'},{'\xba','\xed'},{'\xba','\xf5'},{'\xba','\xf4'},{'\x95','\x6a'}, + {'\xba','\xf3'},{'\xba','\xf9'},{'\x00','\x00'},{'\xe3','\x63'},{'\xba','\xfa'}, + {'\xe3','\x71'},{'\xba','\xf6'},{'\xba','\xec'},{'\xe3','\x73'},{'\xba','\xef'}, + {'\xba','\xf0'},{'\xba','\xf8'},{'\xe3','\x68'},{'\xe3','\x67'},{'\xe3','\x64'}, + {'\x00','\x00'},{'\xe3','\x6c'},{'\xe3','\x69'},{'\xe3','\x6d'},{'\xba','\xfd'}, + {'\x00','\x00'},{'\xe3','\x79'},{'\xba','\xf2'},{'\xe3','\x6e'},{'\xe3','\x6f'}, + {'\x96','\xe6'},{'\xe3','\x6b'},{'\x93','\x5c'},{'\x96','\xe7'},{'\x93','\xe7'}, + {'\xba','\xfc'},{'\x96','\xe8'},{'\xfa','\xe6'},{'\xfa','\xe7'},{'\xfa','\xe8'}, + {'\xe6','\xe7'},{'\xbd','\x70'},{'\xbd','\x79'},{'\xbd','\x75'},{'\xe6','\xe4'}, + {'\x95','\xc3'},{'\xbd','\x72'},{'\xbd','\x76'},{'\xe6','\xf0'},{'\xbd','\x6c'}, + {'\xe6','\xe8'},{'\x00','\x00'},{'\xbd','\x74'},{'\xfa','\xe9'},{'\x96','\xe9'}, + {'\xe6','\xeb'},{'\xe6','\xe6'},{'\xbd','\x73'},{'\xbd','\x77'},{'\xe6','\xe5'}, + {'\x00','\x00'},{'\xbd','\x71'},{'\x00','\x00'},{'\xe6','\xef'},{'\xbd','\x6e'}, + {'\xe6','\xee'},{'\xe6','\xed'},{'\xbd','\x7a'},{'\xe5','\x72'},{'\xbd','\x6d'}, + {'\xfc','\xf1'},{'\xe6','\xec'},{'\xe6','\xe3'},{'\x00','\x00'},{'\xbd','\x7b'}, + {'\xe6','\xea'},{'\xbd','\x6f'},{'\x00','\x00'},{'\x96','\xea'},{'\x9f','\x7e'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x92','\x4d'},{'\x00','\x00'},{'\xe6','\xe9'}, + {'\x92','\xed'},{'\x94','\xc3'},{'\x00','\x00'},{'\x9f','\xa1'},{'\xbf','\xa2'}, + {'\xbf','\xa7'},{'\xbf','\x7e'},{'\xea','\xd8'},{'\xea','\xcf'},{'\xea','\xdb'}, + {'\xea','\xd3'},{'\xea','\xd9'},{'\xbf','\xa8'},{'\xbf','\xa1'},{'\xea','\xcc'}, + {'\xea','\xd2'},{'\xea','\xdc'},{'\xea','\xd5'},{'\xea','\xda'},{'\xea','\xce'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xea','\xd6'},{'\xbf','\xa3'},{'\xea','\xd4'}, + {'\xbf','\xa6'},{'\xbf','\xa5'},{'\xea','\xd0'},{'\xea','\xd1'},{'\xea','\xcd'}, + {'\xea','\xd7'},{'\xbf','\xa4'},{'\xea','\xde'},{'\xea','\xdd'},{'\x92','\xdf'}, + {'\xfc','\xf2'},{'\x00','\x00'},{'\xed','\xda'},{'\xed','\xd6'},{'\xc1','\x5f'}, + {'\x00','\x00'},{'\xed','\xd0'},{'\xc1','\x59'},{'\xc1','\x69'},{'\xed','\xdc'}, + {'\xc1','\x61'},{'\xc1','\x5d'},{'\xed','\xd3'},{'\xc1','\x64'},{'\xc1','\x67'}, + {'\xed','\xde'},{'\xc1','\x5c'},{'\xed','\xd5'},{'\xc1','\x65'},{'\xed','\xe0'}, + {'\xed','\xdd'},{'\xed','\xd1'},{'\xc1','\x60'},{'\xc1','\x5a'},{'\xc1','\x68'}, + {'\xed','\xd8'},{'\xc1','\x63'},{'\xed','\xd2'},{'\xc1','\x5e'},{'\xed','\xdf'}, + {'\xc1','\x62'},{'\xc1','\x5b'},{'\xed','\xd9'},{'\xc1','\x66'},{'\xed','\xd7'}, + {'\x93','\x4f'},{'\x82','\x5a'},{'\xed','\xdb'},{'\xfa','\xea'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xf0','\x6e'},{'\xf0','\x74'},{'\xc2','\xb9'},{'\xf0','\x77'}, + {'\xc2','\xb4'},{'\xc2','\xb5'},{'\xf0','\x6f'},{'\xf0','\x76'},{'\xf0','\x71'}, + {'\xc2','\xba'},{'\xc2','\xb7'},{'\x9f','\xa2'},{'\xf0','\x6d'},{'\xfa','\xeb'}, + {'\xc2','\xb6'},{'\xf0','\x73'},{'\xf0','\x75'},{'\xc2','\xb8'},{'\xf0','\x72'}, + {'\xf0','\x70'},{'\x00','\x00'},{'\x9f','\xa3'},{'\x8a','\x50'},{'\x94','\xc4'}, + {'\xf2','\xb8'},{'\xc3','\xb7'},{'\xc3','\xb8'},{'\xc3','\xb4'},{'\x9f','\xa4'}, + {'\xc3','\xb5'},{'\x8c','\xe8'},{'\xf2','\xb4'},{'\xf2','\xb2'},{'\x00','\x00'}, + {'\xf2','\xb6'},{'\xc3','\xba'},{'\xf2','\xb7'},{'\xf2','\xb0'},{'\xf2','\xaf'}, + {'\xf2','\xb3'},{'\xf2','\xb1'},{'\xc3','\xb6'},{'\xf2','\xb5'},{'\xf4','\xac'}, + {'\xc4','\x7e'},{'\xc4','\x7d'},{'\xf4','\xad'},{'\xfa','\xec'},{'\xf4','\xaf'}, + {'\xf4','\xae'},{'\xc4','\xa1'},{'\x94','\xc5'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xf5','\xeb'},{'\xf5','\xe8'},{'\xf5','\xe9'},{'\xfa','\xed'},{'\xf5','\xe7'}, + {'\xf5','\xea'},{'\xc4','\xf2'},{'\xf5','\xec'},{'\xfa','\xee'},{'\xc4','\xf1'}, + {'\x94','\xc6'},{'\xf7','\x42'},{'\xfa','\xef'},{'\xc5','\xd5'},{'\xc5','\xd7'}, + {'\xf7','\xee'},{'\xc5','\xd6'},{'\xf8','\xb9'},{'\xf9','\x40'},{'\xf9','\x42'}, + {'\xf8','\xfe'},{'\xf9','\x41'},{'\xc6','\x6c'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9c','\xeb'},{'\x83','\x5f'},{'\x83','\x76'},{'\x83','\x71'},{'\x83','\x70'}, + {'\x8a','\x4e'},{'\x83','\x74'},{'\x83','\x75'},{'\x83','\xcb'},{'\x8d','\xbe'}, + {'\x90','\x44'},{'\x83','\x72'},{'\x83','\x73'},{'\x87','\xfe'},{'\x83','\xcc'}, + {'\x00','\x00'},{'\x83','\xc8'},{'\x83','\xca'},{'\x83','\xc6'},{'\x86','\xfc'}, + {'\x83','\xcd'},{'\x00','\x00'},{'\x8a','\x4c'},{'\x87','\x41'},{'\x83','\xcf'}, + {'\x83','\xce'},{'\x83','\xc7'},{'\x83','\xc5'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x83','\xc9'},{'\x8d','\xc5'},{'\x88','\x45'},{'\x8d','\xd3'},{'\x84','\x71'}, + {'\x84','\x72'},{'\x87','\xfd'},{'\x84','\x6f'},{'\x84','\x6e'},{'\x84','\x6d'}, + {'\x8a','\xeb'},{'\x84','\x70'},{'\x89','\x53'},{'\x84','\x68'},{'\x84','\x6b'}, + {'\x84','\x6c'},{'\x84','\x6a'},{'\x8b','\xb1'},{'\x85','\xee'},{'\x8d','\xd4'}, + {'\x85','\xf0'},{'\x85','\x44'},{'\x85','\x43'},{'\xfa','\xf0'},{'\x8a','\xed'}, + {'\x85','\x4a'},{'\x8d','\xe4'},{'\x8b','\xb3'},{'\x85','\x48'},{'\x85','\x49'}, + {'\x85','\x4b'},{'\x85','\x47'},{'\x85','\x45'},{'\x85','\x42'},{'\x84','\x69'}, + {'\x8e','\x4a'},{'\x8e','\x4b'},{'\x85','\xef'},{'\x8a','\xef'},{'\x00','\x00'}, + {'\x85','\xf1'},{'\x85','\xf2'},{'\x8c','\x49'},{'\x8e','\x49'},{'\x8a','\x45'}, + {'\x87','\x43'},{'\x86','\xf8'},{'\x00','\x00'},{'\x8c','\xa2'},{'\x86','\xfd'}, + {'\x8e','\x7b'},{'\x86','\xf7'},{'\xfa','\xf1'},{'\x8e','\x7a'},{'\x8b','\xb2'}, + {'\x87','\x42'},{'\x87','\x40'},{'\x87','\x45'},{'\x8a','\x49'},{'\x86','\xfe'}, + {'\x00','\x00'},{'\x8e','\x7c'},{'\x8e','\x79'},{'\x86','\xf6'},{'\x86','\xf4'}, + {'\x86','\xf5'},{'\x86','\xf9'},{'\x86','\xfb'},{'\x87','\x44'},{'\x88','\x49'}, + {'\x8e','\xc2'},{'\x88','\x40'},{'\x88','\x41'},{'\x8d','\xa3'},{'\x88','\x4b'}, + {'\x88','\x4a'},{'\x88','\x42'},{'\x00','\x00'},{'\x8f','\x79'},{'\x8e','\xc4'}, + {'\x88','\x48'},{'\x88','\x46'},{'\x8e','\xc5'},{'\x00','\x00'},{'\x8e','\xc6'}, + {'\xfa','\xf2'},{'\x88','\x47'},{'\x87','\xfc'},{'\x8a','\x47'},{'\x88','\x43'}, + {'\x8e','\xc3'},{'\x88','\x44'},{'\x89','\x52'},{'\x89','\x4e'},{'\x8e','\xf0'}, + {'\x89','\x51'},{'\x8a','\x4a'},{'\x00','\x00'},{'\x89','\x50'},{'\x8c','\xa1'}, + {'\x8f','\x5d'},{'\x89','\x4b'},{'\x89','\x4c'},{'\x8c','\x48'},{'\x8a','\x4f'}, + {'\x8a','\x51'},{'\x8a','\x48'},{'\x8c','\xfb'},{'\x8a','\x44'},{'\x8a','\x46'}, + {'\x8a','\x4d'},{'\x90','\x45'},{'\x8a','\xee'},{'\x8a','\xec'},{'\x8a','\xf0'}, + {'\xfa','\xf3'},{'\x8f','\xde'},{'\x8f','\xbf'},{'\x8f','\xc0'},{'\x8b','\xb5'}, + {'\x90','\x7c'},{'\xa6','\xce'},{'\x9f','\xa5'},{'\xac','\xfb'},{'\xd2','\x6f'}, + {'\xaf','\xca'},{'\x00','\x00'},{'\x00','\x00'},{'\xb2','\xda'},{'\xda','\xfc'}, + {'\xda','\xfd'},{'\x9f','\xa6'},{'\x9f','\xa7'},{'\x8c','\x4a'},{'\xea','\xdf'}, + {'\xc1','\x6a'},{'\xed','\xe1'},{'\x00','\x00'},{'\x95','\x74'},{'\xc2','\xbb'}, + {'\x9f','\xa8'},{'\xf2','\xba'},{'\xf2','\xb9'},{'\xc4','\xa2'},{'\xf5','\xed'}, + {'\xfb','\xaa'},{'\xf7','\x43'},{'\xc5','\xf8'},{'\xca','\x49'},{'\x9f','\xa9'}, + {'\x9d','\x75'},{'\xaa','\xc9'},{'\xa8','\x75'},{'\x00','\x00'},{'\x8b','\xb4'}, + {'\xd0','\x4d'},{'\x00','\x00'},{'\x87','\x46'},{'\xd3','\x60'},{'\xd3','\x5b'}, + {'\xd3','\x5f'},{'\xd3','\x5d'},{'\xaf','\xcb'},{'\xd3','\x5e'},{'\xd3','\x5c'}, + {'\x88','\x4d'},{'\xd6','\xf1'},{'\x00','\x00'},{'\xda','\xfe'},{'\xdb','\x40'}, + {'\xdf','\x69'},{'\xdf','\x6a'},{'\xb8','\x6e'},{'\xb8','\x6f'},{'\xdf','\x68'}, + {'\xdf','\x6b'},{'\xdf','\x67'},{'\xb8','\x6d'},{'\x00','\x00'},{'\xbb','\x40'}, + {'\xfa','\xf4'},{'\xb8','\x70'},{'\xe3','\x7a'},{'\x8f','\xc1'},{'\xbd','\x7c'}, + {'\xe6','\xf1'},{'\xbd','\x7d'},{'\x95','\x64'},{'\xbf','\xa9'},{'\xea','\xe2'}, + {'\xea','\xe0'},{'\xea','\xe1'},{'\xed','\xe4'},{'\xed','\xe3'},{'\xed','\xe2'}, + {'\x00','\x00'},{'\x8d','\x56'},{'\xfa','\xf5'},{'\xf2','\xbb'},{'\x00','\x00'}, + {'\xc3','\xb9'},{'\xf2','\xbc'},{'\xf7','\x44'},{'\xc5','\xf9'},{'\xf8','\xba'}, + {'\xa6','\xcf'},{'\xaa','\xcb'},{'\xaa','\xca'},{'\xd0','\x4f'},{'\xac','\xfc'}, + {'\x9f','\xaa'},{'\x00','\x00'},{'\xd0','\x4e'},{'\xd3','\x62'},{'\x9f','\xab'}, + {'\xaf','\xcc'},{'\xd6','\xf2'},{'\xd3','\x61'},{'\x95','\xe0'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xb2','\xdc'},{'\xd6','\xf5'},{'\xd6','\xf3'},{'\xd6','\xf4'}, + {'\xb2','\xdb'},{'\x8e','\x4c'},{'\xdb','\x42'},{'\xdb','\x43'},{'\xdb','\x41'}, + {'\x95','\x55'},{'\xb8','\x73'},{'\xdf','\x6d'},{'\xdf','\x6c'},{'\xdf','\x6e'}, + {'\xb8','\x72'},{'\xb8','\x71'},{'\x00','\x00'},{'\x00','\x00'},{'\xe6','\xf2'}, + {'\xe6','\xf4'},{'\xfa','\xf6'},{'\xbd','\x7e'},{'\xe6','\xf3'},{'\xea','\xe3'}, + {'\xbf','\xaa'},{'\xf0','\x79'},{'\x9f','\xac'},{'\xf0','\x78'},{'\xc3','\xbb'}, + {'\xf2','\xbd'},{'\xc3','\xbd'},{'\xc3','\xbc'},{'\xf4','\xb0'},{'\xf5','\xee'}, + {'\xc4','\xf3'},{'\xa6','\xd0'},{'\xd0','\x50'},{'\xac','\xfd'},{'\xd3','\x65'}, + {'\xaf','\xce'},{'\xd3','\x64'},{'\xd3','\x63'},{'\x00','\x00'},{'\xaf','\xcd'}, + {'\xfa','\xf7'},{'\xd6','\xfb'},{'\x00','\x00'},{'\xd6','\xfd'},{'\xd6','\xf6'}, + {'\xd6','\xf7'},{'\xb2','\xdd'},{'\xd6','\xf8'},{'\xb2','\xde'},{'\xd6','\xfc'}, + {'\xd6','\xf9'},{'\xd6','\xfa'},{'\xb2','\xdf'},{'\x00','\x00'},{'\xb5','\xbe'}, + {'\xb5','\xbf'},{'\x00','\x00'},{'\xdb','\x44'},{'\x8a','\xf1'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xdf','\x6f'},{'\xdf','\x70'},{'\x9f','\xad'},{'\xe3','\x7e'}, + {'\xbb','\x43'},{'\xbb','\x41'},{'\xbb','\x42'},{'\xe3','\x7b'},{'\xe3','\x7c'}, + {'\x00','\x00'},{'\xe3','\x7d'},{'\xe6','\xf9'},{'\x9f','\xae'},{'\xe6','\xfa'}, + {'\xbd','\xa1'},{'\xe6','\xf7'},{'\xe6','\xf6'},{'\xe6','\xf8'},{'\xe6','\xf5'}, + {'\xbf','\xad'},{'\xea','\xe4'},{'\xbf','\xab'},{'\xbf','\xac'},{'\xed','\xe6'}, + {'\xc1','\x6b'},{'\xed','\xe5'},{'\xef','\xa8'},{'\x00','\x00'},{'\xf0','\x7a'}, + {'\xf0','\x7b'},{'\xc2','\xbc'},{'\x9f','\xaf'},{'\xc2','\xbd'},{'\xc1','\x6c'}, + {'\xf2','\xbe'},{'\xf2','\xbf'},{'\xf4','\xb1'},{'\xc4','\xa3'},{'\xa6','\xd1'}, + {'\x9f','\xb0'},{'\xa6','\xd2'},{'\xac','\xfe'},{'\xaa','\xcc'},{'\xaf','\xcf'}, + {'\xd0','\x51'},{'\x9f','\xb1'},{'\x00','\x00'},{'\x00','\x00'},{'\xb5','\xc0'}, + {'\xa6','\xd3'},{'\xad','\x41'},{'\xd0','\x52'},{'\xd0','\x53'},{'\xad','\x40'}, + {'\xad','\x42'},{'\xa6','\xd4'},{'\x00','\x00'},{'\xd0','\x54'},{'\xaf','\xd1'}, + {'\xd3','\x66'},{'\xaf','\xd3'},{'\xaf','\xd0'},{'\xaf','\xd2'},{'\x00','\x00'}, + {'\xd7','\x41'},{'\xb2','\xe0'},{'\xfc','\xf6'},{'\xd7','\x40'},{'\xd6','\xfe'}, + {'\xfa','\xf8'},{'\xdf','\x71'},{'\xfa','\xf9'},{'\x00','\x00'},{'\xe3','\xa1'}, + {'\xfa','\xfa'},{'\xbd','\xa2'},{'\x8f','\x5e'},{'\xbf','\xae'},{'\xea','\xe6'}, + {'\xea','\xe5'},{'\x00','\x00'},{'\xed','\xe7'},{'\x00','\x00'},{'\x9f','\xb2'}, + {'\x9f','\xb3'},{'\xf5','\xef'},{'\xfa','\xfb'},{'\x00','\x00'},{'\xa6','\xd5'}, + {'\xcb','\x73'},{'\xcd','\xaa'},{'\xad','\x43'},{'\xd0','\x55'},{'\x8a','\x55'}, + {'\xd3','\x68'},{'\x00','\x00'},{'\x95','\x5c'},{'\x9f','\xb4'},{'\xaf','\xd4'}, + {'\xd3','\x67'},{'\xaf','\xd5'},{'\x00','\x00'},{'\x00','\x00'},{'\x8a','\xf3'}, + {'\xd7','\x43'},{'\x00','\x00'},{'\x00','\x00'},{'\xb2','\xe2'},{'\xd7','\x42'}, + {'\xd7','\x44'},{'\x00','\x00'},{'\xb2','\xe1'},{'\x8c','\xd9'},{'\x8a','\xf2'}, + {'\x8f','\xdf'},{'\x00','\x00'},{'\xdb','\x46'},{'\xdb','\x47'},{'\xdb','\x45'}, + {'\xb5','\xc1'},{'\x00','\x00'},{'\x8a','\x54'},{'\x00','\x00'},{'\xb8','\x74'}, + {'\x00','\x00'},{'\xb8','\x75'},{'\x00','\x00'},{'\xbb','\x45'},{'\xfc','\xfa'}, + {'\xe3','\xa3'},{'\xe3','\xa2'},{'\xbb','\x44'},{'\xfa','\xfc'},{'\x00','\x00'}, + {'\x82','\x6b'},{'\xfc','\xf7'},{'\xfc','\xf8'},{'\xe6','\xfb'},{'\x00','\x00'}, + {'\xfc','\xf9'},{'\xe6','\xfc'},{'\xfa','\xfd'},{'\x8f','\x7a'},{'\x8a','\x53'}, + {'\x00','\x00'},{'\xea','\xe7'},{'\x00','\x00'},{'\x00','\x00'},{'\xc1','\x70'}, + {'\xc1','\x6f'},{'\xc1','\x6d'},{'\xc1','\x6e'},{'\xc1','\x71'},{'\x93','\x77'}, + {'\xf0','\x7c'},{'\xc2','\xbf'},{'\xc2','\xbe'},{'\xf2','\xc0'},{'\xf4','\xb2'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc5','\xa5'},{'\xc5','\xa4'}, + {'\xa6','\xd6'},{'\x91','\xd5'},{'\x00','\x00'},{'\xd1','\xfb'},{'\x85','\x4c'}, + {'\xb8','\x77'},{'\xb5','\xc2'},{'\xb8','\x76'},{'\xbb','\x46'},{'\x00','\x00'}, + {'\xa6','\xd7'},{'\xc9','\xa9'},{'\xa6','\xd8'},{'\xa6','\xd9'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xcd','\xab'},{'\xcb','\x76'},{'\x00','\x00'},{'\xcb','\x77'}, + {'\xa8','\x77'},{'\x00','\x00'},{'\xcb','\x74'},{'\xa8','\x76'},{'\x00','\x00'}, + {'\xa8','\x79'},{'\xcb','\x75'},{'\xa8','\x7b'},{'\xa8','\x7a'},{'\xcb','\x78'}, + {'\xa8','\x78'},{'\x00','\x00'},{'\x96','\xaf'},{'\x85','\xf6'},{'\xaa','\xd1'}, + {'\xaa','\xcf'},{'\xcd','\xad'},{'\x88','\x4f'},{'\xaa','\xce'},{'\xfc','\xfb'}, + {'\x9f','\xb5'},{'\x00','\x00'},{'\xaa','\xd3'},{'\xaa','\xd5'},{'\xaa','\xd2'}, + {'\xfa','\xfe'},{'\xcd','\xb0'},{'\xcd','\xac'},{'\xaa','\xd6'},{'\x00','\x00'}, + {'\xaa','\xd0'},{'\xa8','\x7c'},{'\x00','\x00'},{'\xaa','\xd4'},{'\xcd','\xaf'}, + {'\xfb','\x4d'},{'\xfb','\x40'},{'\xcd','\xae'},{'\x00','\x00'},{'\xaa','\xcd'}, + {'\x00','\x00'},{'\x96','\xcb'},{'\x96','\xa6'},{'\x85','\x4d'},{'\x85','\xf8'}, + {'\x85','\x4e'},{'\x83','\xd0'},{'\xd0','\x5b'},{'\xad','\x47'},{'\xad','\x48'}, + {'\xd0','\x5d'},{'\x8a','\x57'},{'\xd0','\x57'},{'\xd0','\x5a'},{'\xd0','\x63'}, + {'\xd0','\x61'},{'\x00','\x00'},{'\xad','\x49'},{'\xd0','\x67'},{'\xad','\x4c'}, + {'\xd0','\x64'},{'\xd0','\x5c'},{'\xd0','\x59'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xdb','\x49'},{'\xd0','\x62'},{'\xad','\x44'},{'\xd0','\x65'},{'\xd0','\x56'}, + {'\xd0','\x5f'},{'\xad','\x46'},{'\xad','\x4b'},{'\xd0','\x60'},{'\xad','\x4f'}, + {'\xad','\x4d'},{'\x00','\x00'},{'\xd0','\x58'},{'\xad','\x4a'},{'\x00','\x00'}, + {'\xd0','\x5e'},{'\xad','\x4e'},{'\xad','\x45'},{'\xd0','\x66'},{'\x8b','\xf8'}, + {'\xfd','\xfb'},{'\xfd','\xfc'},{'\x8c','\x4b'},{'\x8d','\xd5'},{'\xfd','\xfd'}, + {'\xaf','\xda'},{'\x00','\x00'},{'\xaf','\xe3'},{'\xaf','\xd8'},{'\xaf','\xd6'}, + {'\xd3','\x6a'},{'\xaf','\xde'},{'\xaf','\xdb'},{'\xd3','\x6c'},{'\x88','\x4e'}, + {'\x00','\x00'},{'\xaf','\xdd'},{'\xd3','\x6b'},{'\xd3','\x69'},{'\xd3','\x6e'}, + {'\xaf','\xe2'},{'\xaf','\xe0'},{'\xdb','\x48'},{'\x00','\x00'},{'\xd3','\x6f'}, + {'\xd3','\x6d'},{'\xaf','\xd7'},{'\xfc','\xfc'},{'\x00','\x00'},{'\xaf','\xd9'}, + {'\xaf','\xdc'},{'\xfe','\x48'},{'\xaf','\xdf'},{'\x83','\xd1'},{'\xaf','\xe1'}, + {'\x00','\x00'},{'\x9f','\xb6'},{'\x8a','\x59'},{'\xfd','\xfe'},{'\x8c','\xda'}, + {'\x8a','\xf4'},{'\x85','\xf9'},{'\xfe','\xee'},{'\x8a','\x56'},{'\x90','\x7d'}, + {'\xd7','\x4e'},{'\xb2','\xe4'},{'\x95','\xa8'},{'\xd7','\x45'},{'\xd7','\x47'}, + {'\x85','\xf7'},{'\xd7','\x48'},{'\x00','\x00'},{'\xd7','\x50'},{'\xd7','\x4c'}, + {'\xd7','\x4a'},{'\x00','\x00'},{'\xd7','\x4d'},{'\xd7','\x51'},{'\xb2','\xe5'}, + {'\xb2','\xe9'},{'\xd7','\x46'},{'\x00','\x00'},{'\xd7','\x4f'},{'\x00','\x00'}, + {'\xb2','\xe7'},{'\x9f','\xb7'},{'\xb2','\xe6'},{'\xd7','\x4b'},{'\xd7','\x49'}, + {'\x00','\x00'},{'\xb2','\xe3'},{'\xb2','\xe8'},{'\xfe','\xef'},{'\x96','\xa5'}, + {'\x93','\xb0'},{'\x9f','\xb8'},{'\x00','\x00'},{'\xfe','\xf0'},{'\xa0','\x42'}, + {'\x8a','\x58'},{'\xb5','\xc8'},{'\xdb','\x51'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xdb','\x4f'},{'\xb5','\xca'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x9f','\xb9'},{'\xdb','\x4a'},{'\xdf','\xa1'},{'\x00','\x00'},{'\xb5','\xc9'}, + {'\xdb','\x4e'},{'\x96','\xab'},{'\x00','\x00'},{'\xdb','\x4b'},{'\xb5','\xc5'}, + {'\xb5','\xcb'},{'\xdb','\x50'},{'\xb5','\xc7'},{'\xdb','\x4d'},{'\xbb','\x47'}, + {'\xb5','\xc6'},{'\xdb','\x4c'},{'\xb5','\xcc'},{'\xb5','\xc4'},{'\xb5','\xc3'}, + {'\x9f','\xba'},{'\x00','\x00'},{'\x00','\x00'},{'\x96','\xae'},{'\x96','\xa2'}, + {'\xdf','\x77'},{'\xdf','\x75'},{'\x00','\x00'},{'\xdf','\x7b'},{'\xfe','\xf1'}, + {'\xdf','\x73'},{'\xdf','\xa2'},{'\xdf','\x78'},{'\x00','\x00'},{'\xdf','\x72'}, + {'\xb8','\x7b'},{'\xb8','\xa3'},{'\xdf','\x7d'},{'\x00','\x00'},{'\xdf','\x76'}, + {'\x00','\x00'},{'\xb8','\x7e'},{'\x9d','\xd0'},{'\xfe','\xf2'},{'\xb8','\x7c'}, + {'\xdf','\x7e'},{'\xb8','\x79'},{'\xb8','\x78'},{'\xdf','\x79'},{'\xb8','\x7d'}, + {'\xb5','\xcd'},{'\x00','\x00'},{'\xdf','\x7c'},{'\xdf','\x74'},{'\xb8','\x7a'}, + {'\xb8','\xa1'},{'\xb8','\xa2'},{'\x89','\x54'},{'\x89','\xae'},{'\xfe','\xf3'}, + {'\x8c','\x65'},{'\xbb','\x4c'},{'\xbb','\x48'},{'\x00','\x00'},{'\xbb','\x4d'}, + {'\xe3','\xa6'},{'\x9f','\xbb'},{'\x00','\x00'},{'\xe3','\xa5'},{'\xe3','\xa7'}, + {'\xbb','\x4a'},{'\xe3','\xa4'},{'\xbb','\x4b'},{'\xe3','\xaa'},{'\xe3','\xa9'}, + {'\xe3','\xa8'},{'\x00','\x00'},{'\xbb','\x49'},{'\x00','\x00'},{'\x8a','\xf5'}, + {'\x00','\x00'},{'\xfe','\xf4'},{'\x00','\x00'},{'\xe7','\x41'},{'\x00','\x00'}, + {'\xe7','\x44'},{'\xbd','\xa8'},{'\xe7','\x43'},{'\xbd','\xa7'},{'\xbd','\xa3'}, + {'\xbd','\xa4'},{'\xbd','\xa5'},{'\xe7','\x40'},{'\xe6','\xfe'},{'\xbd','\xa6'}, + {'\x00','\x00'},{'\xe7','\x42'},{'\xe6','\xfd'},{'\x94','\xc7'},{'\x9f','\xbc'}, + {'\xea','\xe9'},{'\xea','\xf3'},{'\xbf','\xb1'},{'\xbf','\xb0'},{'\xfe','\xf5'}, + {'\xea','\xed'},{'\xea','\xef'},{'\x00','\x00'},{'\xea','\xea'},{'\x00','\x00'}, + {'\xea','\xee'},{'\xea','\xe8'},{'\xea','\xf1'},{'\xbf','\xaf'},{'\xea','\xf0'}, + {'\xea','\xec'},{'\xfb','\x6e'},{'\xea','\xf2'},{'\xfe','\xf6'},{'\xea','\xeb'}, + {'\xc1','\x74'},{'\xed','\xe8'},{'\xed','\xee'},{'\xc1','\x78'},{'\xc1','\x7a'}, + {'\xc1','\x77'},{'\xc1','\x76'},{'\xfe','\xf7'},{'\xc1','\x75'},{'\xc1','\x73'}, + {'\xed','\xe9'},{'\xed','\xec'},{'\xc1','\x72'},{'\xed','\xed'},{'\xfc','\xfe'}, + {'\xc1','\x79'},{'\xed','\xeb'},{'\x00','\x00'},{'\xed','\xea'},{'\xc2','\xc0'}, + {'\x00','\x00'},{'\xc2','\xc1'},{'\xf0','\xa1'},{'\xf0','\x7d'},{'\xf0','\x7e'}, + {'\x93','\x62'},{'\x00','\x00'},{'\xf2','\xc2'},{'\x00','\x00'},{'\xf2','\xc1'}, + {'\xc3','\xbe'},{'\xf4','\xb4'},{'\xc4','\xa4'},{'\xf4','\xb3'},{'\x00','\x00'}, + {'\xf5','\xf0'},{'\xf7','\x45'},{'\xc5','\xa6'},{'\xf9','\x43'},{'\xf9','\x44'}, + {'\xc5','\xd8'},{'\xa6','\xda'},{'\x9f','\xbd'},{'\xaa','\xd7'},{'\xdb','\x52'}, + {'\xbb','\x4e'},{'\xc1','\x7b'},{'\xed','\xef'},{'\xa6','\xdb'},{'\x00','\x00'}, + {'\xaf','\xe5'},{'\xaf','\xe4'},{'\xdb','\x53'},{'\x95','\xd3'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xea','\xf4'},{'\xa6','\xdc'},{'\xad','\x50'},{'\x00','\x00'}, + {'\xfd','\x42'},{'\xdb','\x54'},{'\xdb','\x55'},{'\xdb','\x56'},{'\xbb','\x4f'}, + {'\xbf','\xb2'},{'\xa6','\xdd'},{'\x00','\x00'},{'\xaa','\xd8'},{'\xd0','\x68'}, + {'\xaf','\xe6'},{'\xd3','\x70'},{'\xb2','\xea'},{'\x00','\x00'},{'\xdb','\x57'}, + {'\xb8','\xa4'},{'\x8a','\x77'},{'\xbb','\x50'},{'\xbf','\xb3'},{'\xc1','\x7c'}, + {'\xc2','\xc2'},{'\xf4','\xb5'},{'\xa6','\xde'},{'\xaa','\xd9'},{'\x92','\xd6'}, + {'\x00','\x00'},{'\xaf','\xe7'},{'\xd7','\x52'},{'\xb5','\xce'},{'\x00','\x00'}, + {'\xbb','\x51'},{'\xe3','\xab'},{'\xe7','\x45'},{'\x93','\xc6'},{'\x95','\xec'}, + {'\x00','\x00'},{'\xfd','\x43'},{'\xa6','\xdf'},{'\xb5','\xcf'},{'\xdf','\xa3'}, + {'\xbb','\x52'},{'\xa6','\xe0'},{'\xcd','\xb1'},{'\xd0','\x69'},{'\xad','\x51'}, + {'\x8f','\xc2'},{'\x00','\x00'},{'\xd3','\x72'},{'\xfb','\x53'},{'\x00','\x00'}, + {'\xaf','\xea'},{'\xfe','\xf8'},{'\xaf','\xe8'},{'\xaf','\xe9'},{'\xaf','\xeb'}, + {'\xfe','\xf9'},{'\xfe','\xfa'},{'\xd3','\x71'},{'\x8c','\x4c'},{'\x89','\x56'}, + {'\xd7','\x57'},{'\xd7','\x54'},{'\xd7','\x56'},{'\xb2','\xeb'},{'\xb2','\xed'}, + {'\xb2','\xec'},{'\xd7','\x53'},{'\xb2','\xee'},{'\xd7','\x55'},{'\x90','\x5b'}, + {'\xdb','\x58'},{'\xdb','\x59'},{'\xfe','\xfb'},{'\xdb','\x5a'},{'\xdf','\xa6'}, + {'\x00','\x00'},{'\xdf','\xa7'},{'\x00','\x00'},{'\xdf','\xa5'},{'\xdf','\xa8'}, + {'\x00','\x00'},{'\xb8','\xa5'},{'\x00','\x00'},{'\xdf','\xa4'},{'\x00','\x00'}, + {'\xbb','\x53'},{'\x00','\x00'},{'\x00','\x00'},{'\xe7','\x4a'},{'\xe7','\x46'}, + {'\xe7','\x49'},{'\xe7','\x4b'},{'\xe7','\x48'},{'\xe7','\x47'},{'\x9f','\xbe'}, + {'\xea','\xf5'},{'\xea','\xf6'},{'\xea','\xf7'},{'\xbf','\xb4'},{'\xbf','\xb5'}, + {'\xed','\xf1'},{'\xed','\xf0'},{'\xed','\xf2'},{'\x94','\xc8'},{'\xf0','\xa3'}, + {'\xf0','\xa2'},{'\x00','\x00'},{'\xf2','\xc4'},{'\xfe','\xfc'},{'\xf2','\xc5'}, + {'\xf2','\xc3'},{'\x9f','\xbf'},{'\xc4','\xa5'},{'\x00','\x00'},{'\xf4','\xb6'}, + {'\xf4','\xb7'},{'\xfe','\xfd'},{'\xf7','\x46'},{'\xf7','\xef'},{'\xf8','\xbb'}, + {'\xa6','\xe1'},{'\xa8','\x7d'},{'\x8a','\x5c'},{'\xc1','\x7d'},{'\xa6','\xe2'}, + {'\x8d','\x5b'},{'\xd7','\x58'},{'\xdb','\x5b'},{'\x82','\x45'},{'\xc6','\x41'}, + {'\xca','\x4a'},{'\x9c','\xd2'},{'\x8b','\xb7'},{'\x9f','\xc0'},{'\xca','\x4b'}, + {'\xca','\x4d'},{'\xa6','\xe3'},{'\xca','\x4e'},{'\xca','\x4c'},{'\x00','\x00'}, + {'\x85','\xeb'},{'\xcb','\xa2'},{'\xcb','\xa3'},{'\xcb','\x7b'},{'\x00','\x00'}, + {'\x9f','\xc1'},{'\xfe','\xfe'},{'\x00','\x00'},{'\xcb','\xa1'},{'\xa8','\xa1'}, + {'\x00','\x00'},{'\xa8','\xa2'},{'\xcb','\x7c'},{'\xcb','\x7a'},{'\xcb','\x79'}, + {'\xcb','\x7d'},{'\xa8','\x7e'},{'\xcb','\x7e'},{'\xd0','\x6a'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x8e','\xf6'},{'\xcd','\xb6'},{'\xaa','\xdc'},{'\xcd','\xb5'}, + {'\xcd','\xb7'},{'\x89','\x59'},{'\xaa','\xdb'},{'\xcd','\xbc'},{'\xaa','\xdf'}, + {'\xcd','\xb2'},{'\xcd','\xc0'},{'\xcd','\xc6'},{'\xaa','\xe6'},{'\xcd','\xc3'}, + {'\xaa','\xe3'},{'\x8c','\x4f'},{'\xcd','\xb9'},{'\xcd','\xbf'},{'\xcd','\xc1'}, + {'\xfb','\xa5'},{'\xcd','\xb4'},{'\xaa','\xe2'},{'\xaa','\xdd'},{'\xcd','\xba'}, + {'\xaa','\xe4'},{'\xaa','\xe7'},{'\xaa','\xe1'},{'\x00','\x00'},{'\xaa','\xda'}, + {'\xcd','\xbe'},{'\xcd','\xb8'},{'\xcd','\xc5'},{'\xaa','\xe9'},{'\xaa','\xe5'}, + {'\xaa','\xe0'},{'\xcd','\xbd'},{'\xaf','\xec'},{'\xcd','\xbb'},{'\xaa','\xde'}, + {'\xaa','\xe8'},{'\x9f','\xc2'},{'\xcd','\xb3'},{'\x8e','\xca'},{'\xcd','\xc2'}, + {'\xcd','\xc4'},{'\x96','\xbe'},{'\x91','\x40'},{'\x00','\x00'},{'\x85','\xfb'}, + {'\x8f','\xe1'},{'\x00','\x00'},{'\x91','\x41'},{'\x84','\x79'},{'\x85','\x51'}, + {'\x87','\x4b'},{'\x83','\x78'},{'\x84','\xf7'},{'\xfd','\x5f'},{'\xad','\x62'}, + {'\xad','\x5c'},{'\xad','\x64'},{'\xad','\x61'},{'\xd0','\x71'},{'\xd0','\x74'}, + {'\xad','\x5d'},{'\x91','\x42'},{'\xd0','\x6b'},{'\x00','\x00'},{'\xad','\x56'}, + {'\xad','\x60'},{'\x00','\x00'},{'\xad','\x63'},{'\xad','\x65'},{'\xd0','\xa2'}, + {'\xd0','\x77'},{'\x9f','\xc3'},{'\xad','\x55'},{'\xd0','\xa1'},{'\xad','\x59'}, + {'\xad','\x57'},{'\xad','\x52'},{'\xd0','\x6f'},{'\x00','\x00'},{'\xd0','\x7e'}, + {'\xd0','\x73'},{'\xd0','\x76'},{'\xd0','\xa5'},{'\x9f','\xc4'},{'\xad','\x66'}, + {'\xd0','\x7d'},{'\xad','\x5e'},{'\xd0','\x78'},{'\xd0','\xa4'},{'\xd0','\x75'}, + {'\xd0','\x79'},{'\xd0','\x7c'},{'\x96','\xa3'},{'\x9f','\xc5'},{'\xd0','\x6d'}, + {'\xd0','\xa3'},{'\xd0','\x7b'},{'\x9f','\xc6'},{'\xfd','\x5d'},{'\xd0','\x6c'}, + {'\x9f','\xc7'},{'\xd0','\x70'},{'\xad','\x5f'},{'\xad','\x5a'},{'\xad','\x53'}, + {'\xad','\x58'},{'\xad','\x54'},{'\xad','\x67'},{'\xd0','\x6e'},{'\xd3','\xa5'}, + {'\xad','\x5b'},{'\x00','\x00'},{'\x9f','\xc8'},{'\xd0','\x7a'},{'\xce','\x41'}, + {'\x92','\xa7'},{'\x8f','\xe0'},{'\x00','\x00'},{'\x8e','\xc9'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x85','\xc3'},{'\x8e','\x46'},{'\xd3','\xa8'},{'\xaf','\xfa'}, + {'\x91','\x43'},{'\xd3','\x76'},{'\x91','\x44'},{'\xd3','\xa3'},{'\xd3','\x7d'}, + {'\x9f','\xc9'},{'\xd3','\xb2'},{'\x00','\x00'},{'\xd3','\xaa'},{'\x00','\x00'}, + {'\xd3','\x7e'},{'\x91','\x45'},{'\xd3','\xa9'},{'\xd3','\x78'},{'\xd3','\x7c'}, + {'\xd3','\xb5'},{'\xaf','\xfd'},{'\xd3','\xad'},{'\xd3','\xa4'},{'\xaf','\xed'}, + {'\xd3','\xb3'},{'\xd3','\x74'},{'\x00','\x00'},{'\xd3','\xac'},{'\x00','\x00'}, + {'\xaf','\xfc'},{'\xaf','\xf7'},{'\xd3','\x73'},{'\xaf','\xf5'},{'\xaf','\xf4'}, + {'\xaf','\xf9'},{'\xd3','\xab'},{'\xaf','\xf1'},{'\xaf','\xf8'},{'\xd0','\x72'}, + {'\xdb','\x5c'},{'\xd3','\xa6'},{'\x9f','\xca'},{'\x00','\x00'},{'\xd3','\x7a'}, + {'\xaf','\xfb'},{'\xd3','\x7b'},{'\xd3','\xa1'},{'\xaf','\xfe'},{'\xd3','\x75'}, + {'\xd3','\xaf'},{'\x91','\x46'},{'\xd3','\xae'},{'\xd3','\xb6'},{'\xaf','\xf3'}, + {'\xaf','\xf0'},{'\xd3','\xb4'},{'\xd3','\xb0'},{'\xd3','\xa7'},{'\xd3','\xa2'}, + {'\xaf','\xf6'},{'\xaf','\xf2'},{'\xd3','\x77'},{'\xaf','\xee'},{'\xd3','\xb1'}, + {'\xaf','\xef'},{'\x00','\x00'},{'\xd3','\x79'},{'\x9f','\xcb'},{'\x93','\x54'}, + {'\x00','\x00'},{'\x84','\x75'},{'\x91','\x47'},{'\x8e','\xc7'},{'\x00','\x00'}, + {'\x8e','\xf4'},{'\x8f','\x5f'},{'\x8a','\xf9'},{'\x89','\x57'},{'\x91','\x48'}, + {'\x86','\xd1'},{'\x85','\xfa'},{'\x8e','\x73'},{'\x86','\xe1'},{'\x86','\xdf'}, + {'\x8e','\xf2'},{'\x8f','\x7b'},{'\x87','\x4a'},{'\x88','\x51'},{'\x91','\x49'}, + {'\x8e','\x4d'},{'\x91','\x4a'},{'\x8b','\xb9'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd7','\x5e'},{'\xd7','\x60'},{'\xd7','\x65'},{'\xd7','\x79'}, + {'\xb2','\xfc'},{'\xb2','\xf2'},{'\x00','\x00'},{'\xd7','\x5d'},{'\xb2','\xfd'}, + {'\xb2','\xfe'},{'\xd7','\x68'},{'\xd7','\x6f'},{'\xd7','\x75'},{'\x00','\x00'}, + {'\xd7','\x62'},{'\x00','\x00'},{'\xd7','\x69'},{'\x00','\x00'},{'\x87','\x48'}, + {'\xb3','\x40'},{'\xd7','\x77'},{'\xd7','\x72'},{'\xb2','\xfa'},{'\xb2','\xf8'}, + {'\xd7','\x6e'},{'\xd7','\x6a'},{'\xd7','\x5c'},{'\xb2','\xef'},{'\xd7','\x61'}, + {'\xd7','\x59'},{'\x9f','\xcc'},{'\xb2','\xf7'},{'\xb2','\xf9'},{'\xd7','\x66'}, + {'\xd7','\x63'},{'\xb2','\xf4'},{'\xd7','\x73'},{'\xb2','\xf1'},{'\xd7','\x64'}, + {'\xd7','\x7a'},{'\xd7','\x6c'},{'\x91','\x4b'},{'\xd7','\x6b'},{'\xb2','\xf0'}, + {'\x91','\x4c'},{'\xb2','\xfb'},{'\x00','\x00'},{'\xb2','\xf3'},{'\xd7','\x5a'}, + {'\xd7','\x5f'},{'\xd7','\x70'},{'\xd7','\x76'},{'\xb3','\x41'},{'\xd7','\x5b'}, + {'\xd7','\x67'},{'\xd7','\x6d'},{'\xb2','\xf6'},{'\x9f','\xcd'},{'\x00','\x00'}, + {'\xd7','\x78'},{'\xd7','\x71'},{'\xd7','\x74'},{'\x85','\x50'},{'\x88','\x50'}, + {'\x8e','\x7d'},{'\x85','\xfd'},{'\x91','\x4d'},{'\x8f','\x60'},{'\x89','\xf7'}, + {'\x8e','\xf5'},{'\x87','\xf3'},{'\x8c','\xc2'},{'\x00','\x00'},{'\x91','\x4e'}, + {'\xb2','\xf5'},{'\xfb','\xad'},{'\xdb','\x6c'},{'\xdb','\x60'},{'\xb5','\xd7'}, + {'\xdb','\x7d'},{'\xdb','\xa7'},{'\xdb','\xaa'},{'\xb5','\xd5'},{'\xdb','\x68'}, + {'\xdb','\xa3'},{'\xdb','\x69'},{'\xdb','\x77'},{'\xb5','\xe2'},{'\xdb','\x73'}, + {'\xb5','\xdf'},{'\x9f','\xce'},{'\xdb','\x74'},{'\xdb','\x5d'},{'\x00','\x00'}, + {'\xdb','\xa4'},{'\x00','\x00'},{'\xfe','\x52'},{'\xb5','\xe8'},{'\xdb','\xa1'}, + {'\xdb','\x75'},{'\xdb','\xac'},{'\xdb','\x70'},{'\xdf','\xc8'},{'\x00','\x00'}, + {'\xdb','\xaf'},{'\xb5','\xe6'},{'\xdb','\x6e'},{'\xdb','\x7a'},{'\xb5','\xe9'}, + {'\xb5','\xd4'},{'\xdb','\x72'},{'\xdb','\xad'},{'\xdb','\x6b'},{'\xdb','\x64'}, + {'\xdb','\x6f'},{'\x00','\x00'},{'\xdb','\x63'},{'\xdb','\x61'},{'\xb5','\xd0'}, + {'\xdb','\xa5'},{'\xdb','\x6a'},{'\xdb','\xa8'},{'\x9f','\xcf'},{'\xdb','\xa9'}, + {'\xb5','\xd8'},{'\xb5','\xdd'},{'\xb5','\xd9'},{'\xb5','\xe1'},{'\xdb','\x7e'}, + {'\xb5','\xda'},{'\xdb','\x76'},{'\xdb','\x66'},{'\x91','\x4f'},{'\xb5','\xd2'}, + {'\xdb','\x5e'},{'\xdb','\xa2'},{'\xdb','\xab'},{'\xdb','\x65'},{'\xb5','\xe0'}, + {'\xdb','\xb0'},{'\xdb','\x71'},{'\x00','\x00'},{'\xdb','\x6d'},{'\x00','\x00'}, + {'\xb5','\xd1'},{'\xb5','\xe5'},{'\x9f','\xd0'},{'\xdb','\x7c'},{'\xb5','\xe7'}, + {'\x00','\x00'},{'\xdb','\x78'},{'\xb5','\xdc'},{'\xb5','\xd6'},{'\xb5','\xde'}, + {'\xb5','\xd3'},{'\xb5','\xe4'},{'\xdb','\x79'},{'\xdb','\x67'},{'\xdb','\x7b'}, + {'\xdb','\x62'},{'\xdb','\xa6'},{'\x9f','\xd1'},{'\x00','\x00'},{'\x9f','\xd2'}, + {'\x00','\x00'},{'\x96','\xa7'},{'\x00','\x00'},{'\x00','\x00'},{'\xdb','\xae'}, + {'\x96','\xbd'},{'\x8c','\xfd'},{'\x00','\x00'},{'\x00','\x00'},{'\xfd','\x63'}, + {'\x9f','\xd3'},{'\x94','\xc9'},{'\xdb','\x5f'},{'\x89','\x5b'},{'\x89','\xf1'}, + {'\x89','\x4d'},{'\x89','\x58'},{'\x8a','\xf7'},{'\xdf','\xc7'},{'\x91','\x50'}, + {'\xdf','\xdd'},{'\xb8','\x55'},{'\xdf','\xcc'},{'\x9f','\xd4'},{'\xdf','\xca'}, + {'\xdf','\xb5'},{'\xb8','\xa9'},{'\xdf','\xc5'},{'\xdf','\xd9'},{'\xdf','\xc1'}, + {'\xb8','\xb1'},{'\xdf','\xd8'},{'\xdf','\xbf'},{'\xb5','\xe3'},{'\xdf','\xcf'}, + {'\xdf','\xc0'},{'\xdf','\xd6'},{'\xb8','\xb0'},{'\xb8','\xa8'},{'\x9f','\xd5'}, + {'\xdf','\xaa'},{'\xdf','\xb2'},{'\x00','\x00'},{'\xdf','\xcb'},{'\xdf','\xc3'}, + {'\xdf','\xdc'},{'\xdf','\xc6'},{'\xb8','\xb6'},{'\xdf','\xd7'},{'\x91','\x51'}, + {'\xb8','\xad'},{'\x9f','\xd6'},{'\xdf','\xc9'},{'\xdf','\xd1'},{'\xdf','\xb6'}, + {'\xdf','\xd0'},{'\x00','\x00'},{'\xdf','\xe1'},{'\xdf','\xb1'},{'\xdf','\xd2'}, + {'\x9f','\xd7'},{'\xdf','\xdf'},{'\x9f','\xd8'},{'\xdf','\xab'},{'\xb5','\xdb'}, + {'\x9f','\xd9'},{'\xdf','\xb9'},{'\xdf','\xb8'},{'\xb8','\xaf'},{'\x91','\x52'}, + {'\xdf','\xbc'},{'\xdf','\xbe'},{'\xdf','\xcd'},{'\xdf','\xde'},{'\xb8','\xb2'}, + {'\x91','\x53'},{'\xb8','\xb3'},{'\x9f','\xda'},{'\xdf','\xb0'},{'\xb8','\xab'}, + {'\xdf','\xb4'},{'\xdf','\xda'},{'\xb8','\xb4'},{'\x00','\x00'},{'\xb8','\xac'}, + {'\xb8','\xae'},{'\xb8','\xb5'},{'\xdf','\xe0'},{'\xdf','\xd3'},{'\xdf','\xce'}, + {'\x95','\xf5'},{'\x9f','\xdb'},{'\xdf','\xbb'},{'\xdf','\xba'},{'\xb8','\xaa'}, + {'\xdf','\xac'},{'\xb8','\xa7'},{'\xdf','\xc4'},{'\xdf','\xad'},{'\xdf','\xc2'}, + {'\x96','\xc0'},{'\x00','\x00'},{'\xdf','\xb7'},{'\xdf','\xdb'},{'\x9f','\xdc'}, + {'\x9f','\xdd'},{'\x00','\x00'},{'\xb8','\xa6'},{'\x00','\x00'},{'\x91','\x54'}, + {'\x00','\x00'},{'\xdf','\xb3'},{'\x8e','\xf1'},{'\x91','\x55'},{'\x8e','\xf3'}, + {'\x00','\x00'},{'\x88','\x52'},{'\x8e','\xc8'},{'\xdf','\xaf'},{'\xdf','\xd5'}, + {'\xdf','\xae'},{'\xbb','\x60'},{'\xe3','\xd3'},{'\x9f','\xde'},{'\x9f','\xdf'}, + {'\xe3','\xc2'},{'\x00','\x00'},{'\x9f','\xe0'},{'\xe3','\xac'},{'\xe3','\xca'}, + {'\xbb','\x58'},{'\xe3','\xbb'},{'\xe3','\xc5'},{'\xbb','\x5b'},{'\xe3','\xbe'}, + {'\xbb','\x59'},{'\xe3','\xaf'},{'\xe3','\xcd'},{'\xe3','\xae'},{'\xe3','\xc1'}, + {'\x9f','\xe1'},{'\xe3','\xad'},{'\x00','\x00'},{'\x00','\x00'},{'\xe3','\xbf'}, + {'\xe3','\xc8'},{'\xe3','\xc6'},{'\xe3','\xba'},{'\xe3','\xb5'},{'\xe3','\xb3'}, + {'\xfd','\x66'},{'\xe3','\xb4'},{'\xe3','\xc7'},{'\xe3','\xd2'},{'\xe3','\xbc'}, + {'\xbb','\x5a'},{'\x00','\x00'},{'\xe3','\xb7'},{'\x00','\x00'},{'\xe3','\xcb'}, + {'\x00','\x00'},{'\xbb','\x5d'},{'\xe3','\xb6'},{'\xe3','\xb0'},{'\xe3','\xc0'}, + {'\xbb','\x61'},{'\x96','\xbc'},{'\x9f','\xe2'},{'\xbb','\x55'},{'\xbb','\x5e'}, + {'\xe3','\xb8'},{'\xe3','\xb2'},{'\x00','\x00'},{'\xbb','\x57'},{'\xdf','\xd4'}, + {'\xbb','\x56'},{'\xe3','\xc3'},{'\x00','\x00'},{'\xbb','\x54'},{'\xbb','\x63'}, + {'\xbb','\x5c'},{'\xe3','\xc4'},{'\xe3','\xb9'},{'\xe3','\xb1'},{'\xe3','\xcc'}, + {'\xe3','\xbd'},{'\xbb','\x62'},{'\xe3','\xd0'},{'\xbb','\x5f'},{'\xe3','\xcf'}, + {'\x00','\x00'},{'\xe3','\xc9'},{'\xe3','\xce'},{'\x00','\x00'},{'\x94','\xca'}, + {'\xfd','\x65'},{'\xe3','\xd1'},{'\x91','\x56'},{'\x8a','\xf8'},{'\x9f','\xe3'}, + {'\x8a','\x5e'},{'\x90','\x6c'},{'\x9f','\xe4'},{'\x9f','\xe5'},{'\x91','\x57'}, + {'\x9f','\xe6'},{'\x8f','\xaa'},{'\x8c','\xbd'},{'\xe7','\x73'},{'\xe7','\x74'}, + {'\xe7','\x67'},{'\xe7','\x66'},{'\xe7','\x62'},{'\xbd','\xb4'},{'\x00','\x00'}, + {'\xbd','\xac'},{'\xe7','\x76'},{'\xe7','\x75'},{'\xdf','\xa9'},{'\xe7','\x5f'}, + {'\xe7','\x63'},{'\xe7','\x5d'},{'\x00','\x00'},{'\xe7','\x70'},{'\xe7','\x61'}, + {'\x9f','\xe7'},{'\xe7','\x77'},{'\xe7','\x5a'},{'\xe7','\x58'},{'\xe7','\x64'}, + {'\xe7','\x6e'},{'\xe7','\x69'},{'\xbd','\xb6'},{'\xe7','\x4f'},{'\x00','\x00'}, + {'\xe7','\x6d'},{'\x9f','\xe8'},{'\x00','\x00'},{'\x9f','\xe9'},{'\xbd','\xb7'}, + {'\xdf','\xbd'},{'\xe7','\x5b'},{'\xe7','\x52'},{'\xe7','\x55'},{'\xe7','\x7b'}, + {'\xe7','\x5c'},{'\xe7','\x53'},{'\xe7','\x51'},{'\xe7','\x4e'},{'\x9f','\xea'}, + {'\xbd','\xb0'},{'\xe7','\x65'},{'\xbd','\xaf'},{'\xbd','\xb3'},{'\xe7','\x60'}, + {'\xe7','\x68'},{'\xbd','\xa9'},{'\xe7','\x78'},{'\xe7','\x7c'},{'\xbd','\xab'}, + {'\x00','\x00'},{'\xe7','\x57'},{'\xe7','\x6b'},{'\xe7','\x6f'},{'\xe7','\x54'}, + {'\xe7','\x79'},{'\xbd','\xb2'},{'\x00','\x00'},{'\xbd','\xb1'},{'\xe7','\x4c'}, + {'\xbd','\xb5'},{'\xe7','\x72'},{'\xe7','\x56'},{'\xe7','\x6a'},{'\xe7','\x50'}, + {'\xe7','\x5e'},{'\xe7','\x59'},{'\xbd','\xad'},{'\xbd','\xae'},{'\xe7','\x6c'}, + {'\xe7','\x7d'},{'\xe7','\x7a'},{'\xe7','\x71'},{'\x00','\x00'},{'\x9f','\xeb'}, + {'\xfe','\x4c'},{'\x93','\x60'},{'\x00','\x00'},{'\x8a','\x5d'},{'\x91','\x58'}, + {'\x90','\x46'},{'\x8c','\x4e'},{'\xe7','\x4d'},{'\x8c','\x4d'},{'\xbd','\xaa'}, + {'\xeb','\x49'},{'\x00','\x00'},{'\xeb','\x40'},{'\xeb','\x43'},{'\x9f','\xed'}, + {'\xbf','\xbb'},{'\xeb','\x45'},{'\xea','\xf9'},{'\xeb','\x41'},{'\xeb','\x47'}, + {'\xbf','\xb8'},{'\xbf','\xbc'},{'\xbf','\xb6'},{'\xfd','\x68'},{'\x9f','\xee'}, + {'\xea','\xfb'},{'\xeb','\x4c'},{'\x00','\x00'},{'\x00','\x00'},{'\xeb','\x46'}, + {'\x9f','\xef'},{'\xea','\xfc'},{'\xeb','\x55'},{'\xeb','\x4f'},{'\xea','\xf8'}, + {'\xee','\x46'},{'\xea','\xfe'},{'\xbf','\xb7'},{'\x91','\x59'},{'\xeb','\x4a'}, + {'\x00','\x00'},{'\xeb','\x54'},{'\xbf','\xbf'},{'\x9f','\xf0'},{'\xeb','\x51'}, + {'\xea','\xfd'},{'\xeb','\x44'},{'\xeb','\x48'},{'\xeb','\x42'},{'\xeb','\x56'}, + {'\xeb','\x53'},{'\xeb','\x50'},{'\xbf','\xb9'},{'\xbf','\xba'},{'\xbf','\xbe'}, + {'\xea','\xfa'},{'\xeb','\x57'},{'\xbf','\xbd'},{'\xeb','\x4d'},{'\x9f','\xf1'}, + {'\x9f','\xf2'},{'\xeb','\x4b'},{'\x8f','\xe2'},{'\x9f','\xf3'},{'\x8c','\x51'}, + {'\xeb','\x4e'},{'\xee','\x53'},{'\xee','\x40'},{'\xee','\x45'},{'\xee','\x52'}, + {'\xee','\x44'},{'\xed','\xfb'},{'\xee','\x41'},{'\x00','\x00'},{'\xc1','\xa2'}, + {'\x00','\x00'},{'\xed','\xf4'},{'\xee','\x4d'},{'\xee','\x4f'},{'\xed','\xf3'}, + {'\xc1','\xa1'},{'\xee','\x51'},{'\xee','\x49'},{'\xc1','\xa8'},{'\xee','\x50'}, + {'\xee','\x42'},{'\xc1','\xaa'},{'\xed','\xf9'},{'\xeb','\x52'},{'\xee','\x4a'}, + {'\xee','\x47'},{'\xed','\xf5'},{'\xee','\x55'},{'\xc1','\xa4'},{'\x00','\x00'}, + {'\x9d','\x76'},{'\xc1','\xa5'},{'\xed','\xf7'},{'\xee','\x48'},{'\x91','\x5a'}, + {'\xee','\x54'},{'\xee','\x4b'},{'\xed','\xfd'},{'\xc1','\xa7'},{'\xc1','\xa3'}, + {'\xee','\x4c'},{'\xed','\xfe'},{'\xee','\x56'},{'\xed','\xf8'},{'\xee','\x43'}, + {'\xee','\x4e'},{'\xed','\xfa'},{'\xed','\xfc'},{'\x00','\x00'},{'\xc2','\xcb'}, + {'\xed','\xf6'},{'\xc1','\xa9'},{'\xc2','\xc4'},{'\xc1','\x7e'},{'\x91','\x5b'}, + {'\x93','\xd6'},{'\x00','\x00'},{'\x82','\x7e'},{'\xc1','\xa6'},{'\xc2','\xc8'}, + {'\xf0','\xb3'},{'\x00','\x00'},{'\xf0','\xa9'},{'\xf0','\xa4'},{'\xf0','\xaa'}, + {'\xf0','\xb4'},{'\xf0','\xb8'},{'\xf0','\xb7'},{'\xc2','\xca'},{'\xc2','\xc9'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xf0','\xab'},{'\xf0','\xb9'},{'\xf0','\xae'}, + {'\xf0','\xa6'},{'\x91','\x5c'},{'\xf0','\xa8'},{'\xf0','\xa7'},{'\xf0','\xad'}, + {'\xf0','\xb2'},{'\xf0','\xa5'},{'\xf0','\xac'},{'\xf0','\xb1'},{'\xc2','\xc7'}, + {'\x00','\x00'},{'\xf0','\xaf'},{'\x00','\x00'},{'\xc2','\xc5'},{'\xf0','\xb0'}, + {'\xc2','\xc3'},{'\xc2','\xc6'},{'\xf2','\xd5'},{'\xf0','\xb5'},{'\x8c','\xa4'}, + {'\x00','\x00'},{'\xc3','\xc2'},{'\x9f','\xf4'},{'\xf2','\xcd'},{'\xf2','\xd1'}, + {'\xf2','\xc9'},{'\xf2','\xcc'},{'\x00','\x00'},{'\xf2','\xd4'},{'\xc3','\xc0'}, + {'\xf2','\xd9'},{'\xf2','\xd2'},{'\x9f','\xf5'},{'\xf2','\xca'},{'\xf2','\xda'}, + {'\xf2','\xd3'},{'\xc3','\xc3'},{'\xc3','\xc4'},{'\xf2','\xd7'},{'\x00','\x00'}, + {'\xf2','\xcb'},{'\xc3','\xbf'},{'\xc3','\xc1'},{'\xf2','\xc6'},{'\xf2','\xce'}, + {'\xf2','\xc8'},{'\x9f','\xf6'},{'\xf2','\xd8'},{'\xf2','\xd6'},{'\xf2','\xc7'}, + {'\xf2','\xcf'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xf4','\xbe'}, + {'\xc3','\xc5'},{'\xf2','\xd0'},{'\xc4','\xa7'},{'\xc4','\xa9'},{'\xc4','\xa6'}, + {'\x9f','\xf7'},{'\xf4','\xc3'},{'\xf4','\xbb'},{'\xf4','\xb9'},{'\xf4','\xbd'}, + {'\xf4','\xba'},{'\xfd','\x6a'},{'\x00','\x00'},{'\xf4','\xbf'},{'\xf4','\xc1'}, + {'\xc4','\xaa'},{'\xc4','\xac'},{'\x00','\x00'},{'\xf4','\xc0'},{'\xc4','\xad'}, + {'\xc4','\xab'},{'\xf4','\xc2'},{'\x9f','\xf8'},{'\x00','\x00'},{'\x9f','\xf9'}, + {'\xfd','\x6b'},{'\xc4','\xa8'},{'\x00','\x00'},{'\x91','\x5d'},{'\x9f','\xfa'}, + {'\x00','\x00'},{'\x91','\x5e'},{'\xc4','\xf4'},{'\xf5','\xf1'},{'\xf5','\xf7'}, + {'\xc4','\xf6'},{'\xf4','\xbc'},{'\xf5','\xf6'},{'\x00','\x00'},{'\xf5','\xfd'}, + {'\xf5','\xf4'},{'\xf5','\xfb'},{'\xf5','\xfa'},{'\xf4','\xb8'},{'\xf5','\xf5'}, + {'\xf0','\xb6'},{'\xf5','\xfe'},{'\xf5','\xf3'},{'\xf5','\xf8'},{'\x9f','\xfb'}, + {'\xf5','\xfc'},{'\xf5','\xf2'},{'\x00','\x00'},{'\xf7','\x4a'},{'\xc4','\xf5'}, + {'\xf5','\xf9'},{'\xfb','\xae'},{'\x94','\xcb'},{'\xf7','\xf4'},{'\xf7','\x4b'}, + {'\xf7','\x49'},{'\xf7','\x47'},{'\xf7','\x48'},{'\xf7','\x4c'},{'\x00','\x00'}, + {'\xc5','\xd9'},{'\xf7','\xf2'},{'\xf7','\xf0'},{'\xf7','\xf5'},{'\xf7','\xf3'}, + {'\x00','\x00'},{'\xf7','\xf6'},{'\xc5','\xda'},{'\xf7','\xf1'},{'\x00','\x00'}, + {'\x9f','\xfc'},{'\xf8','\xbc'},{'\x00','\x00'},{'\x9f','\xfd'},{'\xf9','\x45'}, + {'\xf9','\x46'},{'\xf9','\x47'},{'\x00','\x00'},{'\x00','\x00'},{'\xf9','\xc7'}, + {'\xf9','\xbd'},{'\xca','\x4f'},{'\xaa','\xea'},{'\x86','\x40'},{'\xad','\x68'}, + {'\x87','\xcb'},{'\xd3','\xb8'},{'\xd3','\xb7'},{'\xb0','\x40'},{'\xb3','\x42'}, + {'\xd7','\x7c'},{'\x00','\x00'},{'\x00','\x00'},{'\xd7','\x7b'},{'\x85','\x52'}, + {'\xb5','\xea'},{'\xb8','\xb8'},{'\x00','\x00'},{'\xb8','\xb7'},{'\xb8','\xb9'}, + {'\x00','\x00'},{'\xe3','\xd4'},{'\xe7','\x7e'},{'\xeb','\x58'},{'\xeb','\x5a'}, + {'\xeb','\x59'},{'\x00','\x00'},{'\xc1','\xab'},{'\xee','\x57'},{'\xf0','\xba'}, + {'\xf9','\xa5'},{'\xa6','\xe4'},{'\x95','\x78'},{'\xcd','\xc9'},{'\xcd','\xca'}, + {'\xcd','\xc8'},{'\xcd','\xc7'},{'\xaa','\xeb'},{'\x9f','\xfe'},{'\xd0','\xa9'}, + {'\xd0','\xa7'},{'\x00','\x00'},{'\x00','\x00'},{'\xd0','\xa6'},{'\x00','\x00'}, + {'\xad','\x69'},{'\xad','\x6b'},{'\xad','\x6a'},{'\xd0','\xa8'},{'\x8a','\xaf'}, + {'\x88','\x53'},{'\x8f','\xc4'},{'\x87','\x4c'},{'\x8b','\xba'},{'\x89','\x5a'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xd3','\xc4'},{'\xd3','\xc1'},{'\xd3','\xbf'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb0','\x41'},{'\xd3','\xc2'},{'\xb0','\x46'}, + {'\xd3','\xbc'},{'\xd3','\xcb'},{'\x00','\x00'},{'\xd3','\xcd'},{'\xd3','\xbd'}, + {'\xfe','\xbb'},{'\xb0','\x43'},{'\xd3','\xce'},{'\xd3','\xc9'},{'\xd3','\xbb'}, + {'\xd3','\xc0'},{'\xd3','\xca'},{'\xd3','\xc6'},{'\xd3','\xc3'},{'\x00','\x00'}, + {'\xb0','\x48'},{'\xd3','\xcc'},{'\xd3','\xbe'},{'\x00','\x00'},{'\xfe','\xbc'}, + {'\xd3','\xc7'},{'\xd3','\xb9'},{'\xb0','\x47'},{'\xb0','\x44'},{'\xd3','\xc5'}, + {'\x00','\x00'},{'\xd3','\xc8'},{'\xd3','\xba'},{'\xb0','\x45'},{'\xb0','\x42'}, + {'\x94','\xcc'},{'\x86','\x43'},{'\xfe','\xbd'},{'\x00','\x00'},{'\xb3','\x4c'}, + {'\xd7','\xa5'},{'\xb3','\x4b'},{'\xfe','\xbe'},{'\xd7','\xa8'},{'\xd7','\xab'}, + {'\xb3','\x48'},{'\xb3','\x46'},{'\xd7','\x7e'},{'\xd7','\xa9'},{'\xd7','\xa7'}, + {'\xd7','\xa4'},{'\xd7','\xac'},{'\xd7','\xad'},{'\xd7','\xaf'},{'\xd7','\xb0'}, + {'\xd7','\x7d'},{'\xb3','\x45'},{'\xd7','\xa2'},{'\xd7','\xa1'},{'\xd7','\xae'}, + {'\xb3','\x47'},{'\xd7','\xa3'},{'\xb3','\x49'},{'\xb3','\x44'},{'\xd7','\xa6'}, + {'\xb3','\x4d'},{'\x8c','\xfe'},{'\xb3','\x4a'},{'\xd7','\xaa'},{'\x92','\xac'}, + {'\x82','\x4c'},{'\x8f','\xc3'},{'\xb5','\xf1'},{'\xdb','\xbf'},{'\x00','\x00'}, + {'\xdb','\xb4'},{'\xb5','\xee'},{'\x00','\x00'},{'\xdf','\xe7'},{'\xdb','\xbd'}, + {'\xdb','\xb1'},{'\xb5','\xec'},{'\xdb','\xb6'},{'\xb5','\xef'},{'\xdb','\xba'}, + {'\xdb','\xb8'},{'\xb5','\xf2'},{'\xb5','\xeb'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xdb','\xb2'},{'\xdb','\xb5'},{'\xb5','\xf0'},{'\x00','\x00'},{'\xdb','\xb3'}, + {'\x00','\x00'},{'\xdb','\xbe'},{'\xdb','\xbc'},{'\xdb','\xb7'},{'\xdb','\xb9'}, + {'\xdb','\xbb'},{'\xb5','\xed'},{'\x8d','\x72'},{'\x94','\xcd'},{'\x8f','\x61'}, + {'\x8e','\x4e'},{'\x8a','\xfa'},{'\x8e','\xf7'},{'\x8f','\xe3'},{'\xdf','\xe8'}, + {'\xdf','\xee'},{'\xdf','\xe4'},{'\xdf','\xea'},{'\xb8','\xba'},{'\xdf','\xe6'}, + {'\xb8','\xc0'},{'\x00','\x00'},{'\x00','\x00'},{'\xb8','\xbf'},{'\x00','\x00'}, + {'\xb8','\xbe'},{'\xdf','\xed'},{'\xb8','\xc1'},{'\xb8','\xc2'},{'\xdf','\xe3'}, + {'\xdf','\xf0'},{'\xb8','\xc3'},{'\xb8','\xbd'},{'\xb8','\xbc'},{'\xdf','\xec'}, + {'\xb8','\xc4'},{'\xdf','\xe2'},{'\xdf','\xe5'},{'\xdf','\xef'},{'\xdf','\xeb'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xe3','\xf4'},{'\xe3','\xe9'},{'\xb8','\xbb'}, + {'\x00','\x00'},{'\x91','\x60'},{'\x00','\x00'},{'\x88','\x54'},{'\xbb','\x6a'}, + {'\xe3','\xdd'},{'\xe3','\xf2'},{'\xe3','\xde'},{'\xbb','\x65'},{'\x00','\x00'}, + {'\xe3','\xdb'},{'\x00','\x00'},{'\xe3','\xe4'},{'\xe3','\xdc'},{'\xbb','\x67'}, + {'\xe3','\xd6'},{'\xe3','\xf1'},{'\xbb','\x68'},{'\xe3','\xee'},{'\xe3','\xef'}, + {'\xe3','\xd7'},{'\xbb','\x6d'},{'\xe3','\xe6'},{'\x00','\x00'},{'\xe3','\xe0'}, + {'\xe3','\xe7'},{'\xe3','\xda'},{'\x00','\x00'},{'\xe3','\xf3'},{'\xe3','\xeb'}, + {'\xe3','\xe5'},{'\xe3','\xd5'},{'\xbb','\x69'},{'\xe3','\xec'},{'\x00','\x00'}, + {'\xbb','\x6c'},{'\xe3','\xf0'},{'\x00','\x00'},{'\xe3','\xea'},{'\xbb','\x66'}, + {'\xe3','\xe8'},{'\x00','\x00'},{'\xe3','\xe2'},{'\xbb','\x64'},{'\xe3','\xd9'}, + {'\xe3','\xe1'},{'\xe3','\xed'},{'\xe3','\xdf'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xe3','\xe3'},{'\x8b','\xbb'},{'\x8a','\x61'},{'\x8a','\xfb'},{'\x00','\x00'}, + {'\x82','\xa2'},{'\xbd','\xc1'},{'\xdf','\xe9'},{'\xe7','\xb2'},{'\xe7','\xbb'}, + {'\xe7','\xb1'},{'\xe7','\xad'},{'\xe7','\xaa'},{'\xbd','\xc2'},{'\xe7','\xa8'}, + {'\xbb','\x6b'},{'\xe7','\xa1'},{'\xbd','\xc0'},{'\xe7','\xa7'},{'\xbd','\xbf'}, + {'\xe7','\xac'},{'\xe7','\xa9'},{'\xe7','\xb9'},{'\xe7','\xb4'},{'\xe7','\xae'}, + {'\xe7','\xb3'},{'\xbd','\xbb'},{'\xe7','\xab'},{'\xe7','\xbe'},{'\xe7','\xa2'}, + {'\xe7','\xa3'},{'\xe7','\xba'},{'\xbd','\xbc'},{'\xe7','\xbf'},{'\xbd','\xbe'}, + {'\xe7','\xc0'},{'\xe7','\xb0'},{'\xe3','\xd8'},{'\xe7','\xb6'},{'\xe7','\xaf'}, + {'\xe7','\xb8'},{'\xe7','\xb5'},{'\x91','\x61'},{'\xfd','\x45'},{'\x00','\x00'}, + {'\xe7','\xa6'},{'\xbd','\xb9'},{'\xe7','\xbd'},{'\xbd','\xba'},{'\xe7','\xa4'}, + {'\xbd','\xbd'},{'\xeb','\x64'},{'\xe7','\xb7'},{'\xe7','\xbc'},{'\x8a','\x60'}, + {'\x91','\x62'},{'\x8f','\xe4'},{'\x82','\x75'},{'\x00','\x00'},{'\xeb','\x61'}, + {'\xbd','\xb8'},{'\xbf','\xc0'},{'\xeb','\x6b'},{'\xeb','\x67'},{'\xfb','\x6c'}, + {'\xeb','\x65'},{'\xeb','\x60'},{'\xeb','\x6f'},{'\x00','\x00'},{'\x91','\x63'}, + {'\xfd','\x47'},{'\xbf','\xc4'},{'\x00','\x00'},{'\xeb','\x5c'},{'\xeb','\x68'}, + {'\xeb','\x69'},{'\xeb','\x5f'},{'\xeb','\x5e'},{'\xeb','\x6c'},{'\x00','\x00'}, + {'\xeb','\x62'},{'\xeb','\x5d'},{'\xeb','\x63'},{'\x00','\x00'},{'\xeb','\x6e'}, + {'\xeb','\x5b'},{'\xeb','\x6d'},{'\xeb','\x6a'},{'\xbf','\xc2'},{'\xbf','\xc1'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xbf','\xc3'},{'\xeb','\x66'},{'\xf0','\xcb'}, + {'\xfe','\xbf'},{'\x00','\x00'},{'\x00','\x00'},{'\x91','\x64'},{'\xfd','\x46'}, + {'\xee','\x59'},{'\xc1','\xb1'},{'\xee','\x5d'},{'\xee','\x5a'},{'\xee','\x61'}, + {'\xee','\x67'},{'\xee','\x5c'},{'\xfe','\xc0'},{'\xee','\x70'},{'\xc1','\xae'}, + {'\xee','\x6a'},{'\xee','\x5f'},{'\xee','\x6b'},{'\xee','\x66'},{'\xee','\x6d'}, + {'\xee','\x5e'},{'\xc1','\xb3'},{'\xc1','\xb2'},{'\xee','\x60'},{'\xee','\x6e'}, + {'\xee','\x58'},{'\xee','\x6c'},{'\xc1','\xac'},{'\xfd','\x49'},{'\xee','\x64'}, + {'\xee','\x63'},{'\xee','\x68'},{'\xee','\x5b'},{'\xc1','\xb0'},{'\x91','\x65'}, + {'\xc1','\xb4'},{'\xee','\x62'},{'\xee','\x69'},{'\xc1','\xb5'},{'\xee','\x65'}, + {'\x00','\x00'},{'\x96','\xc7'},{'\x00','\x00'},{'\x91','\x66'},{'\xc1','\xad'}, + {'\xc1','\xaf'},{'\xf0','\xc7'},{'\xf0','\xc5'},{'\x00','\x00'},{'\xfd','\x4c'}, + {'\xf0','\xcc'},{'\xf0','\xc9'},{'\xf0','\xcd'},{'\xfe','\xc5'},{'\xf0','\xbe'}, + {'\xf0','\xc6'},{'\xf0','\xd1'},{'\xee','\x6f'},{'\xf0','\xc2'},{'\xc2','\xcf'}, + {'\xe7','\xa5'},{'\xf0','\xbd'},{'\xf0','\xca'},{'\xf0','\xc4'},{'\xf0','\xc1'}, + {'\xf0','\xbc'},{'\xf0','\xbb'},{'\xf0','\xd0'},{'\x00','\x00'},{'\xf0','\xc0'}, + {'\xf0','\xbf'},{'\xc2','\xcd'},{'\xf0','\xc8'},{'\xfb','\xab'},{'\xc2','\xcc'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc2','\xce'},{'\xf0','\xc3'},{'\xf0','\xcf'}, + {'\xfd','\x4d'},{'\xf2','\xde'},{'\xf2','\xdf'},{'\x00','\x00'},{'\xc3','\xc9'}, + {'\xf2','\xdc'},{'\xc3','\xc6'},{'\xf2','\xe4'},{'\x00','\x00'},{'\xc3','\xca'}, + {'\xf2','\xe6'},{'\xf2','\xdb'},{'\xf0','\xce'},{'\xf2','\xe8'},{'\xf2','\xdd'}, + {'\xfb','\x72'},{'\xc3','\xc7'},{'\xf2','\xe3'},{'\x91','\x67'},{'\xf2','\xe5'}, + {'\xf2','\xe0'},{'\xf2','\xe7'},{'\xf2','\xe2'},{'\xf2','\xe1'},{'\xc3','\xc8'}, + {'\x91','\x68'},{'\xfd','\x4e'},{'\xf4','\xc5'},{'\xf4','\xc6'},{'\x00','\x00'}, + {'\xf4','\xc8'},{'\xc4','\xae'},{'\xc4','\xaf'},{'\xf4','\xc9'},{'\xf4','\xc7'}, + {'\xfd','\x4f'},{'\xf4','\xc4'},{'\x00','\x00'},{'\xf6','\x42'},{'\xf6','\x45'}, + {'\xf6','\x41'},{'\x00','\x00'},{'\xc4','\xfa'},{'\xf6','\x43'},{'\xc4','\xf9'}, + {'\xc4','\xf8'},{'\xc4','\xf7'},{'\xf6','\x44'},{'\xf7','\x51'},{'\xf7','\x4f'}, + {'\x91','\x69'},{'\xf7','\x4e'},{'\xf6','\x40'},{'\xf7','\x50'},{'\xf6','\x46'}, + {'\xf7','\x4d'},{'\xfd','\x50'},{'\xf7','\xf9'},{'\xf7','\xd7'},{'\xf7','\xf7'}, + {'\xc5','\xdb'},{'\xf7','\xf8'},{'\xf7','\xfa'},{'\x00','\x00'},{'\xf8','\xbf'}, + {'\xc5','\xfa'},{'\xf8','\xbe'},{'\xf8','\xbd'},{'\xc5','\xfb'},{'\x00','\x00'}, + {'\xc6','\x5a'},{'\xf9','\x6e'},{'\xf9','\xa7'},{'\xf9','\xa6'},{'\xf9','\xa8'}, + {'\xa6','\xe5'},{'\xd0','\xaa'},{'\xfd','\x51'},{'\xd3','\xcf'},{'\xd3','\xd0'}, + {'\x8d','\x75'},{'\x92','\xdb'},{'\x00','\x00'},{'\xdb','\xc0'},{'\x00','\x00'}, + {'\xf6','\x47'},{'\xf8','\xc0'},{'\xa6','\xe6'},{'\xad','\x6c'},{'\xd0','\xab'}, + {'\xfe','\xc6'},{'\x00','\x00'},{'\x00','\x00'},{'\xd7','\xb1'},{'\xb3','\x4e'}, + {'\x83','\xf5'},{'\xdb','\xc2'},{'\xdb','\xc1'},{'\xb5','\xf3'},{'\x00','\x00'}, + {'\xb8','\xc5'},{'\xe7','\xc1'},{'\xbd','\xc3'},{'\x00','\x00'},{'\xbd','\xc4'}, + {'\xfd','\x5b'},{'\x00','\x00'},{'\xfe','\xc7'},{'\xbf','\xc5'},{'\xc5','\xfc'}, + {'\xa6','\xe7'},{'\x91','\xd6'},{'\x86','\x44'},{'\x00','\x00'},{'\xd0','\xac'}, + {'\xaa','\xed'},{'\xd0','\xae'},{'\xd0','\xad'},{'\xad','\x6d'},{'\x8c','\xdc'}, + {'\xd3','\xd1'},{'\x84','\x7c'},{'\xd3','\xd8'},{'\xb0','\x49'},{'\xd3','\xd6'}, + {'\xd3','\xd4'},{'\x00','\x00'},{'\xd3','\xdb'},{'\xd3','\xd2'},{'\xd3','\xd3'}, + {'\xb0','\x4a'},{'\x00','\x00'},{'\xb0','\x4e'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xd3','\xdc'},{'\xb0','\x4d'},{'\xd3','\xda'},{'\xd3','\xd7'},{'\xd3','\xd5'}, + {'\xb0','\x4b'},{'\xb0','\x4c'},{'\xd3','\xd9'},{'\x8b','\xbd'},{'\x88','\xd3'}, + {'\x00','\x00'},{'\xfe','\xc8'},{'\xb3','\x50'},{'\xd7','\xb2'},{'\x00','\x00'}, + {'\xb3','\x55'},{'\xd7','\xc2'},{'\xb3','\x54'},{'\xd7','\xc4'},{'\xfe','\xc9'}, + {'\xfe','\xca'},{'\xd7','\xb8'},{'\xb3','\x52'},{'\xd7','\xc3'},{'\x00','\x00'}, + {'\xd7','\xb3'},{'\xb3','\x53'},{'\xd7','\xbf'},{'\xd7','\xbb'},{'\xd7','\xbd'}, + {'\xd7','\xb7'},{'\xd7','\xbe'},{'\x90','\xba'},{'\x00','\x00'},{'\xb3','\x4f'}, + {'\xd7','\xba'},{'\xfd','\x56'},{'\xd7','\xb9'},{'\xd7','\xb5'},{'\x00','\x00'}, + {'\xd7','\xc0'},{'\x00','\x00'},{'\x00','\x00'},{'\xd7','\xbc'},{'\xd7','\xb4'}, + {'\x00','\x00'},{'\xd7','\xb6'},{'\xb3','\x51'},{'\xd7','\xc1'},{'\x8c','\xdb'}, + {'\x91','\x6a'},{'\x00','\x00'},{'\x94','\xce'},{'\xb5','\xf6'},{'\xdb','\xcd'}, + {'\x00','\x00'},{'\x95','\xdd'},{'\x91','\x6c'},{'\xdb','\xc9'},{'\xdb','\xcb'}, + {'\xdb','\xc6'},{'\xdb','\xc5'},{'\xdb','\xc3'},{'\x00','\x00'},{'\xdb','\xca'}, + {'\xdb','\xcc'},{'\xdb','\xc8'},{'\x91','\x6d'},{'\xdb','\xc7'},{'\xb5','\xf4'}, + {'\xb5','\xf5'},{'\x94','\xcf'},{'\x94','\xd0'},{'\x86','\x45'},{'\x8b','\xbc'}, + {'\xfb','\x63'},{'\x00','\x00'},{'\xdb','\xcf'},{'\xb8','\xcd'},{'\xdf','\xf2'}, + {'\xdf','\xf8'},{'\xdf','\xf3'},{'\xdf','\xf4'},{'\xf9','\xd8'},{'\xdf','\xf9'}, + {'\x00','\x00'},{'\xb8','\xcf'},{'\x00','\x00'},{'\xb8','\xc7'},{'\xb8','\xce'}, + {'\xdf','\xf1'},{'\xdb','\xc4'},{'\xb8','\xca'},{'\xb8','\xc8'},{'\xdf','\xf7'}, + {'\xdf','\xf6'},{'\xb8','\xc9'},{'\xb8','\xcb'},{'\xdf','\xf5'},{'\xb8','\xc6'}, + {'\x00','\x00'},{'\xb8','\xcc'},{'\x8f','\x62'},{'\x8f','\xc5'},{'\x89','\x5c'}, + {'\x91','\x6e'},{'\xfe','\xcb'},{'\xe3','\xf6'},{'\xbb','\x74'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xe4','\x42'},{'\xe4','\x41'},{'\x00','\x00'},{'\xe3','\xfb'}, + {'\xbb','\x76'},{'\xe4','\x40'},{'\xe3','\xf7'},{'\xe3','\xf8'},{'\xbb','\x6e'}, + {'\xbb','\x70'},{'\x91','\x6f'},{'\xe3','\xfd'},{'\xe3','\xf5'},{'\xbb','\x72'}, + {'\xbb','\x71'},{'\xe3','\xf9'},{'\xe3','\xfe'},{'\xe3','\xfc'},{'\xbb','\x73'}, + {'\xe3','\xfa'},{'\xfe','\xcc'},{'\xfe','\xcd'},{'\xdb','\xce'},{'\xbb','\x6f'}, + {'\x00','\x00'},{'\x94','\xd1'},{'\xe7','\xc2'},{'\xe7','\xc9'},{'\xbd','\xc6'}, + {'\x00','\x00'},{'\xe7','\xcd'},{'\xbd','\xca'},{'\xe7','\xc5'},{'\xe7','\xc3'}, + {'\x00','\x00'},{'\xe7','\xcc'},{'\x00','\x00'},{'\xbd','\xc5'},{'\xe7','\xcb'}, + {'\xbd','\xc7'},{'\xbd','\xc8'},{'\xe7','\xc4'},{'\xbd','\xc9'},{'\xe7','\xca'}, + {'\xe7','\xc6'},{'\xe7','\xc7'},{'\xe7','\xc8'},{'\xbb','\x75'},{'\x8a','\x63'}, + {'\x91','\x70'},{'\x91','\x71'},{'\xeb','\x70'},{'\xeb','\x7c'},{'\x00','\x00'}, + {'\xbf','\xca'},{'\xeb','\x77'},{'\xeb','\x79'},{'\xfe','\xce'},{'\xbf','\xc8'}, + {'\xeb','\x71'},{'\xeb','\x75'},{'\x00','\x00'},{'\xeb','\x78'},{'\xbf','\xc6'}, + {'\xbf','\xc9'},{'\xeb','\x7b'},{'\xeb','\x73'},{'\xeb','\x74'},{'\xeb','\x7a'}, + {'\xeb','\x72'},{'\xeb','\x76'},{'\xbf','\xc7'},{'\xee','\x72'},{'\x8c','\x53'}, + {'\xee','\x71'},{'\xc1','\xb7'},{'\xee','\x77'},{'\xc1','\xb9'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xc1','\xb6'},{'\xee','\x73'},{'\xc1','\xba'},{'\xee','\x74'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xee','\x75'},{'\xee','\x78'},{'\xfd','\x58'}, + {'\xc1','\xb8'},{'\x00','\x00'},{'\xf0','\xd6'},{'\xfe','\xcf'},{'\x00','\x00'}, + {'\xf0','\xd9'},{'\x00','\x00'},{'\xf0','\xd3'},{'\xf0','\xd5'},{'\xfd','\x59'}, + {'\x00','\x00'},{'\xf0','\xd4'},{'\xf0','\xd7'},{'\xf0','\xd8'},{'\xee','\x76'}, + {'\xf0','\xd2'},{'\xfe','\xd0'},{'\x00','\x00'},{'\xc3','\xcd'},{'\xf2','\xec'}, + {'\xf2','\xef'},{'\xf2','\xf1'},{'\xf2','\xea'},{'\xf2','\xeb'},{'\xf2','\xee'}, + {'\xf2','\xf0'},{'\xc3','\xce'},{'\xc3','\xcc'},{'\xc3','\xcb'},{'\xf2','\xed'}, + {'\xf2','\xe9'},{'\xf4','\xca'},{'\xc4','\xb0'},{'\xfe','\xd1'},{'\xf4','\xcb'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xf6','\x49'},{'\xc4','\xfb'},{'\xf6','\x4b'}, + {'\xc4','\xfc'},{'\xf6','\x48'},{'\xf6','\x4a'},{'\xc5','\xa8'},{'\x00','\x00'}, + {'\xf7','\x52'},{'\xc5','\xa7'},{'\xf7','\xfd'},{'\xf7','\xfc'},{'\x00','\x00'}, + {'\xf7','\xfb'},{'\x91','\x72'},{'\x00','\x00'},{'\xf9','\x48'},{'\xf9','\x49'}, + {'\xf9','\x4b'},{'\xf9','\x4a'},{'\x00','\x00'},{'\xca','\x50'},{'\xa6','\xe8'}, + {'\xfe','\xd2'},{'\xad','\x6e'},{'\xd7','\xc5'},{'\xb5','\xf7'},{'\x00','\x00'}, + {'\xdf','\xfa'},{'\xc2','\xd0'},{'\x95','\xf6'},{'\xf2','\xf2'},{'\xfd','\x6d'}, + {'\xfd','\x6e'},{'\xa8','\xa3'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb3','\x57'},{'\x00','\x00'},{'\xfe','\xd3'},{'\x00','\x00'},{'\xb3','\x56'}, + {'\xfd','\x6f'},{'\xdb','\xd0'},{'\xb5','\xf8'},{'\xdb','\xd2'},{'\xdb','\xd1'}, + {'\x00','\x00'},{'\x92','\x60'},{'\xdf','\xfb'},{'\xb8','\xd0'},{'\xe4','\x43'}, + {'\xe4','\x46'},{'\xe4','\x45'},{'\x00','\x00'},{'\xe4','\x44'},{'\xe7','\xce'}, + {'\xe7','\xd0'},{'\xe7','\xcf'},{'\xfb','\xaf'},{'\xbf','\xcc'},{'\x93','\xe1'}, + {'\x00','\x00'},{'\x95','\xc5'},{'\xbf','\xcb'},{'\x00','\x00'},{'\xc1','\xbb'}, + {'\xee','\x79'},{'\xee','\x7b'},{'\xee','\x7a'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc2','\xd1'},{'\x92','\x6d'},{'\x00','\x00'},{'\x00','\x00'},{'\xf2','\xf4'}, + {'\xf2','\xf3'},{'\x00','\x00'},{'\xf4','\xcc'},{'\xc4','\xb1'},{'\x00','\x00'}, + {'\xfd','\x71'},{'\xc4','\xfd'},{'\xf7','\x54'},{'\xf7','\x53'},{'\xc6','\x5b'}, + {'\x83','\x4e'},{'\x8d','\x73'},{'\x00','\x00'},{'\x84','\x7e'},{'\x84','\x7d'}, + {'\x85','\x53'},{'\x8d','\xe6'},{'\x8c','\xa6'},{'\x8c','\x54'},{'\x8a','\x64'}, + {'\x8e','\x7e'},{'\x90','\x5c'},{'\x00','\x00'},{'\x89','\x5e'},{'\x8f','\x63'}, + {'\x8a','\xfc'},{'\x8f','\xc6'},{'\xa8','\xa4'},{'\xd0','\xaf'},{'\xad','\x6f'}, + {'\xd7','\xc8'},{'\xd7','\xc6'},{'\x00','\x00'},{'\x00','\x00'},{'\xd7','\xc7'}, + {'\xdb','\xd4'},{'\xdb','\xd5'},{'\xe0','\x43'},{'\xdb','\xd3'},{'\x8a','\xfd'}, + {'\xdf','\xfc'},{'\xe0','\x41'},{'\xe0','\x40'},{'\xe0','\x42'},{'\xb8','\xd1'}, + {'\xdf','\xfe'},{'\xdf','\xfd'},{'\xe0','\x44'},{'\x91','\x73'},{'\xe4','\x49'}, + {'\xe4','\x47'},{'\x00','\x00'},{'\xe4','\x48'},{'\xe7','\xd3'},{'\xe7','\xd1'}, + {'\x00','\x00'},{'\x8f','\xc7'},{'\xe7','\xd2'},{'\xeb','\x7d'},{'\xee','\x7c'}, + {'\xee','\x7d'},{'\xc2','\xd2'},{'\x00','\x00'},{'\xf2','\xf5'},{'\xf4','\xcd'}, + {'\xc4','\xb2'},{'\x00','\x00'},{'\xf6','\x4c'},{'\xf7','\x55'},{'\xc5','\xa9'}, + {'\x00','\x00'},{'\xf7','\xfe'},{'\xf9','\x4c'},{'\xa8','\xa5'},{'\x00','\x00'}, + {'\xad','\x71'},{'\xad','\x72'},{'\xd0','\xb0'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xd0','\xb1'},{'\xad','\x70'},{'\x00','\x00'},{'\xb0','\x54'},{'\x00','\x00'}, + {'\xb0','\x52'},{'\x00','\x00'},{'\xb0','\x51'},{'\xb0','\x58'},{'\xb0','\x50'}, + {'\xb0','\x59'},{'\xd3','\xdd'},{'\xb0','\x56'},{'\x00','\x00'},{'\xb0','\x53'}, + {'\xb0','\x57'},{'\xb0','\x55'},{'\xb0','\x4f'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb3','\x5f'},{'\xfe','\xd4'},{'\xb3','\x59'},{'\xd7','\xcc'},{'\xb3','\x5e'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb3','\x60'},{'\xb3','\x5a'},{'\x00','\x00'}, + {'\xb3','\x5b'},{'\x00','\x00'},{'\xd7','\xca'},{'\x00','\x00'},{'\xfe','\xd5'}, + {'\xb3','\x58'},{'\xfe','\xd6'},{'\xd7','\xcb'},{'\xb3','\x5d'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd7','\xc9'},{'\xb3','\x5c'},{'\x00','\x00'},{'\x93','\xd5'}, + {'\xb6','\x44'},{'\x00','\x00'},{'\xb6','\x46'},{'\x91','\x74'},{'\xfe','\xd7'}, + {'\xdb','\xd8'},{'\xb6','\x45'},{'\xb5','\xf9'},{'\xb5','\xfd'},{'\xfe','\xd8'}, + {'\xb8','\xe4'},{'\xe0','\x49'},{'\xdb','\xda'},{'\xb5','\xfe'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xdb','\xdd'},{'\xdb','\xde'},{'\xb6','\x43'},{'\x00','\x00'}, + {'\xdb','\xe0'},{'\xfd','\x73'},{'\xdb','\xe2'},{'\x00','\x00'},{'\xdb','\xe3'}, + {'\xdb','\xd7'},{'\xdb','\xd6'},{'\xdb','\xe4'},{'\xb6','\x42'},{'\xdb','\xe1'}, + {'\xdb','\xdf'},{'\x00','\x00'},{'\xb6','\x40'},{'\xb5','\xfb'},{'\xb6','\x47'}, + {'\xdb','\xdb'},{'\xdb','\xdc'},{'\xdb','\xd9'},{'\x00','\x00'},{'\xb6','\x41'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb5','\xfc'},{'\x00','\x00'},{'\xb5','\xfa'}, + {'\xe0','\x48'},{'\xb8','\xdf'},{'\xb8','\xda'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb8','\xd5'},{'\xfc','\xda'},{'\xb8','\xe5'},{'\xb8','\xd6'},{'\x00','\x00'}, + {'\xb8','\xd2'},{'\xb8','\xe1'},{'\xb8','\xde'},{'\xb8','\xe0'},{'\x00','\x00'}, + {'\xb8','\xd7'},{'\xb8','\xdc'},{'\xb8','\xd3'},{'\xb8','\xd4'},{'\xe0','\x50'}, + {'\xe0','\x4d'},{'\xe0','\x45'},{'\xe0','\x4a'},{'\x00','\x00'},{'\xb8','\xe2'}, + {'\xe0','\x51'},{'\xb8','\xe3'},{'\xb8','\xd9'},{'\x00','\x00'},{'\xfd','\x72'}, + {'\xe0','\x47'},{'\x00','\x00'},{'\xe0','\x4f'},{'\xe0','\x4b'},{'\xe0','\x4e'}, + {'\xe0','\x4c'},{'\xb8','\xdd'},{'\xe0','\x46'},{'\xb8','\xd8'},{'\x00','\x00'}, + {'\x8c','\xa9'},{'\x8a','\x6c'},{'\xe4','\x4c'},{'\xbb','\x78'},{'\xbb','\x7b'}, + {'\x00','\x00'},{'\xe4','\x4e'},{'\xfe','\xda'},{'\xbb','\xa5'},{'\xe4','\x4d'}, + {'\xbb','\x7d'},{'\xfe','\xdb'},{'\xbd','\xcf'},{'\xe4','\x4f'},{'\x00','\x00'}, + {'\xbb','\xa4'},{'\xe4','\x4b'},{'\xbb','\xa6'},{'\x00','\x00'},{'\xfe','\xdc'}, + {'\x00','\x00'},{'\xbb','\x79'},{'\x00','\x00'},{'\xb8','\xdb'},{'\xbb','\x7c'}, + {'\x00','\x00'},{'\xbb','\x7a'},{'\xbb','\x7e'},{'\xbb','\xa2'},{'\xbb','\x77'}, + {'\xbb','\xa7'},{'\xbb','\xa3'},{'\xfe','\xdd'},{'\xbb','\xa1'},{'\xe4','\x4a'}, + {'\x91','\x75'},{'\x93','\xab'},{'\x00','\x00'},{'\xfe','\xde'},{'\xbd','\xd6'}, + {'\x00','\x00'},{'\xbd','\xd2'},{'\x00','\x00'},{'\xfe','\xdf'},{'\x00','\x00'}, + {'\xbd','\xd9'},{'\x00','\x00'},{'\xe7','\xd6'},{'\xbd','\xda'},{'\xe7','\xe2'}, + {'\xe7','\xdb'},{'\xbd','\xcb'},{'\xe7','\xe3'},{'\xe7','\xdd'},{'\xbd','\xd5'}, + {'\xe7','\xde'},{'\x00','\x00'},{'\xbd','\xd4'},{'\xe7','\xe1'},{'\xbd','\xce'}, + {'\xe7','\xdf'},{'\xe7','\xd5'},{'\xbd','\xcd'},{'\xeb','\xaa'},{'\xbd','\xd3'}, + {'\x00','\x00'},{'\xbd','\xd0'},{'\x82','\x51'},{'\xbd','\xd8'},{'\x00','\x00'}, + {'\xe7','\xd4'},{'\x00','\x00'},{'\xe7','\xd8'},{'\xbd','\xcc'},{'\xe7','\xd7'}, + {'\xe7','\xd9'},{'\xe7','\xda'},{'\xbd','\xd7'},{'\xe7','\xdc'},{'\xe7','\xe0'}, + {'\xe7','\xe4'},{'\x91','\x76'},{'\xbd','\xdb'},{'\xbf','\xd2'},{'\xeb','\xa5'}, + {'\xeb','\xab'},{'\xeb','\xa8'},{'\xeb','\x7e'},{'\xeb','\xac'},{'\xeb','\xa1'}, + {'\x00','\x00'},{'\xeb','\xa7'},{'\x00','\x00'},{'\xbf','\xcd'},{'\xbf','\xd3'}, + {'\xeb','\xad'},{'\x00','\x00'},{'\xfe','\xe0'},{'\xbf','\xcf'},{'\x00','\x00'}, + {'\xbf','\xd9'},{'\xbf','\xd4'},{'\xeb','\xaf'},{'\xeb','\xa9'},{'\xbf','\xd0'}, + {'\xeb','\xa2'},{'\xbf','\xda'},{'\xeb','\xa3'},{'\xeb','\xa4'},{'\xbf','\xdb'}, + {'\xbf','\xd8'},{'\xbd','\xd1'},{'\x9d','\xd1'},{'\xbf','\xce'},{'\xeb','\xb0'}, + {'\xbf','\xdc'},{'\x00','\x00'},{'\xbf','\xd5'},{'\xeb','\xae'},{'\xbf','\xd1'}, + {'\xbf','\xd6'},{'\xbf','\xd7'},{'\x00','\x00'},{'\xc1','\xc3'},{'\xee','\xa4'}, + {'\xee','\xad'},{'\xee','\xaa'},{'\xee','\xac'},{'\x00','\x00'},{'\xc1','\xc0'}, + {'\xee','\xa5'},{'\xfd','\x74'},{'\xee','\xab'},{'\xc1','\xbc'},{'\xee','\xa7'}, + {'\xc1','\xc4'},{'\xee','\xa3'},{'\xee','\xa8'},{'\xee','\xaf'},{'\xeb','\xa6'}, + {'\xee','\xa9'},{'\xee','\xa2'},{'\xc1','\xbd'},{'\xee','\xa1'},{'\xc1','\xbe'}, + {'\xee','\xb0'},{'\xc1','\xbf'},{'\xee','\xae'},{'\xc1','\xc2'},{'\xee','\x7e'}, + {'\xfe','\xe1'},{'\xc1','\xc1'},{'\x93','\xdc'},{'\xee','\xa6'},{'\xf0','\xdc'}, + {'\xf0','\xea'},{'\xf0','\xe5'},{'\xf0','\xe7'},{'\xf0','\xdb'},{'\xc2','\xd3'}, + {'\x00','\x00'},{'\xf0','\xda'},{'\xc2','\xd6'},{'\xc2','\xd5'},{'\x96','\xc1'}, + {'\xf0','\xe9'},{'\xf0','\xe1'},{'\xf0','\xde'},{'\xf0','\xe4'},{'\x00','\x00'}, + {'\xf0','\xdd'},{'\x00','\x00'},{'\xf0','\xdf'},{'\xf0','\xe8'},{'\xf0','\xe6'}, + {'\x00','\x00'},{'\xc2','\xd4'},{'\xf0','\xed'},{'\xf0','\xeb'},{'\xf0','\xe2'}, + {'\xf0','\xec'},{'\xf0','\xe3'},{'\xfe','\xe3'},{'\xf2','\xf9'},{'\xc3','\xcf'}, + {'\xf3','\x41'},{'\xfd','\x75'},{'\x00','\x00'},{'\xf6','\x4f'},{'\xc3','\xd6'}, + {'\xf0','\xe0'},{'\xf2','\xf7'},{'\xc3','\xd2'},{'\xf2','\xf8'},{'\xf2','\xfd'}, + {'\xfd','\x77'},{'\xfe','\xe4'},{'\xc3','\xd4'},{'\xc3','\xd5'},{'\xf2','\xf6'}, + {'\xf3','\x40'},{'\xf3','\x42'},{'\xf2','\xfa'},{'\xf2','\xfc'},{'\xf2','\xfe'}, + {'\xf2','\xfb'},{'\xf3','\x43'},{'\xc3','\xd1'},{'\xc3','\xd7'},{'\xc3','\xd3'}, + {'\x91','\x77'},{'\xc3','\xd0'},{'\xf4','\xd0'},{'\xfe','\xe5'},{'\xc4','\xb7'}, + {'\xf4','\xce'},{'\x00','\x00'},{'\xfe','\xe6'},{'\xf4','\xd2'},{'\x00','\x00'}, + {'\xf4','\xd3'},{'\xc4','\xb5'},{'\xf4','\xd4'},{'\xf4','\xd1'},{'\xfe','\xe7'}, + {'\xf4','\xcf'},{'\xc4','\xb8'},{'\xc4','\xb4'},{'\xf4','\xd5'},{'\x00','\x00'}, + {'\xc4','\xb6'},{'\xc4','\xb3'},{'\x91','\x78'},{'\x92','\xf0'},{'\x00','\x00'}, + {'\xc4','\xfe'},{'\x00','\x00'},{'\x00','\x00'},{'\xc5','\x40'},{'\xf6','\x4e'}, + {'\xf6','\x4d'},{'\xf6','\x50'},{'\xf6','\x51'},{'\x00','\x00'},{'\xc5','\x41'}, + {'\xf7','\x56'},{'\xf7','\x5b'},{'\xc5','\xaa'},{'\xfd','\x76'},{'\xf7','\x58'}, + {'\x82','\x63'},{'\xf7','\x57'},{'\xf7','\x5a'},{'\xf7','\x59'},{'\x00','\x00'}, + {'\xf8','\x43'},{'\x00','\x00'},{'\xc5','\xdc'},{'\xf8','\x42'},{'\xf8','\x40'}, + {'\x00','\x00'},{'\xf8','\x41'},{'\x00','\x00'},{'\x95','\xf8'},{'\x00','\x00'}, + {'\xc5','\xfe'},{'\xc5','\xfd'},{'\xf8','\xc1'},{'\xf8','\xc2'},{'\xc6','\x40'}, + {'\x00','\x00'},{'\xf9','\x4d'},{'\xf9','\x4e'},{'\xc6','\x67'},{'\xfe','\xe8'}, + {'\xc6','\x6d'},{'\x00','\x00'},{'\xf9','\xa9'},{'\xf9','\xc8'},{'\x9c','\xec'}, + {'\x83','\x79'},{'\x83','\x7a'},{'\x83','\x7b'},{'\x87','\x50'},{'\x8b','\xc2'}, + {'\x83','\xd4'},{'\x83','\xd6'},{'\x83','\xd5'},{'\x8d','\x58'},{'\x83','\xd7'}, + {'\x83','\xda'},{'\x00','\x00'},{'\x83','\xd9'},{'\x8c','\x56'},{'\x83','\xd8'}, + {'\x83','\xd3'},{'\x00','\x00'},{'\x8a','\x68'},{'\x89','\x62'},{'\x8f','\x7e'}, + {'\x8d','\xe7'},{'\x84','\xa2'},{'\x84','\xa4'},{'\x84','\xa5'},{'\x84','\xa8'}, + {'\x88','\x62'},{'\x00','\x00'},{'\x84','\xa7'},{'\x89','\x6a'},{'\x84','\xa6'}, + {'\x84','\xa1'},{'\x84','\xa3'},{'\x85','\x56'},{'\x85','\x57'},{'\x85','\x5e'}, + {'\x85','\x54'},{'\x85','\x59'},{'\x8b','\xbf'},{'\x00','\x00'},{'\x85','\x5a'}, + {'\x85','\x5c'},{'\x85','\x5d'},{'\x85','\x5b'},{'\x8f','\x65'},{'\x85','\x55'}, + {'\x8d','\xe8'},{'\x85','\x58'},{'\x00','\x00'},{'\x8c','\x57'},{'\x8d','\xe9'}, + {'\x8e','\x4f'},{'\x8e','\x52'},{'\x86','\x49'},{'\x8e','\x50'},{'\x86','\x4a'}, + {'\x86','\x4b'},{'\x86','\x4c'},{'\x86','\x4e'},{'\x86','\x50'},{'\x8e','\x53'}, + {'\x86','\x4f'},{'\x88','\x5a'},{'\x86','\x54'},{'\x86','\x53'},{'\x86','\x51'}, + {'\x86','\x52'},{'\x86','\x4d'},{'\x88','\x63'},{'\x86','\x47'},{'\x86','\x48'}, + {'\x86','\x46'},{'\x8e','\xf8'},{'\x8e','\x51'},{'\x00','\x00'},{'\x87','\x51'}, + {'\x87','\x4f'},{'\x87','\x4e'},{'\x87','\x58'},{'\x87','\x52'},{'\x87','\x54'}, + {'\x87','\x56'},{'\x87','\x55'},{'\x87','\x57'},{'\x87','\x53'},{'\x87','\x4d'}, + {'\x8e','\xa1'},{'\x88','\x5b'},{'\x88','\x5c'},{'\x8e','\xcb'},{'\x89','\x67'}, + {'\x8c','\xdd'},{'\x8e','\xcc'},{'\x88','\x65'},{'\x88','\x5d'},{'\x88','\x5e'}, + {'\x88','\x66'},{'\x88','\x61'},{'\x8e','\xcd'},{'\x88','\x60'},{'\x88','\x5f'}, + {'\x88','\x57'},{'\x88','\x59'},{'\x88','\x64'},{'\x88','\x58'},{'\x00','\x00'}, + {'\x88','\x56'},{'\x89','\x63'},{'\x89','\x6d'},{'\x89','\x64'},{'\x8a','\x69'}, + {'\x89','\x61'},{'\x89','\x65'},{'\x8e','\xf9'},{'\x89','\x68'},{'\x89','\x69'}, + {'\x8e','\xfa'},{'\x89','\x6b'},{'\x89','\x6e'},{'\x8d','\x59'},{'\x89','\x66'}, + {'\x89','\x6c'},{'\x89','\x60'},{'\x89','\x5f'},{'\x8a','\x65'},{'\x8e','\xfb'}, + {'\x00','\x00'},{'\x8a','\xfe'},{'\x8d','\xa4'},{'\x8f','\x64'},{'\x8a','\x6b'}, + {'\x8a','\x6a'},{'\x8a','\x66'},{'\x8f','\x66'},{'\x8a','\x67'},{'\x8a','\x6d'}, + {'\x8b','\x40'},{'\x8f','\xa1'},{'\x8b','\x42'},{'\x91','\x79'},{'\x8b','\x41'}, + {'\x8b','\xc0'},{'\x8f','\xc8'},{'\x8b','\xc3'},{'\x90','\x78'},{'\x8b','\xbe'}, + {'\x8b','\xc1'},{'\x90','\xa6'},{'\x8c','\xa7'},{'\x8c','\x58'},{'\x8d','\x5a'}, + {'\xa8','\xa6'},{'\x00','\x00'},{'\xd7','\xcd'},{'\x91','\x7a'},{'\xd7','\xce'}, + {'\xe0','\x52'},{'\xe4','\x50'},{'\xe7','\xe5'},{'\xc1','\xc6'},{'\x00','\x00'}, + {'\xc1','\xc5'},{'\xf0','\xee'},{'\xf3','\x44'},{'\x00','\x00'},{'\xf8','\x44'}, + {'\xa8','\xa7'},{'\xd3','\xde'},{'\xb0','\x5a'},{'\xb3','\x61'},{'\xe0','\x54'}, + {'\xe0','\x53'},{'\xbd','\xdc'},{'\xe7','\xe6'},{'\xbd','\xdd'},{'\xee','\xb1'}, + {'\xc2','\xd7'},{'\xfe','\xe9'},{'\x00','\x00'},{'\x00','\x00'},{'\xc6','\x76'}, + {'\xa8','\xa8'},{'\xcd','\xcb'},{'\xd3','\xdf'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb3','\x62'},{'\x00','\x00'},{'\xd7','\xcf'},{'\xd7','\xd0'},{'\x00','\x00'}, + {'\xdb','\xe5'},{'\x00','\x00'},{'\xb6','\x48'},{'\xb8','\xe6'},{'\x00','\x00'}, + {'\xe0','\x56'},{'\xe0','\x55'},{'\xe0','\x57'},{'\x00','\x00'},{'\xe4','\x51'}, + {'\xe4','\x52'},{'\xbb','\xa8'},{'\xbf','\xdd'},{'\xbd','\xde'},{'\xbf','\xde'}, + {'\x00','\x00'},{'\xee','\xb5'},{'\xee','\xb2'},{'\xee','\xb4'},{'\xee','\xb3'}, + {'\xc1','\xc7'},{'\x00','\x00'},{'\xf0','\xef'},{'\xf3','\x46'},{'\xf3','\x45'}, + {'\xcb','\xa4'},{'\xb0','\x5c'},{'\xb0','\x5b'},{'\xd3','\xe0'},{'\x91','\x7b'}, + {'\xd7','\xd1'},{'\x00','\x00'},{'\x00','\x00'},{'\xdb','\xe7'},{'\xdb','\xe6'}, + {'\xb6','\x49'},{'\x00','\x00'},{'\xe0','\x59'},{'\xe0','\x5a'},{'\xe0','\x58'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xb8','\xe8'},{'\xb8','\xe7'},{'\x00','\x00'}, + {'\xbb','\xaa'},{'\xbb','\xa9'},{'\x91','\x7c'},{'\xe7','\xe7'},{'\xeb','\xb3'}, + {'\xeb','\xb1'},{'\xeb','\xb2'},{'\xbf','\xdf'},{'\xee','\xb7'},{'\xee','\xb6'}, + {'\x00','\x00'},{'\xf0','\xf2'},{'\xf0','\xf1'},{'\xf0','\xf0'},{'\xf3','\x47'}, + {'\xfe','\xea'},{'\xf9','\xaa'},{'\xa8','\xa9'},{'\xad','\x73'},{'\xfe','\xeb'}, + {'\xad','\x74'},{'\xb0','\x5d'},{'\xb0','\x5e'},{'\xd3','\xe2'},{'\xd3','\xe1'}, + {'\xd7','\xd2'},{'\x00','\x00'},{'\xb3','\x68'},{'\xb3','\x66'},{'\xb3','\x63'}, + {'\xb3','\x67'},{'\xb3','\x65'},{'\xb3','\x64'},{'\xfd','\x79'},{'\x91','\x7d'}, + {'\xb6','\x4a'},{'\xdb','\xea'},{'\x00','\x00'},{'\xb8','\xed'},{'\xb6','\x4c'}, + {'\xb6','\x51'},{'\xdb','\xec'},{'\xb6','\x53'},{'\xb6','\x52'},{'\xb6','\x55'}, + {'\xdb','\xeb'},{'\xdb','\xe8'},{'\xb6','\x4f'},{'\xb6','\x4b'},{'\xb6','\x4d'}, + {'\xdb','\xe9'},{'\xb6','\x54'},{'\xb6','\x50'},{'\xb6','\x4e'},{'\xb8','\xef'}, + {'\xb8','\xee'},{'\xb8','\xec'},{'\xb8','\xf0'},{'\x00','\x00'},{'\xb8','\xea'}, + {'\xb8','\xeb'},{'\x00','\x00'},{'\xb8','\xe9'},{'\x00','\x00'},{'\xe0','\x5b'}, + {'\x95','\x60'},{'\x82','\x62'},{'\xe4','\x54'},{'\x00','\x00'},{'\xbb','\xac'}, + {'\xbb','\xad'},{'\xbb','\xab'},{'\xfe','\xec'},{'\xe4','\x53'},{'\xfe','\xed'}, + {'\xe4','\x55'},{'\x00','\x00'},{'\xe7','\xea'},{'\xe7','\xec'},{'\x92','\xce'}, + {'\xbd','\xe7'},{'\xe7','\xed'},{'\xbd','\xe0'},{'\xe7','\xe9'},{'\xbd','\xdf'}, + {'\xbd','\xe9'},{'\xbd','\xe5'},{'\xbd','\xe6'},{'\xbd','\xe2'},{'\xe7','\xe8'}, + {'\xbd','\xe1'},{'\xe7','\xee'},{'\xe7','\xeb'},{'\x9e','\x40'},{'\xbd','\xe8'}, + {'\xfd','\x7a'},{'\xbd','\xe3'},{'\xbd','\xe4'},{'\xeb','\xb5'},{'\x00','\x00'}, + {'\xeb','\xb7'},{'\xeb','\xb6'},{'\x9e','\x41'},{'\xeb','\xb8'},{'\xbf','\xe0'}, + {'\xeb','\xb4'},{'\x00','\x00'},{'\xfd','\x7b'},{'\xc1','\xcb'},{'\xee','\xb8'}, + {'\xc1','\xc8'},{'\xc1','\xcc'},{'\xc1','\xca'},{'\xc1','\xc9'},{'\xf0','\xf3'}, + {'\x00','\x00'},{'\xf0','\xf6'},{'\x00','\x00'},{'\xf0','\xf5'},{'\x9e','\x42'}, + {'\xf0','\xf4'},{'\xc2','\xd8'},{'\xf3','\x48'},{'\xf3','\x49'},{'\xc3','\xd8'}, + {'\xf3','\x4a'},{'\xc3','\xd9'},{'\x82','\x57'},{'\xfd','\x7c'},{'\xc4','\xba'}, + {'\x00','\x00'},{'\xc4','\xb9'},{'\xf6','\x52'},{'\x9e','\x43'},{'\x91','\x7e'}, + {'\xc5','\x42'},{'\xf6','\x53'},{'\xf7','\x5c'},{'\xc5','\xab'},{'\xc5','\xac'}, + {'\x95','\x76'},{'\xf8','\x45'},{'\x00','\x00'},{'\xc6','\x42'},{'\x9e','\x44'}, + {'\x83','\x50'},{'\x83','\x7c'},{'\x83','\x7d'},{'\x00','\x00'},{'\x83','\xdd'}, + {'\x83','\xdc'},{'\x84','\xaa'},{'\x88','\x6e'},{'\x84','\x50'},{'\x88','\x6c'}, + {'\x84','\xac'},{'\x88','\x71'},{'\x84','\xa9'},{'\x84','\xad'},{'\x84','\xae'}, + {'\x85','\x68'},{'\x8a','\x70'},{'\x85','\x5f'},{'\x84','\xab'},{'\x85','\x61'}, + {'\x88','\x6b'},{'\x85','\x63'},{'\x8d','\xeb'},{'\x85','\x60'},{'\x85','\x66'}, + {'\x8d','\xea'},{'\x85','\x6a'},{'\x85','\x69'},{'\x85','\x64'},{'\x85','\x65'}, + {'\x85','\x62'},{'\x86','\x55'},{'\x8f','\xa3'},{'\x86','\x57'},{'\x86','\x58'}, + {'\x86','\x59'},{'\x86','\x5a'},{'\x86','\x5b'},{'\x8c','\xaa'},{'\x86','\x56'}, + {'\x86','\x5c'},{'\x90','\x47'},{'\x8e','\xa2'},{'\x87','\x5a'},{'\x91','\xa1'}, + {'\x87','\x5b'},{'\x88','\x6a'},{'\x88','\x6d'},{'\x91','\xa2'},{'\x8c','\xde'}, + {'\x88','\x69'},{'\x88','\x70'},{'\x00','\x00'},{'\x00','\x00'},{'\x88','\x72'}, + {'\x88','\x68'},{'\x8e','\xce'},{'\x89','\x6f'},{'\x00','\x00'},{'\x8b','\x43'}, + {'\x8a','\x71'},{'\x8a','\x6e'},{'\x8a','\x6f'},{'\x8f','\xa2'},{'\x8c','\xdf'}, + {'\x8b','\xc5'},{'\x00','\x00'},{'\x8b','\xc4'},{'\x8c','\x5a'},{'\x8c','\x59'}, + {'\x8d','\x5c'},{'\xa8','\xaa'},{'\x00','\x00'},{'\xb3','\x6a'},{'\xb3','\x69'}, + {'\xe0','\x5c'},{'\xe0','\x5d'},{'\x00','\x00'},{'\xbb','\xae'},{'\xeb','\xb9'}, + {'\xbd','\xea'},{'\xeb','\xba'},{'\xee','\xb9'},{'\xa8','\xab'},{'\x91','\xa3'}, + {'\xd0','\xb2'},{'\xad','\x76'},{'\xad','\x75'},{'\x87','\x5c'},{'\xd3','\xe3'}, + {'\xb0','\x5f'},{'\xd3','\xe4'},{'\xd7','\xd5'},{'\x9e','\x45'},{'\xd7','\xd4'}, + {'\x00','\x00'},{'\xd7','\xd3'},{'\x00','\x00'},{'\x00','\x00'},{'\xdb','\xee'}, + {'\xb6','\x58'},{'\xfd','\x7d'},{'\x00','\x00'},{'\xdb','\xed'},{'\xb6','\x57'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xdb','\xef'},{'\xb6','\x56'}, + {'\x8a','\x72'},{'\xe0','\x5f'},{'\xe0','\x62'},{'\xe0','\x60'},{'\xe0','\x61'}, + {'\xe0','\x65'},{'\xe0','\x5e'},{'\xe0','\x66'},{'\xe0','\x63'},{'\xe0','\x64'}, + {'\xbb','\xb0'},{'\xe4','\x56'},{'\x00','\x00'},{'\x00','\x00'},{'\xbb','\xaf'}, + {'\x00','\x00'},{'\xe7','\xf2'},{'\xe7','\xf0'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xbd','\xeb'},{'\xe7','\xef'},{'\xe7','\xf1'},{'\x00','\x00'},{'\xbd','\xec'}, + {'\x00','\x00'},{'\xeb','\xbb'},{'\xfd','\x7e'},{'\xeb','\xbc'},{'\xc1','\xcd'}, + {'\x9e','\x46'},{'\xf3','\x4c'},{'\xf3','\x4e'},{'\xf3','\x4b'},{'\xf3','\x4d'}, + {'\xf4','\xd6'},{'\xf6','\x54'},{'\x00','\x00'},{'\x90','\xa3'},{'\xf9','\x6f'}, + {'\xa8','\xac'},{'\xad','\x77'},{'\xd3','\xe5'},{'\xd3','\xe7'},{'\xd3','\xe6'}, + {'\x8c','\x5b'},{'\xd7','\xd8'},{'\xb3','\x6c'},{'\x00','\x00'},{'\xd7','\xd6'}, + {'\x00','\x00'},{'\xb3','\x6b'},{'\xd7','\xd9'},{'\x9e','\x47'},{'\xd7','\xda'}, + {'\xd7','\xd7'},{'\x8c','\xac'},{'\x8f','\x67'},{'\xdb','\xfb'},{'\xb6','\x60'}, + {'\xdb','\xf3'},{'\xdb','\xf9'},{'\x00','\x00'},{'\x00','\x00'},{'\xb6','\x5b'}, + {'\xb6','\x5e'},{'\xdb','\xf2'},{'\xb6','\x59'},{'\xdb','\xf6'},{'\xe0','\x6c'}, + {'\xb6','\x5d'},{'\x00','\x00'},{'\xdb','\xf1'},{'\xfd','\xa1'},{'\xdb','\xf7'}, + {'\xdb','\xf4'},{'\xdb','\xfa'},{'\xdb','\xf0'},{'\xdb','\xf8'},{'\xb6','\x5c'}, + {'\xb6','\x5f'},{'\xdb','\xf5'},{'\xb6','\x5a'},{'\x90','\x5e'},{'\xb8','\xf2'}, + {'\xe0','\x68'},{'\xb8','\xf1'},{'\xe0','\x6f'},{'\xe0','\x6e'},{'\xb8','\xf8'}, + {'\x00','\x00'},{'\xb8','\xf9'},{'\xe0','\x70'},{'\xb8','\xf3'},{'\xe0','\x6d'}, + {'\xb8','\xf7'},{'\xe0','\x72'},{'\xe0','\x69'},{'\x00','\x00'},{'\xe0','\x6b'}, + {'\xb8','\xf4'},{'\xe0','\x67'},{'\xe0','\x6a'},{'\xe0','\x71'},{'\xb8','\xf5'}, + {'\xe0','\x73'},{'\x88','\x73'},{'\x00','\x00'},{'\x8b','\xc6'},{'\x8b','\x46'}, + {'\x90','\x5d'},{'\xb8','\xf6'},{'\x8c','\xad'},{'\xbb','\xb1'},{'\xe4','\x5b'}, + {'\xe4','\x61'},{'\xe4','\x59'},{'\xe4','\x62'},{'\x9e','\x48'},{'\xe4','\x58'}, + {'\xe4','\x5d'},{'\xe4','\x63'},{'\xe4','\x60'},{'\xe4','\x5f'},{'\xe4','\x5e'}, + {'\x91','\xa4'},{'\xe4','\x57'},{'\xe4','\x5c'},{'\x00','\x00'},{'\x8c','\xab'}, + {'\xe4','\x5a'},{'\x9e','\x49'},{'\xbd','\xf1'},{'\xbd','\xee'},{'\xe7','\xfb'}, + {'\xe8','\x41'},{'\xe8','\x43'},{'\xe8','\x40'},{'\xe7','\xf8'},{'\xe7','\xfa'}, + {'\xe8','\x45'},{'\xe8','\x42'},{'\xe7','\xfc'},{'\xe8','\x46'},{'\xe7','\xf9'}, + {'\xe8','\x44'},{'\xbd','\xef'},{'\xbd','\xf5'},{'\xbd','\xf3'},{'\xe7','\xf3'}, + {'\xbd','\xf4'},{'\xbd','\xf0'},{'\xe7','\xf4'},{'\xe7','\xf6'},{'\xe7','\xf5'}, + {'\xe7','\xfd'},{'\xe7','\xfe'},{'\xfd','\xa2'},{'\xbd','\xf2'},{'\x95','\x57'}, + {'\xbd','\xed'},{'\x8c','\xe1'},{'\xfb','\x6d'},{'\xe7','\xf7'},{'\x8c','\xe0'}, + {'\xeb','\xc6'},{'\xbf','\xe2'},{'\x00','\x00'},{'\xeb','\xbd'},{'\xbf','\xe3'}, + {'\xbf','\xe6'},{'\xeb','\xc2'},{'\x00','\x00'},{'\xeb','\xbf'},{'\xbf','\xe5'}, + {'\x91','\xa5'},{'\x00','\x00'},{'\xeb','\xc3'},{'\xeb','\xc4'},{'\xeb','\xbe'}, + {'\xeb','\xc7'},{'\xeb','\xc0'},{'\xeb','\xc5'},{'\xbf','\xe4'},{'\x00','\x00'}, + {'\xbf','\xe1'},{'\xeb','\xc1'},{'\x9e','\x4a'},{'\xee','\xbf'},{'\xc1','\xd0'}, + {'\xc1','\xce'},{'\xc1','\xd1'},{'\xc1','\xcf'},{'\xee','\xbe'},{'\xee','\xbb'}, + {'\xee','\xba'},{'\xfd','\xa3'},{'\xee','\xbd'},{'\x8d','\x74'},{'\x8b','\x44'}, + {'\xee','\xbc'},{'\xf1','\x45'},{'\xc2','\xde'},{'\xf0','\xfb'},{'\xf0','\xfa'}, + {'\x00','\x00'},{'\xc2','\xd9'},{'\xf1','\x41'},{'\xf1','\x40'},{'\xf0','\xf7'}, + {'\xf1','\x43'},{'\xf0','\xfc'},{'\xc2','\xdd'},{'\xf0','\xf9'},{'\xf1','\x42'}, + {'\xf0','\xf8'},{'\xc2','\xda'},{'\xc2','\xdc'},{'\xf0','\xfd'},{'\xc2','\xdb'}, + {'\xf0','\xfe'},{'\x9e','\x4b'},{'\xf1','\x44'},{'\xf3','\x52'},{'\x00','\x00'}, + {'\xc3','\xde'},{'\xf3','\x4f'},{'\x00','\x00'},{'\xf3','\x53'},{'\x91','\xa6'}, + {'\x9e','\x4c'},{'\xc3','\xdb'},{'\xf3','\x51'},{'\xc3','\xe0'},{'\xfd','\xa5'}, + {'\xc3','\xdd'},{'\xfd','\xa4'},{'\xf3','\x50'},{'\x00','\x00'},{'\xc3','\xdf'}, + {'\xf3','\x54'},{'\xc3','\xda'},{'\x00','\x00'},{'\x9e','\x4d'},{'\x90','\x7e'}, + {'\x9e','\x4e'},{'\xc4','\xbc'},{'\xc4','\xbe'},{'\x00','\x00'},{'\xf4','\xd9'}, + {'\xc4','\xbd'},{'\xf4','\xd7'},{'\xc3','\xdc'},{'\xf4','\xd8'},{'\xc4','\xbb'}, + {'\xc5','\x43'},{'\xc5','\x45'},{'\xf6','\x56'},{'\xc5','\x44'},{'\xf6','\x55'}, + {'\x8d','\xa5'},{'\xf7','\x61'},{'\xc5','\xad'},{'\xf7','\x60'},{'\xc5','\xae'}, + {'\xf7','\x5e'},{'\xf7','\x5d'},{'\xf7','\x62'},{'\xf7','\x63'},{'\xf8','\x46'}, + {'\x91','\xa7'},{'\xf7','\x5f'},{'\x00','\x00'},{'\x90','\xa4'},{'\xf8','\xc6'}, + {'\xf8','\xc3'},{'\xf8','\xc4'},{'\xf8','\xc5'},{'\xc6','\x5c'},{'\x00','\x00'}, + {'\xf9','\x51'},{'\xf9','\x50'},{'\xf9','\x4f'},{'\xf9','\x70'},{'\xfd','\xa6'}, + {'\xf9','\xbe'},{'\xf9','\xab'},{'\xc6','\x6e'},{'\xa8','\xad'},{'\xb0','\x60'}, + {'\x95','\xdf'},{'\x00','\x00'},{'\x82','\x49'},{'\x91','\xa8'},{'\x91','\xa9'}, + {'\xb8','\xfa'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9e','\x4f'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9e','\x50'},{'\xbd','\xf6'},{'\x00','\x00'}, + {'\x9e','\x51'},{'\xeb','\xc8'},{'\x94','\xd3'},{'\x00','\x00'},{'\xc2','\xdf'}, + {'\x00','\x00'},{'\xf3','\x55'},{'\x9e','\x52'},{'\x00','\x00'},{'\x91','\xaa'}, + {'\x91','\xab'},{'\x00','\x00'},{'\x94','\xd4'},{'\xf9','\xac'},{'\xa8','\xae'}, + {'\xaa','\xee'},{'\xad','\x79'},{'\xad','\x78'},{'\x91','\xac'},{'\xb0','\x63'}, + {'\x00','\x00'},{'\xd3','\xe8'},{'\xb0','\x61'},{'\xd3','\xe9'},{'\xb0','\x62'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xd7','\xdf'},{'\xd7','\xdb'},{'\x00','\x00'}, + {'\xfb','\xa1'},{'\xb3','\x6d'},{'\xd7','\xde'},{'\xd7','\xdd'},{'\xd7','\xdc'}, + {'\xb3','\x6e'},{'\xd7','\xe0'},{'\xd7','\xe1'},{'\x93','\x7d'},{'\x91','\xad'}, + {'\x9e','\x53'},{'\xdc','\x43'},{'\xdc','\x41'},{'\xdc','\x45'},{'\xdc','\x46'}, + {'\xdc','\x4c'},{'\x00','\x00'},{'\xdc','\x48'},{'\xdc','\x4a'},{'\x9e','\x54'}, + {'\xdc','\x42'},{'\xdb','\xfc'},{'\x00','\x00'},{'\xdc','\x49'},{'\x9e','\x55'}, + {'\x00','\x00'},{'\xdc','\x4b'},{'\xdc','\x44'},{'\xdc','\x47'},{'\xdb','\xfd'}, + {'\xb6','\x62'},{'\xdc','\x40'},{'\xdb','\xfe'},{'\xb6','\x61'},{'\xb6','\x63'}, + {'\x92','\xad'},{'\xb8','\xfd'},{'\xe0','\x75'},{'\xe0','\x77'},{'\xe0','\x76'}, + {'\xe0','\x7b'},{'\xb8','\xfb'},{'\x00','\x00'},{'\xe0','\x78'},{'\xe0','\x74'}, + {'\xe0','\x79'},{'\xe0','\x7a'},{'\xb8','\xfc'},{'\xb8','\xfe'},{'\xe0','\x7c'}, + {'\x91','\xae'},{'\xe4','\x67'},{'\xe4','\x66'},{'\x00','\x00'},{'\xe4','\x64'}, + {'\xe4','\x65'},{'\xbb','\xb3'},{'\xbb','\xb5'},{'\xbb','\xb2'},{'\xbb','\xb4'}, + {'\xe8','\x4d'},{'\xe8','\x4e'},{'\xe8','\x49'},{'\xfd','\xa7'},{'\xe8','\x4a'}, + {'\xbd','\xf8'},{'\xbd','\xfd'},{'\xbd','\xf7'},{'\xbd','\xfe'},{'\xbd','\xf9'}, + {'\xe8','\x4b'},{'\x00','\x00'},{'\x00','\x00'},{'\xe8','\x4c'},{'\xe8','\x48'}, + {'\xbe','\x40'},{'\xbd','\xfb'},{'\x00','\x00'},{'\x00','\x00'},{'\xbd','\xfa'}, + {'\xbd','\xfc'},{'\x00','\x00'},{'\xe8','\x47'},{'\x95','\x70'},{'\xeb','\xca'}, + {'\xbf','\xe8'},{'\x9e','\x56'},{'\x00','\x00'},{'\xeb','\xcc'},{'\xbf','\xea'}, + {'\xeb','\xcf'},{'\xeb','\xcb'},{'\xeb','\xc9'},{'\xeb','\xce'},{'\xbf','\xe9'}, + {'\xeb','\xcd'},{'\x00','\x00'},{'\xbf','\xe7'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc1','\xd3'},{'\xc1','\xd6'},{'\xee','\xc1'},{'\x9e','\x57'},{'\xc1','\xd4'}, + {'\xee','\xc0'},{'\xc1','\xd2'},{'\xc1','\xd5'},{'\xf1','\x46'},{'\xf1','\x47'}, + {'\xf1','\x48'},{'\xc2','\xe0'},{'\x9e','\x58'},{'\xf1','\x49'},{'\x94','\xd5'}, + {'\xc2','\xe1'},{'\xc3','\xe2'},{'\xf3','\x58'},{'\xf3','\x59'},{'\xf3','\x57'}, + {'\xf3','\x56'},{'\xf3','\x5a'},{'\xc3','\xe1'},{'\xf4','\xdd'},{'\xf4','\xdb'}, + {'\xf4','\xdc'},{'\xf4','\xde'},{'\xf4','\xda'},{'\xf4','\xdf'},{'\xf6','\x58'}, + {'\xfd','\xa9'},{'\xf6','\x59'},{'\xf6','\x57'},{'\xc5','\x46'},{'\xf7','\x64'}, + {'\xc5','\xaf'},{'\xf7','\x65'},{'\xf8','\x48'},{'\xf8','\x47'},{'\x00','\x00'}, + {'\x83','\x51'},{'\x83','\x61'},{'\x83','\xa1'},{'\x83','\xde'},{'\x00','\x00'}, + {'\x83','\xdf'},{'\x8b','\x48'},{'\x84','\xaf'},{'\x88','\x79'},{'\x84','\xb0'}, + {'\x8c','\xae'},{'\x91','\xaf'},{'\x85','\x6b'},{'\x90','\x6e'},{'\x85','\x6c'}, + {'\x8d','\xed'},{'\x85','\x6d'},{'\x91','\xb0'},{'\x8d','\xee'},{'\x90','\x5f'}, + {'\x8d','\xec'},{'\x87','\x60'},{'\x86','\x5f'},{'\x86','\x5e'},{'\x86','\x60'}, + {'\x8b','\xc8'},{'\x00','\x00'},{'\x8e','\x56'},{'\x8e','\x55'},{'\x86','\x5d'}, + {'\x87','\x5f'},{'\x87','\x5e'},{'\x88','\x75'},{'\x88','\x78'},{'\x88','\x77'}, + {'\x88','\x74'},{'\x88','\x7c'},{'\x88','\x7b'},{'\x00','\x00'},{'\x88','\x76'}, + {'\x88','\x7a'},{'\x89','\x73'},{'\x89','\x70'},{'\x89','\x71'},{'\x00','\x00'}, + {'\x89','\x72'},{'\x8c','\xe2'},{'\x8a','\x76'},{'\x8a','\x73'},{'\x8a','\x74'}, + {'\x8f','\xa4'},{'\x8b','\x49'},{'\x8b','\xc7'},{'\xa8','\xaf'},{'\xb6','\x64'}, + {'\x00','\x00'},{'\x8b','\xc9'},{'\xb9','\x40'},{'\xfd','\x41'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xbb','\xb6'},{'\x00','\x00'},{'\x9e','\x59'},{'\xbf','\xec'}, + {'\x91','\xb1'},{'\xbf','\xeb'},{'\x8c','\xaf'},{'\x00','\x00'},{'\x8c','\x47'}, + {'\x00','\x00'},{'\xc3','\xe3'},{'\xc4','\x7c'},{'\xc5','\x47'},{'\xa8','\xb0'}, + {'\xb0','\x64'},{'\xb9','\x41'},{'\x9e','\x5a'},{'\xf3','\x5b'},{'\xc6','\xd6'}, + {'\x9c','\xe0'},{'\x94','\xd6'},{'\x9e','\x5b'},{'\x8b','\xca'},{'\x93','\xc3'}, + {'\x94','\x4e'},{'\x94','\x44'},{'\x89','\x77'},{'\x86','\x63'},{'\xcb','\xa6'}, + {'\x00','\x00'},{'\x88','\x7e'},{'\xa8','\xb1'},{'\x00','\x00'},{'\xa8','\xb4'}, + {'\xa8','\xb3'},{'\xa8','\xb2'},{'\x86','\x65'},{'\x8a','\x79'},{'\xcb','\xa5'}, + {'\x9e','\x5c'},{'\xcd','\xcd'},{'\xa0','\xa4'},{'\xcd','\xcf'},{'\xaa','\xef'}, + {'\x9e','\x5d'},{'\x86','\x62'},{'\xaa','\xf1'},{'\xcd','\xcc'},{'\xcd','\xce'}, + {'\xaa','\xf0'},{'\xcd','\xd1'},{'\xcd','\xd0'},{'\xcd','\xd2'},{'\x8a','\x78'}, + {'\x84','\xb1'},{'\x94','\xd7'},{'\x85','\x6e'},{'\x87','\x61'},{'\x86','\x64'}, + {'\x84','\xb2'},{'\x89','\x76'},{'\xd0','\xb6'},{'\xd0','\xb4'},{'\xad','\x7c'}, + {'\xd0','\xb3'},{'\xad','\xa3'},{'\xad','\x7e'},{'\xad','\x7b'},{'\x00','\x00'}, + {'\xad','\xa4'},{'\x8b','\x4a'},{'\xad','\x7d'},{'\xad','\xa2'},{'\x00','\x00'}, + {'\xad','\xa1'},{'\xd0','\xb5'},{'\x91','\xb2'},{'\xad','\x7a'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x84','\xb3'},{'\xb0','\x6a'},{'\xd3','\xeb'},{'\xd3','\xf1'}, + {'\xb0','\x67'},{'\xb0','\x6e'},{'\x95','\xd9'},{'\xb0','\x69'},{'\xd3','\xee'}, + {'\xd3','\xf0'},{'\xb0','\x6c'},{'\xd3','\xea'},{'\xd3','\xed'},{'\xb0','\x68'}, + {'\xb0','\x65'},{'\xd3','\xec'},{'\xb0','\x6b'},{'\xd3','\xef'},{'\xb0','\x6d'}, + {'\xb0','\x66'},{'\x00','\x00'},{'\x9e','\x5e'},{'\x89','\x75'},{'\x87','\x62'}, + {'\xd7','\xe3'},{'\xd7','\xe6'},{'\xb3','\x70'},{'\x91','\xb3'},{'\xb3','\x7a'}, + {'\xb3','\x76'},{'\xd7','\xe4'},{'\x87','\x63'},{'\x93','\x7a'},{'\xb3','\x7e'}, + {'\xb3','\x77'},{'\xb3','\x7c'},{'\xb3','\x72'},{'\x00','\x00'},{'\xb3','\x6f'}, + {'\xb3','\x71'},{'\xb3','\x7d'},{'\xd7','\xe5'},{'\xb3','\x75'},{'\xb3','\x78'}, + {'\xb3','\x74'},{'\xb3','\x79'},{'\xd7','\xe7'},{'\xb3','\x7b'},{'\xb3','\x73'}, + {'\xd7','\xe2'},{'\x00','\x00'},{'\x8d','\x41'},{'\x94','\xd8'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xdc','\x4d'}, + {'\xb6','\x65'},{'\xdc','\x4f'},{'\x00','\x00'},{'\xb6','\x67'},{'\xb6','\x69'}, + {'\x9e','\x5f'},{'\xdc','\x4e'},{'\xb6','\x66'},{'\xb6','\x6a'},{'\x9e','\x60'}, + {'\xb6','\x68'},{'\x91','\xb4'},{'\x00','\x00'},{'\x8d','\x42'},{'\xb9','\x47'}, + {'\xe0','\xa3'},{'\xb9','\x4f'},{'\xe0','\x7e'},{'\x00','\x00'},{'\xb9','\x50'}, + {'\xb9','\x45'},{'\x00','\x00'},{'\xe0','\xa1'},{'\x93','\x72'},{'\x00','\x00'}, + {'\xb9','\x4a'},{'\x00','\x00'},{'\xe0','\xa2'},{'\xb9','\x43'},{'\xb9','\x42'}, + {'\xfd','\xb6'},{'\xb9','\x4d'},{'\xb9','\x4c'},{'\xb9','\x4b'},{'\xb9','\x49'}, + {'\xb9','\x4e'},{'\xe0','\x7d'},{'\xb9','\x44'},{'\xb9','\x46'},{'\xb9','\x48'}, + {'\xfd','\xb5'},{'\x89','\x78'},{'\xbb','\xb8'},{'\xbb','\xbb'},{'\x00','\x00'}, + {'\xbb','\xbf'},{'\xbb','\xb9'},{'\xbb','\xbe'},{'\xbb','\xbc'},{'\x00','\x00'}, + {'\xbb','\xb7'},{'\xfe','\x61'},{'\xbb','\xbd'},{'\xbb','\xba'},{'\x9e','\x61'}, + {'\x91','\xb5'},{'\x00','\x00'},{'\xe8','\x52'},{'\xbe','\x43'},{'\xbe','\x41'}, + {'\x00','\x00'},{'\xe8','\x53'},{'\x9e','\x62'},{'\xbe','\x44'},{'\xbe','\x42'}, + {'\xe8','\x51'},{'\xe8','\x50'},{'\x00','\x00'},{'\xbf','\xf0'},{'\xe8','\x4f'}, + {'\xbf','\xee'},{'\xbf','\xed'},{'\xeb','\xd0'},{'\xbe','\x45'},{'\xbf','\xef'}, + {'\xeb','\xd1'},{'\xbf','\xf2'},{'\xeb','\xd2'},{'\xbf','\xf1'},{'\xc1','\xd8'}, + {'\xee','\xc3'},{'\xc1','\xd7'},{'\xc1','\xdc'},{'\xc1','\xda'},{'\xc1','\xdb'}, + {'\xc2','\xe3'},{'\xc1','\xd9'},{'\xee','\xc2'},{'\xeb','\xd3'},{'\xc2','\xe2'}, + {'\xc2','\xe4'},{'\x91','\xb6'},{'\xc3','\xe4'},{'\xc3','\xe5'},{'\x00','\x00'}, + {'\xf4','\xe0'},{'\x00','\x00'},{'\xc5','\xde'},{'\xc5','\xdd'},{'\xa8','\xb6'}, + {'\x00','\x00'},{'\x88','\xa3'},{'\xca','\x55'},{'\xb0','\x6f'},{'\x00','\x00'}, + {'\xca','\x52'},{'\xca','\x53'},{'\xca','\x51'},{'\x00','\x00'},{'\xca','\x54'}, + {'\x00','\x00'},{'\x8f','\xa5'},{'\xcb','\xaa'},{'\xcb','\xa7'},{'\xcb','\xac'}, + {'\xcb','\xa8'},{'\xa8','\xb7'},{'\xa8','\xba'},{'\x00','\x00'},{'\xcb','\xa9'}, + {'\xa8','\xb9'},{'\xcb','\xab'},{'\x95','\x40'},{'\x00','\x00'},{'\xa8','\xb8'}, + {'\x00','\x00'},{'\x8e','\x57'},{'\x00','\x00'},{'\x85','\x6f'},{'\xcd','\xd5'}, + {'\xcd','\xd7'},{'\xaa','\xf4'},{'\xcd','\xd3'},{'\xcd','\xd6'},{'\xcd','\xd4'}, + {'\xaa','\xf2'},{'\xaa','\xf5'},{'\x00','\x00'},{'\xaa','\xf3'},{'\x86','\x66'}, + {'\x89','\x79'},{'\x88','\xa1'},{'\x00','\x00'},{'\xd0','\xb8'},{'\xd0','\xbc'}, + {'\xd0','\xb9'},{'\x00','\x00'},{'\xad','\xa7'},{'\x00','\x00'},{'\xad','\xa8'}, + {'\xfd','\xab'},{'\xd0','\xbb'},{'\x00','\x00'},{'\xd0','\xbd'},{'\xd0','\xbf'}, + {'\x00','\x00'},{'\xad','\xa5'},{'\xd0','\xbe'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xad','\xa6'},{'\x8d','\xc6'},{'\x8e','\xfc'},{'\x88','\xa2'},{'\x00','\x00'}, + {'\x8d','\xf0'},{'\xd7','\xee'},{'\xd0','\xba'},{'\xd3','\xf2'},{'\xd3','\xfb'}, + {'\xd3','\xf9'},{'\xd3','\xf4'},{'\xd3','\xf5'},{'\xd3','\xfa'},{'\xd3','\xfc'}, + {'\xb0','\x71'},{'\x91','\xb7'},{'\xd3','\xf7'},{'\xd3','\xf3'},{'\xb0','\x70'}, + {'\xb0','\x72'},{'\xd3','\xf6'},{'\xd3','\xfd'},{'\xd3','\xf8'},{'\x8c','\xe3'}, + {'\x90','\xbb'},{'\xb3','\xa1'},{'\xd7','\xf1'},{'\xd7','\xe9'},{'\xd7','\xef'}, + {'\xd7','\xf0'},{'\xb3','\xa2'},{'\x00','\x00'},{'\xd7','\xe8'},{'\xd7','\xea'}, + {'\xd0','\xb7'},{'\xd7','\xec'},{'\xd7','\xed'},{'\xd7','\xeb'},{'\xb6','\x6c'}, + {'\x00','\x00'},{'\x92','\x7b'},{'\x8e','\xcf'},{'\xdc','\x56'},{'\xeb','\xd4'}, + {'\xdc','\x57'},{'\xdc','\x54'},{'\xb3','\xa3'},{'\xb6','\x6e'},{'\xdc','\x53'}, + {'\xdc','\x59'},{'\xdc','\x58'},{'\xb6','\x6b'},{'\xdc','\x5c'},{'\xdc','\x52'}, + {'\xdc','\x5b'},{'\xdc','\x50'},{'\xdc','\x5a'},{'\xdc','\x55'},{'\xb6','\x6d'}, + {'\x00','\x00'},{'\xe0','\xaa'},{'\x00','\x00'},{'\xe0','\xa5'},{'\xe0','\xab'}, + {'\xe0','\xa6'},{'\xe0','\xa4'},{'\xe0','\xa7'},{'\xb9','\x51'},{'\x00','\x00'}, + {'\xe0','\xa9'},{'\x91','\xb8'},{'\xe0','\xa8'},{'\xb9','\x52'},{'\xbb','\xc1'}, + {'\xbb','\xc0'},{'\xe4','\x6e'},{'\xe4','\x71'},{'\xe4','\x69'},{'\xe4','\x6d'}, + {'\xbb','\xc2'},{'\xe4','\x6c'},{'\xe4','\x6a'},{'\xe4','\x70'},{'\xe4','\x6b'}, + {'\xe4','\x68'},{'\xe4','\x6f'},{'\x00','\x00'},{'\xe8','\x59'},{'\xbe','\x48'}, + {'\xf1','\x4a'},{'\xe8','\x56'},{'\xe8','\x57'},{'\xe8','\x55'},{'\xdc','\x51'}, + {'\xbe','\x47'},{'\xe8','\x5a'},{'\xe8','\x54'},{'\xbe','\x46'},{'\xbe','\x49'}, + {'\xe8','\x58'},{'\xeb','\xd5'},{'\xbf','\xf3'},{'\xeb','\xd6'},{'\xeb','\xd7'}, + {'\x00','\x00'},{'\xee','\xc4'},{'\xc1','\xdd'},{'\xf1','\x4b'},{'\xf1','\x4c'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xf1','\x4d'},{'\xf3','\x5d'},{'\xf3','\x5c'}, + {'\xf4','\xe2'},{'\x00','\x00'},{'\xf4','\xe1'},{'\xf6','\x5b'},{'\xf6','\x5c'}, + {'\xf6','\x5a'},{'\xf7','\x66'},{'\xc5','\xb0'},{'\xa8','\xbb'},{'\xad','\xaa'}, + {'\xad','\xa9'},{'\xb0','\x75'},{'\xb0','\x74'},{'\xd4','\x40'},{'\xd4','\x41'}, + {'\xd3','\xfe'},{'\xfd','\xac'},{'\xb0','\x73'},{'\xd7','\xf5'},{'\x92','\xf8'}, + {'\xd7','\xf6'},{'\xd7','\xf2'},{'\xb3','\xa4'},{'\xd7','\xf3'},{'\xfd','\xaf'}, + {'\xd7','\xf4'},{'\x00','\x00'},{'\xfd','\xae'},{'\x8a','\x7a'},{'\x96','\xa8'}, + {'\xdc','\x5f'},{'\xdc','\x61'},{'\xdc','\x5d'},{'\xdc','\x60'},{'\xb6','\x6f'}, + {'\xdc','\x5e'},{'\xb6','\x70'},{'\x00','\x00'},{'\xfd','\xb0'},{'\xdd','\x73'}, + {'\xb9','\x55'},{'\xb9','\x54'},{'\x00','\x00'},{'\xb9','\x53'},{'\x00','\x00'}, + {'\xe0','\xac'},{'\xe0','\xad'},{'\x96','\xa9'},{'\x8b','\x4c'},{'\xe4','\x73'}, + {'\xe4','\x75'},{'\xbb','\xc6'},{'\xbb','\xc3'},{'\x96','\xa1'},{'\xbb','\xc5'}, + {'\xbb','\xc4'},{'\xe4','\x74'},{'\xe4','\x72'},{'\x00','\x00'},{'\xfd','\xb1'}, + {'\x8d','\xa6'},{'\x90','\xa5'},{'\x8d','\x5d'},{'\xe8','\x61'},{'\xe8','\x5e'}, + {'\xe8','\x5f'},{'\xbe','\x4d'},{'\xe8','\x60'},{'\xe8','\x5b'},{'\xe8','\x5c'}, + {'\xbe','\x4a'},{'\x00','\x00'},{'\xbe','\x4b'},{'\xe8','\x5d'},{'\xbe','\x4c'}, + {'\x96','\xaa'},{'\xeb','\xdb'},{'\xfd','\xb2'},{'\xeb','\xdc'},{'\xeb','\xd9'}, + {'\xeb','\xda'},{'\xbf','\xf4'},{'\xeb','\xd8'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x82','\x79'},{'\x00','\x00'},{'\xee','\xc8'},{'\xee','\xc5'}, + {'\xee','\xc7'},{'\xc1','\xe0'},{'\xee','\xcb'},{'\xc1','\xdf'},{'\xee','\xc9'}, + {'\xee','\xcc'},{'\xee','\xca'},{'\xee','\xc6'},{'\xc1','\xde'},{'\x82','\x66'}, + {'\xf1','\x4f'},{'\x00','\x00'},{'\xf1','\x50'},{'\xf1','\x4e'},{'\x9e','\x63'}, + {'\xf1','\x52'},{'\xc2','\xe5'},{'\xc2','\xe6'},{'\xf3','\x5f'},{'\xc3','\xe7'}, + {'\xf1','\x51'},{'\xf3','\x5e'},{'\xc3','\xe6'},{'\xf4','\xe5'},{'\xf4','\xe6'}, + {'\xc4','\xbf'},{'\xf4','\xe4'},{'\x9e','\x64'},{'\xf4','\xe3'},{'\x92','\xf1'}, + {'\xf6','\x5d'},{'\xc5','\x48'},{'\xfd','\xb3'},{'\xf8','\x49'},{'\xf8','\xc8'}, + {'\xf8','\xc7'},{'\x00','\x00'},{'\xc6','\x43'},{'\xc6','\x5d'},{'\xf8','\xc9'}, + {'\xf9','\x71'},{'\x9e','\x65'},{'\xc6','\x6f'},{'\xa8','\xbc'},{'\xaa','\xf6'}, + {'\x92','\xd8'},{'\xb9','\x56'},{'\x8c','\x5c'},{'\xc4','\xc0'},{'\xa8','\xbd'}, + {'\xad','\xab'},{'\xb3','\xa5'},{'\xb6','\x71'},{'\xc2','\xe7'},{'\xaa','\xf7'}, + {'\x00','\x00'},{'\xd0','\xc1'},{'\xd0','\xc0'},{'\xd4','\x42'},{'\x91','\xb9'}, + {'\xb0','\x78'},{'\xb0','\x76'},{'\xb0','\x7a'},{'\xd4','\x44'},{'\x91','\xba'}, + {'\xb0','\x79'},{'\xb0','\x77'},{'\x91','\xbb'},{'\x96','\x49'},{'\x00','\x00'}, + {'\x91','\xbc'},{'\xd4','\x43'},{'\xb3','\xa8'},{'\xd7','\xfc'},{'\x91','\xbd'}, + {'\xb3','\xa7'},{'\xb3','\xa9'},{'\xd8','\x42'},{'\xb3','\xab'},{'\xd7','\xfe'}, + {'\xd8','\x40'},{'\xd7','\xf7'},{'\xb3','\xaa'},{'\xd8','\x43'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xd7','\xf9'},{'\x00','\x00'},{'\xd7','\xfa'},{'\xd7','\xf8'}, + {'\xb3','\xa6'},{'\x91','\xbe'},{'\xd8','\x41'},{'\xd7','\xfb'},{'\xd7','\xfd'}, + {'\x9e','\x66'},{'\x00','\x00'},{'\x91','\xbf'},{'\xdc','\x6d'},{'\xfd','\xb7'}, + {'\xdc','\x6c'},{'\xdc','\x6a'},{'\xdc','\x62'},{'\xdc','\x71'},{'\xdc','\x65'}, + {'\xdc','\x6f'},{'\xdc','\x76'},{'\xdc','\x6e'},{'\xb6','\x79'},{'\x9e','\x67'}, + {'\xb6','\x75'},{'\xdc','\x63'},{'\x00','\x00'},{'\xdc','\x69'},{'\xb6','\x77'}, + {'\x95','\x4c'},{'\xdc','\x68'},{'\xb6','\x78'},{'\xb6','\x7a'},{'\xdc','\x6b'}, + {'\x9e','\x68'},{'\xb6','\x72'},{'\xb6','\x73'},{'\xdc','\x77'},{'\xdc','\x75'}, + {'\x00','\x00'},{'\xdc','\x74'},{'\xdc','\x66'},{'\x00','\x00'},{'\xdc','\x72'}, + {'\x00','\x00'},{'\xb6','\x76'},{'\x00','\x00'},{'\x00','\x00'},{'\x9e','\x69'}, + {'\x00','\x00'},{'\xb6','\x74'},{'\xdc','\x73'},{'\xdc','\x64'},{'\xdc','\x67'}, + {'\xdc','\x70'},{'\x9e','\x6a'},{'\x91','\xc0'},{'\xfb','\x5f'},{'\x9e','\x6b'}, + {'\x91','\xc1'},{'\xe4','\xba'},{'\xe0','\xb7'},{'\x00','\x00'},{'\xe0','\xb0'}, + {'\xe0','\xc3'},{'\xe0','\xcc'},{'\xe0','\xb3'},{'\xb9','\x61'},{'\x9e','\x6c'}, + {'\xe0','\xc0'},{'\xb9','\x57'},{'\xb9','\x59'},{'\xb9','\x65'},{'\xe0','\xb1'}, + {'\x00','\x00'},{'\x9e','\x6d'},{'\xb9','\x5a'},{'\xb9','\x5c'},{'\xb9','\x66'}, + {'\xb9','\x5b'},{'\x9e','\x6e'},{'\x00','\x00'},{'\x00','\x00'},{'\x93','\x7b'}, + {'\xb9','\x64'},{'\xe0','\xb9'},{'\x00','\x00'},{'\xe0','\xae'},{'\xb9','\x62'}, + {'\xe0','\xb8'},{'\xb9','\x5e'},{'\xe0','\xca'},{'\xb9','\x63'},{'\xe0','\xc8'}, + {'\xe0','\xbc'},{'\xe0','\xc6'},{'\xb9','\x60'},{'\xe0','\xaf'},{'\xe0','\xc9'}, + {'\xe0','\xc4'},{'\x96','\x40'},{'\xe0','\xcb'},{'\xb9','\x58'},{'\x9e','\x6f'}, + {'\x91','\xc3'},{'\xb9','\x67'},{'\xb9','\x5d'},{'\x00','\x00'},{'\x9e','\x70'}, + {'\xe0','\xb5'},{'\x9e','\x71'},{'\xe0','\xbd'},{'\xe0','\xc1'},{'\x95','\xf1'}, + {'\xe0','\xc5'},{'\xb9','\x5f'},{'\xe0','\xb4'},{'\xe0','\xb2'},{'\xe0','\xbe'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x9e','\x72'},{'\xe0','\xbb'}, + {'\xe0','\xba'},{'\x9e','\x73'},{'\xe0','\xbf'},{'\xe0','\xc2'},{'\x92','\xc0'}, + {'\xe0','\xc7'},{'\x96','\x43'},{'\x8c','\xe5'},{'\x00','\x00'},{'\xe4','\x78'}, + {'\x91','\xc4'},{'\xbb','\xc7'},{'\xe4','\xa4'},{'\xe4','\x7a'},{'\xbb','\xcc'}, + {'\xbb','\xd0'},{'\xe4','\xad'},{'\xe4','\xb5'},{'\xe4','\xa6'},{'\xbb','\xc8'}, + {'\x9e','\x74'},{'\xe4','\xaa'},{'\xe0','\xb6'},{'\x9e','\x75'},{'\xbb','\xc9'}, + {'\xe4','\xb1'},{'\xe4','\xb6'},{'\xe4','\xae'},{'\x9e','\x76'},{'\xe4','\xb0'}, + {'\xe4','\xb9'},{'\xe4','\xb2'},{'\xe4','\x7e'},{'\xe4','\xa9'},{'\x9e','\x77'}, + {'\x00','\x00'},{'\xbb','\xd1'},{'\x00','\x00'},{'\xbb','\xcd'},{'\xe4','\x7c'}, + {'\xe4','\xab'},{'\xbb','\xcb'},{'\xe4','\xa5'},{'\xbb','\xca'},{'\xe4','\xb3'}, + {'\xe4','\xa2'},{'\xe4','\x79'},{'\xbb','\xce'},{'\xe4','\xb8'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xe4','\x7b'},{'\xe4','\xaf'},{'\xe4','\xac'},{'\xe4','\xa7'}, + {'\xe4','\x77'},{'\xe4','\x76'},{'\xe4','\xa1'},{'\xe4','\xb4'},{'\xbb','\xcf'}, + {'\xe4','\xb7'},{'\xe4','\x7d'},{'\xe4','\xa3'},{'\xbe','\x52'},{'\x93','\x4b'}, + {'\x8d','\xa8'},{'\x00','\x00'},{'\x00','\x00'},{'\x9e','\x78'},{'\xbe','\x5a'}, + {'\xbe','\x55'},{'\xe8','\xa4'},{'\xe8','\xa1'},{'\xe8','\x67'},{'\xbe','\x50'}, + {'\x00','\x00'},{'\xf9','\xd7'},{'\x9e','\x79'},{'\xbe','\x4f'},{'\xbe','\x56'}, + {'\x00','\x00'},{'\xfd','\xb9'},{'\x9e','\x7a'},{'\xe8','\x65'},{'\xbe','\x54'}, + {'\xe8','\x71'},{'\xe8','\x63'},{'\xe8','\x64'},{'\xbe','\x4e'},{'\xe8','\xa3'}, + {'\xbe','\x58'},{'\xe8','\x74'},{'\xe8','\x79'},{'\xe8','\x73'},{'\xeb','\xee'}, + {'\xe8','\x6f'},{'\xe8','\x77'},{'\xe8','\x75'},{'\xe8','\x68'},{'\xe8','\x62'}, + {'\xe8','\x7d'},{'\xbe','\x57'},{'\xe8','\x7e'},{'\x9e','\x7b'},{'\xe8','\x78'}, + {'\x00','\x00'},{'\xe8','\x6d'},{'\xe8','\x6b'},{'\xe8','\x66'},{'\x00','\x00'}, + {'\x9e','\x7c'},{'\x00','\x00'},{'\xe8','\x6e'},{'\xe8','\x7b'},{'\xe8','\x6a'}, + {'\xe8','\x7a'},{'\xe8','\xa2'},{'\x00','\x00'},{'\x9e','\x7d'},{'\xbe','\x53'}, + {'\x9e','\x7e'},{'\xe8','\x76'},{'\xe8','\x7c'},{'\xe8','\x72'},{'\xe8','\x6c'}, + {'\xbe','\x51'},{'\x9e','\xa1'},{'\x9e','\xa2'},{'\x91','\xc5'},{'\xe4','\xa8'}, + {'\xe8','\x70'},{'\xbe','\x59'},{'\xe8','\x69'},{'\x94','\x58'},{'\x93','\x74'}, + {'\x9e','\xa3'},{'\x00','\x00'},{'\x9e','\xa4'},{'\xeb','\xf4'},{'\xbf','\xf7'}, + {'\xeb','\xf3'},{'\xeb','\xf0'},{'\xec','\x44'},{'\xbf','\xfb'},{'\x9e','\xa5'}, + {'\xec','\x41'},{'\xeb','\xf8'},{'\xec','\x43'},{'\xeb','\xe9'},{'\xeb','\xf6'}, + {'\x9e','\xa6'},{'\xbf','\xfd'},{'\x00','\x00'},{'\xeb','\xe1'},{'\x9e','\xa7'}, + {'\xeb','\xdf'},{'\xec','\x42'},{'\x00','\x00'},{'\xec','\x40'},{'\xeb','\xfe'}, + {'\xeb','\xed'},{'\xeb','\xec'},{'\xeb','\xe2'},{'\xc0','\x40'},{'\x00','\x00'}, + {'\xeb','\xe8'},{'\xeb','\xf2'},{'\xeb','\xfd'},{'\xc0','\x43'},{'\xec','\x45'}, + {'\x00','\x00'},{'\xc1','\xe8'},{'\xc0','\x45'},{'\xbf','\xfe'},{'\xeb','\xe6'}, + {'\x00','\x00'},{'\xeb','\xef'},{'\xeb','\xde'},{'\xeb','\xe0'},{'\xbf','\xf5'}, + {'\xc0','\x42'},{'\xbf','\xfa'},{'\xeb','\xe7'},{'\xeb','\xf7'},{'\xeb','\xf1'}, + {'\xc0','\x41'},{'\xeb','\xdd'},{'\xc1','\xe3'},{'\xeb','\xf9'},{'\xeb','\xfc'}, + {'\xbf','\xfc'},{'\x93','\xf3'},{'\xeb','\xeb'},{'\xc0','\x44'},{'\xbf','\xf9'}, + {'\x9e','\xa8'},{'\x9e','\xa9'},{'\x93','\xf7'},{'\xbf','\xf8'},{'\xeb','\xf5'}, + {'\xeb','\xfb'},{'\xbf','\xf6'},{'\x00','\x00'},{'\xeb','\xe4'},{'\xeb','\xfa'}, + {'\x91','\xc6'},{'\x94','\xdb'},{'\xeb','\xe5'},{'\x00','\x00'},{'\x8b','\xd6'}, + {'\x00','\x00'},{'\x9e','\xaa'},{'\xfe','\x7c'},{'\x9e','\xab'},{'\x9e','\xac'}, + {'\x97','\x55'},{'\x96','\x42'},{'\xeb','\xea'},{'\xee','\xd2'},{'\xfe','\x79'}, + {'\xee','\xd7'},{'\xc1','\xe5'},{'\xc1','\xe7'},{'\xee','\xdd'},{'\xc1','\xe1'}, + {'\xee','\xec'},{'\xee','\xe3'},{'\xee','\xd8'},{'\xee','\xd9'},{'\xee','\xe2'}, + {'\x00','\x00'},{'\xc1','\xee'},{'\xee','\xe1'},{'\xee','\xd1'},{'\xee','\xe0'}, + {'\xee','\xd4'},{'\xee','\xed'},{'\xc1','\xed'},{'\xc1','\xeb'},{'\xee','\xd5'}, + {'\x00','\x00'},{'\xee','\xe8'},{'\x9e','\xad'},{'\xee','\xda'},{'\xee','\xe7'}, + {'\x9e','\xae'},{'\xee','\xe9'},{'\xee','\xd0'},{'\xc1','\xe6'},{'\x9e','\xaf'}, + {'\xee','\xea'},{'\x9e','\xb0'},{'\x96','\x44'},{'\xee','\xde'},{'\xfd','\xba'}, + {'\xc1','\xea'},{'\xee','\xdb'},{'\xfd','\xbb'},{'\x00','\x00'},{'\xc1','\xec'}, + {'\xee','\xe4'},{'\x00','\x00'},{'\x9e','\xb1'},{'\x9e','\xb2'},{'\xc1','\xe4'}, + {'\xee','\xd6'},{'\xee','\xe5'},{'\x9e','\xb3'},{'\xee','\xdf'},{'\xeb','\xe3'}, + {'\xee','\xe6'},{'\xee','\xd3'},{'\x9e','\xb4'},{'\xc1','\xe9'},{'\x00','\x00'}, + {'\xee','\xeb'},{'\x9e','\xb5'},{'\xc1','\xe2'},{'\xee','\xce'},{'\x9e','\xb6'}, + {'\xfb','\x73'},{'\x9e','\xb7'},{'\x9e','\xb8'},{'\xf1','\x60'},{'\xf1','\x59'}, + {'\xc2','\xe9'},{'\x00','\x00'},{'\xf1','\x54'},{'\xf1','\x63'},{'\xf1','\x5b'}, + {'\xee','\xdc'},{'\x9e','\xb9'},{'\xf1','\x65'},{'\xf1','\x55'},{'\x00','\x00'}, + {'\xc2','\xe8'},{'\xf1','\x5f'},{'\xc2','\xea'},{'\xc2','\xf2'},{'\xc2','\xf0'}, + {'\xf1','\x61'},{'\xc2','\xf1'},{'\xf1','\x57'},{'\x9e','\xba'},{'\xf1','\x58'}, + {'\xf1','\x5d'},{'\xf1','\x62'},{'\x9e','\xbb'},{'\xee','\xcd'},{'\xc2','\xeb'}, + {'\xf1','\x6a'},{'\xf1','\x67'},{'\xf1','\x6b'},{'\xf1','\x5e'},{'\xf1','\x5a'}, + {'\xf1','\x68'},{'\xf3','\x6a'},{'\xf1','\x5c'},{'\x00','\x00'},{'\xc2','\xee'}, + {'\x97','\x56'},{'\xc2','\xed'},{'\xee','\xcf'},{'\xc2','\xef'},{'\xf1','\x64'}, + {'\xf1','\x66'},{'\xc2','\xec'},{'\xf1','\x69'},{'\xf1','\x53'},{'\x00','\x00'}, + {'\xf1','\x56'},{'\x9e','\xbc'},{'\x94','\xdc'},{'\xfd','\xbc'},{'\x9e','\xbd'}, + {'\x00','\x00'},{'\x9e','\xbe'},{'\x00','\x00'},{'\x9e','\xbf'},{'\xf3','\x73'}, + {'\x00','\x00'},{'\xf3','\x63'},{'\xc3','\xeb'},{'\xf3','\x71'},{'\x00','\x00'}, + {'\x97','\x57'},{'\xf3','\x61'},{'\xc3','\xec'},{'\x00','\x00'},{'\xf3','\x6c'}, + {'\x9e','\xc0'},{'\xf3','\x68'},{'\xc3','\xf1'},{'\xf3','\x72'},{'\xf3','\x62'}, + {'\xf3','\x65'},{'\xc3','\xe9'},{'\xf3','\x74'},{'\x9e','\xc1'},{'\xf3','\x6d'}, + {'\xf3','\x70'},{'\xc3','\xef'},{'\xc3','\xf4'},{'\xc3','\xf2'},{'\xf3','\x69'}, + {'\xf3','\x64'},{'\x9e','\xc2'},{'\xc3','\xed'},{'\xc3','\xee'},{'\xf3','\x60'}, + {'\xc3','\xea'},{'\x9e','\xc3'},{'\xc3','\xe8'},{'\xc3','\xf0'},{'\xf3','\x6f'}, + {'\xc3','\xf3'},{'\x97','\x58'},{'\xf3','\x6b'},{'\xf3','\x75'},{'\xc3','\xf5'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xf3','\x67'},{'\x00','\x00'}, + {'\xf3','\x6e'},{'\x00','\x00'},{'\x9e','\xc4'},{'\x9e','\xc5'},{'\x00','\x00'}, + {'\x9e','\xc6'},{'\x9e','\xc7'},{'\xf4','\xf3'},{'\xf5','\x42'},{'\xf4','\xf5'}, + {'\xf4','\xfc'},{'\xf3','\x66'},{'\xf4','\xfa'},{'\xf4','\xe9'},{'\xf5','\x40'}, + {'\xc4','\xc3'},{'\xf4','\xed'},{'\xf4','\xfe'},{'\xf4','\xf4'},{'\x9e','\xc8'}, + {'\x00','\x00'},{'\xc4','\xc2'},{'\x9e','\xc9'},{'\x00','\x00'},{'\xf5','\x44'}, + {'\xf4','\xf6'},{'\x9e','\xca'},{'\xf4','\xfb'},{'\xf4','\xfd'},{'\xf4','\xe7'}, + {'\xf5','\x41'},{'\xf4','\xf2'},{'\xf4','\xf7'},{'\xf4','\xeb'},{'\xf4','\xef'}, + {'\xf5','\x43'},{'\xf4','\xf9'},{'\xf4','\xe8'},{'\xf4','\xec'},{'\xf4','\xee'}, + {'\xf4','\xf8'},{'\x9e','\xcb'},{'\xc4','\xc1'},{'\xf4','\xf1'},{'\x97','\x59'}, + {'\x9e','\xcc'},{'\x00','\x00'},{'\x9e','\xcd'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xf4','\xea'},{'\x97','\x5a'},{'\x00','\x00'},{'\x00','\x00'},{'\x9e','\xce'}, + {'\x9e','\xcf'},{'\x9e','\xd0'},{'\xfd','\xbd'},{'\xf4','\xf0'},{'\xf6','\x61'}, + {'\xf6','\x66'},{'\xc5','\x4f'},{'\xf6','\x68'},{'\x9e','\xd1'},{'\xc5','\x49'}, + {'\x00','\x00'},{'\xf6','\x64'},{'\xf6','\x6a'},{'\xc5','\x4e'},{'\xc5','\x4a'}, + {'\x00','\x00'},{'\xc5','\x4b'},{'\xf6','\x60'},{'\xf6','\x67'},{'\xc5','\x4d'}, + {'\xf6','\x65'},{'\xc5','\x4c'},{'\xf6','\x5f'},{'\xf6','\x63'},{'\xf6','\x62'}, + {'\x97','\x5b'},{'\xf6','\x5e'},{'\xf6','\x69'},{'\x97','\x5c'},{'\x9e','\xd2'}, + {'\x9e','\xd3'},{'\xc5','\xb1'},{'\xf7','\x6d'},{'\xf7','\x70'},{'\xf7','\x6c'}, + {'\xf7','\x6e'},{'\xf7','\x6f'},{'\xf7','\x69'},{'\xf7','\x6a'},{'\xf7','\x67'}, + {'\x9e','\xd4'},{'\x00','\x00'},{'\xf7','\x6b'},{'\xf7','\x68'},{'\xc5','\xb2'}, + {'\xc5','\xb3'},{'\x97','\x5d'},{'\x9e','\xd5'},{'\xf8','\x4b'},{'\x00','\x00'}, + {'\xf8','\x4d'},{'\x9e','\xd6'},{'\x00','\x00'},{'\x97','\x5e'},{'\x95','\x58'}, + {'\x00','\x00'},{'\xf8','\x4c'},{'\xf8','\x4e'},{'\x00','\x00'},{'\xc5','\xe0'}, + {'\x00','\x00'},{'\xf8','\x4a'},{'\xc5','\xdf'},{'\xc5','\xe1'},{'\x9e','\xd7'}, + {'\x00','\x00'},{'\x9e','\xd8'},{'\xf8','\xcb'},{'\xf8','\xcc'},{'\xc6','\x44'}, + {'\xf8','\xca'},{'\x9e','\xd9'},{'\xf9','\x53'},{'\xf9','\x52'},{'\xf9','\x54'}, + {'\xc6','\x5f'},{'\xf9','\x55'},{'\xc6','\x5e'},{'\xf9','\x56'},{'\xf9','\x72'}, + {'\xf9','\x75'},{'\xf9','\x74'},{'\xc6','\x68'},{'\xf9','\x73'},{'\x9e','\xda'}, + {'\x00','\x00'},{'\x9e','\xdb'},{'\xc6','\x72'},{'\xc6','\x70'},{'\xc6','\x71'}, + {'\xc6','\x77'},{'\xf9','\xc0'},{'\xf9','\xc1'},{'\xf9','\xbf'},{'\xf9','\xc9'}, + {'\x00','\x00'},{'\x9c','\xf0'},{'\x8d','\xc1'},{'\x8d','\xc0'},{'\x83','\xe1'}, + {'\x83','\xe0'},{'\x83','\xe2'},{'\x83','\xe3'},{'\x8d','\xc7'},{'\x8d','\xd9'}, + {'\x8d','\xd6'},{'\x84','\xb6'},{'\x8d','\xd7'},{'\x00','\x00'},{'\x84','\xb7'}, + {'\x84','\xb5'},{'\x8f','\x46'},{'\x8d','\xd8'},{'\x00','\x00'},{'\x84','\xb4'}, + {'\x00','\x00'},{'\x85','\x73'},{'\x97','\x5f'},{'\x8d','\xf4'},{'\x86','\x73'}, + {'\x85','\x76'},{'\x85','\x71'},{'\x8c','\x5d'},{'\x85','\x74'},{'\x88','\xae'}, + {'\x89','\xa1'},{'\x85','\x78'},{'\x85','\x77'},{'\x8d','\x76'},{'\x84','\xe8'}, + {'\x85','\x75'},{'\x8b','\x4f'},{'\x86','\x6e'},{'\x8d','\xf7'},{'\x8d','\xf2'}, + {'\x8d','\xf3'},{'\x8d','\xf6'},{'\x85','\x72'},{'\x8d','\xf5'},{'\x8e','\x5a'}, + {'\x89','\x7e'},{'\x8e','\x5b'},{'\x86','\x68'},{'\x86','\x67'},{'\x84','\x73'}, + {'\x8e','\x5c'},{'\x97','\x60'},{'\x86','\x6a'},{'\x86','\x69'},{'\x8d','\xb2'}, + {'\x8d','\xa7'},{'\x8e','\x60'},{'\x8e','\x5f'},{'\x86','\x6b'},{'\x86','\x75'}, + {'\x86','\x6c'},{'\x8c','\xb2'},{'\x86','\x6f'},{'\x86','\x70'},{'\x8d','\x44'}, + {'\x86','\x6d'},{'\x86','\x76'},{'\x00','\x00'},{'\x8e','\x59'},{'\x86','\x71'}, + {'\x8e','\x58'},{'\x86','\x72'},{'\x8e','\x5e'},{'\x86','\x74'},{'\x8c','\xb4'}, + {'\x00','\x00'},{'\x88','\xa8'},{'\x8e','\xa5'},{'\x8e','\xa4'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x8e','\xa6'},{'\x8e','\xac'},{'\x8e','\xd1'},{'\x97','\x61'}, + {'\x8c','\x5e'},{'\x00','\x00'},{'\x8c','\xb3'},{'\x87','\x66'},{'\x88','\xaa'}, + {'\x97','\x62'},{'\x8e','\xa7'},{'\x8f','\xa7'},{'\x8f','\x6a'},{'\x87','\x68'}, + {'\x87','\x6c'},{'\x8e','\xd5'},{'\x8e','\xad'},{'\x00','\x00'},{'\x8f','\xec'}, + {'\x87','\x6a'},{'\x8f','\xcd'},{'\x8e','\xaa'},{'\x8e','\xa8'},{'\x87','\x69'}, + {'\x87','\x67'},{'\x89','\xa4'},{'\x8e','\xa9'},{'\x87','\x64'},{'\x8e','\xa3'}, + {'\x85','\xb6'},{'\x97','\x63'},{'\x8f','\xe5'},{'\x87','\x6b'},{'\x87','\x65'}, + {'\x8e','\xab'},{'\x8c','\xe4'},{'\x8f','\xee'},{'\x88','\xa7'},{'\x00','\x00'}, + {'\x8f','\x42'},{'\x8e','\xd2'},{'\x8b','\xce'},{'\x8b','\xd5'},{'\x88','\xa6'}, + {'\x8b','\x4e'},{'\x88','\xaf'},{'\x97','\x64'},{'\x88','\xa9'},{'\x8a','\xa2'}, + {'\x8e','\xd6'},{'\x8e','\xd7'},{'\x8c','\x5f'},{'\x88','\xac'},{'\x8e','\xd4'}, + {'\x88','\xad'},{'\x88','\xa4'},{'\x8e','\x5d'},{'\x97','\x65'},{'\x97','\x66'}, + {'\x88','\xab'},{'\x88','\xa5'},{'\x8e','\xd0'},{'\x8e','\xd3'},{'\x8e','\xd8'}, + {'\x8f','\x44'},{'\x8f','\x40'},{'\x8f','\x41'},{'\x97','\x67'},{'\x89','\x7d'}, + {'\x8a','\x7d'},{'\x8f','\x43'},{'\x00','\x00'},{'\x97','\x68'},{'\x8f','\x45'}, + {'\x89','\xa7'},{'\x00','\x00'},{'\x89','\xa2'},{'\x89','\xa8'},{'\x8d','\xa9'}, + {'\x8a','\xa3'},{'\x89','\xa5'},{'\x89','\xa6'},{'\x00','\x00'},{'\x90','\xf1'}, + {'\x8e','\xfd'},{'\x97','\x69'},{'\x97','\x6a'},{'\x8e','\xfe'},{'\x89','\x7a'}, + {'\x8a','\x7e'},{'\x89','\x7b'},{'\x89','\x7c'},{'\x89','\xa9'},{'\x8a','\xa1'}, + {'\x00','\x00'},{'\x8f','\x69'},{'\x8b','\xd3'},{'\x8f','\x6b'},{'\x8a','\xa8'}, + {'\x8f','\x68'},{'\x8a','\xa5'},{'\x8a','\xa4'},{'\x8a','\xa6'},{'\x8f','\xa8'}, + {'\x00','\x00'},{'\x8a','\xa7'},{'\x97','\x6b'},{'\x8a','\x7b'},{'\x8a','\x7c'}, + {'\x8b','\xd4'},{'\x00','\x00'},{'\x8f','\xea'},{'\x97','\x6c'},{'\x8a','\x42'}, + {'\x8b','\x51'},{'\x00','\x00'},{'\x8b','\x54'},{'\x8d','\x7d'},{'\x00','\x00'}, + {'\x8c','\xb6'},{'\x8b','\x50'},{'\x97','\x6d'},{'\x8f','\xa9'},{'\x8b','\x52'}, + {'\x8b','\x4d'},{'\x8b','\x53'},{'\x8f','\xa6'},{'\x90','\x60'},{'\x00','\x00'}, + {'\x8b','\xd1'},{'\x8b','\xcf'},{'\x8b','\xd0'},{'\x8b','\xd2'},{'\x00','\x00'}, + {'\x8f','\xc9'},{'\x8b','\xcb'},{'\x8b','\xcc'},{'\x8b','\xcd'},{'\x8f','\xca'}, + {'\x00','\x00'},{'\x8f','\xe8'},{'\x97','\x6e'},{'\x8f','\xe9'},{'\x8f','\xed'}, + {'\x97','\x6f'},{'\x8f','\xe6'},{'\x90','\xa1'},{'\x8f','\xe7'},{'\x97','\x70'}, + {'\x8f','\xcb'},{'\x8f','\xeb'},{'\x90','\x61'},{'\x8c','\xb1'},{'\x00','\x00'}, + {'\x8c','\xb5'},{'\x8c','\xb0'},{'\x90','\x48'},{'\x97','\x71'},{'\x8d','\x43'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x8c','\x7c'},{'\xaa','\xf8'},{'\x9e','\xdc'}, + {'\x00','\x00'},{'\xd8','\x44'},{'\xdc','\x78'},{'\xe8','\xa5'},{'\xf3','\x76'}, + {'\x00','\x00'},{'\x83','\x63'},{'\xaa','\xf9'},{'\x00','\x00'},{'\xad','\xac'}, + {'\xb0','\x7b'},{'\x00','\x00'},{'\x9e','\xdd'},{'\xd8','\x45'},{'\x97','\x72'}, + {'\xd8','\x46'},{'\xb3','\xac'},{'\x94','\xdd'},{'\xb6','\x7d'},{'\xdc','\x7a'}, + {'\xdc','\x79'},{'\xb6','\xa3'},{'\xb6','\x7c'},{'\xdc','\x7b'},{'\xb6','\x7e'}, + {'\xb6','\xa2'},{'\xb6','\xa1'},{'\xb6','\x7b'},{'\x00','\x00'},{'\x94','\xde'}, + {'\xfd','\xbe'},{'\xb9','\x68'},{'\x97','\x73'},{'\x00','\x00'},{'\xe0','\xd0'}, + {'\xe0','\xce'},{'\x00','\x00'},{'\xe0','\xcf'},{'\xe0','\xcd'},{'\x97','\x74'}, + {'\xbb','\xd2'},{'\x92','\x6b'},{'\xbb','\xd5'},{'\xbb','\xd7'},{'\xbb','\xd6'}, + {'\x9e','\xde'},{'\xfd','\xbf'},{'\xbb','\xd3'},{'\xbb','\xd4'},{'\x9e','\xdf'}, + {'\xe8','\xa7'},{'\xe8','\xa6'},{'\xbe','\x5b'},{'\xe8','\xa8'},{'\x00','\x00'}, + {'\xe8','\xa9'},{'\xbe','\x5c'},{'\x97','\x75'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xec','\x4d'},{'\xec','\x4b'},{'\xee','\xf3'},{'\x00','\x00'},{'\xec','\x49'}, + {'\xec','\x4a'},{'\xc0','\x46'},{'\xec','\x46'},{'\xec','\x4e'},{'\xec','\x48'}, + {'\xec','\x4c'},{'\xee','\xef'},{'\x00','\x00'},{'\x00','\x00'},{'\xee','\xf1'}, + {'\x00','\x00'},{'\xee','\xf2'},{'\xc1','\xf3'},{'\xee','\xee'},{'\xc1','\xf2'}, + {'\xee','\xf0'},{'\xc1','\xef'},{'\xc1','\xf0'},{'\xc1','\xf1'},{'\xec','\x47'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc2','\xf5'},{'\xf1','\x6e'},{'\xf1','\x6c'}, + {'\xf1','\x6d'},{'\xc2','\xf3'},{'\xc2','\xf6'},{'\xc2','\xf4'},{'\x00','\x00'}, + {'\x93','\xa7'},{'\x00','\x00'},{'\xf3','\x77'},{'\xf3','\x78'},{'\xc3','\xf6'}, + {'\x00','\x00'},{'\xf5','\x45'},{'\xf5','\x47'},{'\xf5','\x46'},{'\xc4','\xc4'}, + {'\xc5','\x50'},{'\xf6','\x6d'},{'\xf6','\x6c'},{'\xf6','\x6b'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x83','\x64'},{'\x83','\xa2'},{'\x83','\xe4'},{'\x8d','\xda'}, + {'\x00','\x00'},{'\x84','\xb8'},{'\x83','\xf4'},{'\x8b','\x56'},{'\x85','\x7a'}, + {'\x8a','\xac'},{'\x85','\x7c'},{'\x85','\x7e'},{'\x85','\x7d'},{'\x85','\x79'}, + {'\x8d','\xf8'},{'\x84','\xdd'},{'\x86','\x77'},{'\x88','\xc1'},{'\x87','\x6e'}, + {'\x87','\x47'},{'\x90','\x49'},{'\x87','\x6f'},{'\x88','\xb0'},{'\x00','\x00'}, + {'\x87','\x71'},{'\x87','\x70'},{'\x87','\x6d'},{'\x8e','\xda'},{'\x90','\xac'}, + {'\x88','\xb1'},{'\x8e','\xd9'},{'\x00','\x00'},{'\x8f','\x48'},{'\x8f','\x49'}, + {'\x8f','\x4a'},{'\x8f','\xb0'},{'\x8f','\x4b'},{'\x8f','\x4c'},{'\x89','\xaa'}, + {'\x8f','\x47'},{'\x8c','\x60'},{'\x8a','\xab'},{'\x8f','\x6c'},{'\x00','\x00'}, + {'\x8a','\xa9'},{'\x8a','\xaa'},{'\x8b','\x55'},{'\x8b','\x57'},{'\x00','\x00'}, + {'\x8b','\x58'},{'\x8f','\xef'},{'\x00','\x00'},{'\xaa','\xfa'},{'\x9c','\xf1'}, + {'\xc9','\xaa'},{'\x85','\xa1'},{'\xca','\x58'},{'\xa6','\xe9'},{'\xca','\x56'}, + {'\xca','\x59'},{'\xca','\x57'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xcb','\xae'},{'\x00','\x00'},{'\xa8','\xc1'},{'\x00','\x00'},{'\xa8','\xc2'}, + {'\xcb','\xb0'},{'\xa8','\xbf'},{'\xcb','\xaf'},{'\xcb','\xad'},{'\xa8','\xc0'}, + {'\xa8','\xbe'},{'\x85','\xa3'},{'\x84','\xbb'},{'\x83','\xe5'},{'\x85','\xa2'}, + {'\x00','\x00'},{'\xfd','\xc1'},{'\xcd','\xd8'},{'\xcd','\xdb'},{'\xaa','\xfd'}, + {'\xcd','\xda'},{'\xcd','\xd9'},{'\x00','\x00'},{'\xaa','\xfc'},{'\xaa','\xfb'}, + {'\xfe','\x42'},{'\xab','\x40'},{'\xcd','\xdc'},{'\xaa','\xfe'},{'\x87','\x72'}, + {'\x84','\xba'},{'\x8b','\xd8'},{'\x84','\xb9'},{'\x83','\xe7'},{'\xd0','\xc6'}, + {'\xad','\xae'},{'\xad','\xaf'},{'\xad','\xb0'},{'\xd0','\xc7'},{'\xd0','\xc3'}, + {'\xad','\xad'},{'\xd0','\xc4'},{'\x00','\x00'},{'\xd0','\xc5'},{'\xd0','\xc2'}, + {'\x83','\xe6'},{'\x9e','\xe0'},{'\x00','\x00'},{'\xb0','\xa4'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xb0','\xa1'},{'\xd4','\x45'},{'\xb0','\xa2'},{'\xb0','\xa5'}, + {'\xd4','\x46'},{'\x00','\x00'},{'\xb0','\x7e'},{'\xb0','\x7c'},{'\xb0','\x7d'}, + {'\xb0','\xa3'},{'\x92','\x67'},{'\x97','\x76'},{'\x8d','\xf9'},{'\x86','\x78'}, + {'\x89','\xac'},{'\xb3','\xad'},{'\xd8','\x49'},{'\xb3','\xb5'},{'\xd8','\x48'}, + {'\x00','\x00'},{'\xd8','\x4b'},{'\xb3','\xb1'},{'\xd8','\x4a'},{'\xb6','\xab'}, + {'\xb3','\xaf'},{'\xb3','\xb2'},{'\xb3','\xae'},{'\xb3','\xb3'},{'\xb3','\xb4'}, + {'\xb3','\xb0'},{'\x00','\x00'},{'\x92','\xb4'},{'\x9e','\xe1'},{'\xd8','\x47'}, + {'\xb6','\xa7'},{'\xdc','\x7d'},{'\x00','\x00'},{'\xdc','\xa3'},{'\xfd','\xc5'}, + {'\x00','\x00'},{'\xdc','\xa2'},{'\xb6','\xac'},{'\xb6','\xa8'},{'\xb6','\xa9'}, + {'\xdc','\x7c'},{'\xdc','\x7e'},{'\xdc','\xa1'},{'\xb6','\xa4'},{'\xb6','\xa6'}, + {'\x00','\x00'},{'\xb6','\xaa'},{'\xb6','\xa5'},{'\x92','\xfa'},{'\x8a','\xad'}, + {'\xe0','\xd3'},{'\xe0','\xd1'},{'\xe0','\xd2'},{'\xb9','\x6a'},{'\xb9','\x6b'}, + {'\xfd','\xc4'},{'\xe0','\xd4'},{'\xb9','\x69'},{'\xbb','\xd8'},{'\x00','\x00'}, + {'\xbb','\xda'},{'\xbb','\xd9'},{'\x97','\x77'},{'\xe4','\xbb'},{'\x00','\x00'}, + {'\x92','\x47'},{'\xe4','\xbc'},{'\xe8','\xab'},{'\x95','\xf9'},{'\xe8','\xaa'}, + {'\x9e','\xe2'},{'\x00','\x00'},{'\xc0','\x47'},{'\xc0','\x48'},{'\xec','\x4f'}, + {'\xc0','\x49'},{'\x00','\x00'},{'\xee','\xf6'},{'\x00','\x00'},{'\xee','\xf4'}, + {'\x97','\x78'},{'\xee','\xf5'},{'\xc1','\xf4'},{'\x97','\x79'},{'\xf1','\x6f'}, + {'\xc3','\xf7'},{'\x00','\x00'},{'\xc6','\xd7'},{'\x95','\xfb'},{'\xc1','\xf5'}, + {'\xab','\x41'},{'\x00','\x00'},{'\xb0','\xa6'},{'\xd4','\x47'},{'\x86','\x79'}, + {'\x8b','\xd9'},{'\xd8','\x4c'},{'\xb3','\xb6'},{'\xb6','\xad'},{'\xdc','\xa4'}, + {'\xdc','\xa6'},{'\xb6','\xaf'},{'\xb6','\xae'},{'\xb6','\xb0'},{'\xb6','\xb1'}, + {'\xdc','\xa5'},{'\xb9','\x6e'},{'\xb9','\x6f'},{'\xb9','\x6d'},{'\xbb','\xdb'}, + {'\xb9','\x6c'},{'\xe0','\xd5'},{'\x8b','\x5b'},{'\x00','\x00'},{'\x92','\xca'}, + {'\xbb','\xdc'},{'\xe8','\xac'},{'\xec','\x50'},{'\xc0','\x4a'},{'\xc1','\xf6'}, + {'\xf1','\x70'},{'\xf1','\x74'},{'\xc2','\xf9'},{'\xf1','\x71'},{'\xc2','\xfa'}, + {'\xc2','\xf8'},{'\xf1','\x75'},{'\xc2','\xfb'},{'\xf1','\x73'},{'\x90','\x6d'}, + {'\xf3','\x79'},{'\xc2','\xf7'},{'\xc3','\xf8'},{'\x00','\x00'},{'\xf8','\xcd'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xab','\x42'},{'\xb3','\xb8'},{'\xb3','\xb7'}, + {'\x94','\x48'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xb6','\xb2'}, + {'\xdc','\xa8'},{'\xdc','\xa7'},{'\xb6','\xb3'},{'\x8d','\x5e'},{'\x9e','\xe3'}, + {'\xe0','\xd9'},{'\xb9','\x73'},{'\xb9','\x70'},{'\xe0','\xd8'},{'\xb9','\x72'}, + {'\xe0','\xd6'},{'\xb9','\x71'},{'\x00','\x00'},{'\xe0','\xd7'},{'\x8b','\xda'}, + {'\xe4','\xbd'},{'\xbb','\xdd'},{'\x8c','\xe6'},{'\xe8','\xaf'},{'\xfd','\xc7'}, + {'\xbe','\x5d'},{'\xe8','\xad'},{'\xbe','\x5e'},{'\xbe','\x5f'},{'\xe8','\xae'}, + {'\xbe','\x60'},{'\x93','\xed'},{'\xec','\x51'},{'\x00','\x00'},{'\xc0','\x4e'}, + {'\xc0','\x4b'},{'\xc0','\x50'},{'\xec','\x53'},{'\xc0','\x4c'},{'\xec','\x52'}, + {'\xc0','\x4f'},{'\x00','\x00'},{'\x00','\x00'},{'\xc0','\x4d'},{'\x00','\x00'}, + {'\xee','\xf9'},{'\xee','\xfb'},{'\x00','\x00'},{'\x9e','\xe4'},{'\xc1','\xf7'}, + {'\xee','\xfa'},{'\xc1','\xf8'},{'\xee','\xf8'},{'\xee','\xf7'},{'\xfd','\xc8'}, + {'\xf1','\x77'},{'\xf1','\x76'},{'\xc2','\xfc'},{'\xf1','\x78'},{'\xf3','\x7e'}, + {'\xc3','\xfa'},{'\xf3','\x7d'},{'\xf3','\x7a'},{'\xc3','\xf9'},{'\xf3','\x7b'}, + {'\xf3','\x7c'},{'\x8d','\x60'},{'\xf5','\x48'},{'\xf5','\x49'},{'\xc4','\xc5'}, + {'\xfd','\xc9'},{'\xc5','\x53'},{'\x97','\x7a'},{'\x9d','\xbb'},{'\xf6','\x6e'}, + {'\x9e','\xe5'},{'\x00','\x00'},{'\xc5','\x51'},{'\xc5','\x52'},{'\xf6','\x6f'}, + {'\x97','\x7b'},{'\x00','\x00'},{'\xc5','\xb4'},{'\xc5','\xb5'},{'\xf7','\x71'}, + {'\x9e','\xe6'},{'\x9e','\xe7'},{'\xc6','\x45'},{'\xf8','\xcf'},{'\xc6','\x47'}, + {'\x00','\x00'},{'\xf8','\xce'},{'\xf8','\xd0'},{'\xc6','\x46'},{'\xf9','\x57'}, + {'\x00','\x00'},{'\xf9','\xad'},{'\x00','\x00'},{'\x97','\x7c'},{'\x00','\x00'}, + {'\x97','\x7d'},{'\x00','\x00'},{'\x97','\x7e'},{'\xab','\x43'},{'\x8e','\xdb'}, + {'\x00','\x00'},{'\x97','\xa1'},{'\xb9','\x74'},{'\x9e','\xe8'},{'\xe4','\xbe'}, + {'\x93','\x43'},{'\xe8','\xb0'},{'\xc0','\x51'},{'\xc0','\x52'},{'\xfe','\x6d'}, + {'\xab','\x44'},{'\xfd','\xca'},{'\xbe','\x61'},{'\xc3','\xfb'},{'\xad','\xb1'}, + {'\x00','\x00'},{'\x97','\xa2'},{'\x8d','\x45'},{'\xc0','\x53'},{'\x00','\x00'}, + {'\xc5','\xe2'},{'\xad','\xb2'},{'\xd8','\x4d'},{'\x97','\xa3'},{'\xdc','\xa9'}, + {'\x95','\xf7'},{'\xdc','\xab'},{'\x00','\x00'},{'\xdc','\xaa'},{'\x97','\xa4'}, + {'\xe0','\xdd'},{'\xe0','\xda'},{'\xb9','\x75'},{'\x00','\x00'},{'\xb9','\x76'}, + {'\xe0','\xdb'},{'\xe0','\xdc'},{'\x94','\xdf'},{'\xe4','\xc0'},{'\xe4','\xc5'}, + {'\xbb','\xde'},{'\xe4','\xbf'},{'\xe4','\xc1'},{'\xe4','\xc8'},{'\xe4','\xc3'}, + {'\xe4','\xc7'},{'\xe4','\xc4'},{'\xe4','\xc2'},{'\xe4','\xc6'},{'\xbb','\xdf'}, + {'\x94','\xe0'},{'\x9e','\xe9'},{'\xe8','\xb3'},{'\x9e','\xea'},{'\xe8','\xb1'}, + {'\xbe','\x63'},{'\x00','\x00'},{'\xbe','\x62'},{'\xe8','\xb2'},{'\xbe','\x64'}, + {'\x94','\xe1'},{'\x8c','\xe7'},{'\x97','\xa5'},{'\x00','\x00'},{'\xec','\x56'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xec','\x55'},{'\xc0','\x54'},{'\xec','\x54'}, + {'\xee','\xfc'},{'\x9e','\xeb'},{'\xee','\xfe'},{'\xef','\x41'},{'\xef','\x40'}, + {'\xfd','\xcb'},{'\xc1','\xf9'},{'\xee','\xfd'},{'\xf1','\xa1'},{'\xc2','\xfd'}, + {'\xf1','\x7d'},{'\xf1','\xa2'},{'\xc2','\xfe'},{'\x00','\x00'},{'\xf1','\x7b'}, + {'\x00','\x00'},{'\xf1','\x7e'},{'\xf1','\x7c'},{'\xf1','\x79'},{'\xc3','\x40'}, + {'\xf1','\x7a'},{'\x8d','\x7e'},{'\x00','\x00'},{'\x9e','\xec'},{'\x97','\xa6'}, + {'\xf3','\xa1'},{'\xfd','\xcc'},{'\x00','\x00'},{'\xf3','\xa3'},{'\xf3','\xa2'}, + {'\xfd','\xcd'},{'\xf5','\x4a'},{'\xfd','\xce'},{'\xf5','\x4b'},{'\x00','\x00'}, + {'\x9e','\xed'},{'\xfd','\xcf'},{'\xf6','\x70'},{'\x9e','\xee'},{'\xc5','\xb7'}, + {'\x9e','\xef'},{'\xc5','\xb6'},{'\xf8','\x4f'},{'\xf8','\x50'},{'\xc6','\x48'}, + {'\xf8','\xd1'},{'\xfd','\xd0'},{'\xc6','\x69'},{'\x00','\x00'},{'\xad','\xb3'}, + {'\xb6','\xb4'},{'\xe4','\xca'},{'\xe4','\xc9'},{'\xe8','\xb5'},{'\xe8','\xb4'}, + {'\x00','\x00'},{'\x9e','\xf0'},{'\xc1','\xfa'},{'\xef','\x43'},{'\xef','\x42'}, + {'\xf1','\xa5'},{'\xf1','\xa3'},{'\xf1','\xa6'},{'\xf1','\xa4'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xc3','\xfc'},{'\xf3','\xa4'},{'\xf3','\xa5'},{'\xf3','\xa6'}, + {'\x9e','\xf1'},{'\xf6','\x71'},{'\x00','\x00'},{'\xf7','\x72'},{'\x00','\x00'}, + {'\xf8','\xd2'},{'\x83','\xa3'},{'\x85','\xa4'},{'\x00','\x00'},{'\x8a','\xb0'}, + {'\x8f','\xab'},{'\x8f','\xce'},{'\x8b','\xdb'},{'\xad','\xb4'},{'\x95','\x61'}, + {'\x00','\x00'},{'\xec','\x57'},{'\xef','\x44'},{'\x97','\xa7'},{'\xad','\xb5'}, + {'\x00','\x00'},{'\x8b','\xdc'},{'\xbb','\xe0'},{'\x00','\x00'},{'\xec','\x58'}, + {'\xc3','\x41'},{'\xf1','\xa7'},{'\xc3','\xfd'},{'\x00','\x00'},{'\xf5','\x4c'}, + {'\xf5','\x4d'},{'\xc5','\x54'},{'\xf8','\x51'},{'\xad','\xb6'},{'\xb3','\xbb'}, + {'\xb3','\xbc'},{'\xd8','\x4e'},{'\xb6','\xb5'},{'\xb6','\xb6'},{'\xdc','\xac'}, + {'\xb6','\xb7'},{'\x00','\x00'},{'\xb9','\x7a'},{'\x00','\x00'},{'\xb9','\x7c'}, + {'\xe0','\xdf'},{'\xe0','\xe0'},{'\xe0','\xde'},{'\xb9','\x77'},{'\xb9','\x78'}, + {'\xb9','\x7b'},{'\xb9','\x79'},{'\x9e','\xf2'},{'\x9e','\xf3'},{'\xe4','\xcb'}, + {'\xbb','\xe1'},{'\xbb','\xe2'},{'\x00','\x00'},{'\x82','\x5b'},{'\xe8','\xbc'}, + {'\xbe','\x67'},{'\xe8','\xb7'},{'\xe8','\xb6'},{'\xfd','\xd2'},{'\xe8','\xbb'}, + {'\xbe','\x65'},{'\x00','\x00'},{'\x9e','\xf4'},{'\xc0','\x5b'},{'\x00','\x00'}, + {'\xe8','\xb8'},{'\xe8','\xbd'},{'\xe8','\xba'},{'\xe8','\xb9'},{'\x00','\x00'}, + {'\xbe','\x66'},{'\x82','\x7b'},{'\xc0','\x59'},{'\xfd','\xd3'},{'\xec','\x5a'}, + {'\xc0','\x55'},{'\x00','\x00'},{'\xec','\x5b'},{'\x9e','\xf5'},{'\x82','\x42'}, + {'\xec','\x59'},{'\x00','\x00'},{'\xc0','\x58'},{'\xc0','\x56'},{'\xc0','\x5a'}, + {'\x00','\x00'},{'\xc0','\x57'},{'\x93','\xdf'},{'\x97','\xa8'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xef','\x45'},{'\x00','\x00'},{'\xef','\x4a'}, + {'\xef','\x46'},{'\xef','\x49'},{'\xc1','\xfb'},{'\xfd','\xd5'},{'\xed','\xd4'}, + {'\xef','\x48'},{'\xef','\x47'},{'\xfd','\xd6'},{'\xc3','\x44'},{'\xc3','\x42'}, + {'\xc3','\x45'},{'\xc3','\x43'},{'\xf1','\xa8'},{'\xf1','\xa9'},{'\xf1','\xaa'}, + {'\xc3','\x46'},{'\x97','\xa9'},{'\x92','\xb8'},{'\x9d','\xd2'},{'\xf3','\xaa'}, + {'\xc4','\x40'},{'\xf3','\xa8'},{'\x00','\x00'},{'\xc4','\x41'},{'\xf3','\xa7'}, + {'\xf3','\xa9'},{'\xc3','\xfe'},{'\xf5','\x51'},{'\xf5','\x4e'},{'\x00','\x00'}, + {'\xf5','\x4f'},{'\xf5','\x50'},{'\xf6','\x72'},{'\xc5','\x56'},{'\xfd','\xd7'}, + {'\xc5','\x55'},{'\x9e','\xf6'},{'\xf7','\x74'},{'\xf7','\x73'},{'\xc5','\xb8'}, + {'\xfd','\xd8'},{'\x00','\x00'},{'\x00','\x00'},{'\xc5','\xe3'},{'\xc6','\x49'}, + {'\xc6','\x60'},{'\xf9','\x58'},{'\xf9','\xae'},{'\xf9','\xaf'},{'\x83','\xa4'}, + {'\x84','\xbc'},{'\x84','\xbd'},{'\x8d','\xfa'},{'\x85','\xa5'},{'\x85','\xa6'}, + {'\x85','\xa7'},{'\x86','\x7e'},{'\x86','\x7c'},{'\x8c','\xb8'},{'\x86','\x7d'}, + {'\x8e','\x62'},{'\x86','\xa1'},{'\x86','\xa2'},{'\x8e','\x61'},{'\x86','\x7b'}, + {'\x8d','\x77'},{'\x87','\x74'},{'\x87','\x73'},{'\x89','\xb0'},{'\x88','\xb3'}, + {'\x89','\xaf'},{'\x00','\x00'},{'\x88','\xb4'},{'\x8e','\xba'},{'\x00','\x00'}, + {'\x8e','\xdc'},{'\x89','\xb5'},{'\x89','\xb1'},{'\x00','\x00'},{'\x89','\xb4'}, + {'\x89','\xb2'},{'\x00','\x00'},{'\x89','\x46'},{'\x8a','\xb1'},{'\x8b','\x5f'}, + {'\x00','\x00'},{'\x8b','\x60'},{'\x8b','\x61'},{'\x8b','\x5e'},{'\x8b','\x5d'}, + {'\x90','\xa7'},{'\x8f','\xf0'},{'\x8b','\xde'},{'\x8f','\xcf'},{'\x8c','\xb9'}, + {'\x00','\x00'},{'\x8c','\xe9'},{'\x97','\xaa'},{'\x8d','\x61'},{'\x90','\xa8'}, + {'\xad','\xb7'},{'\xdc','\xad'},{'\x94','\xe2'},{'\x00','\x00'},{'\xe0','\xe1'}, + {'\xe4','\xcc'},{'\xe4','\xcd'},{'\xbb','\xe3'},{'\x00','\x00'},{'\xbb','\xe4'}, + {'\xe8','\xbe'},{'\xbe','\x68'},{'\xfd','\xd9'},{'\x00','\x00'},{'\xc1','\xfc'}, + {'\x9e','\xf7'},{'\xf1','\xab'},{'\x9e','\xf8'},{'\xc3','\x47'},{'\xf3','\xad'}, + {'\xc4','\x42'},{'\xf3','\xac'},{'\xf3','\xae'},{'\xf3','\xab'},{'\xf6','\x75'}, + {'\xf5','\x52'},{'\xf5','\x53'},{'\x97','\xab'},{'\xc4','\xc6'},{'\x00','\x00'}, + {'\xf6','\x74'},{'\x9e','\xf9'},{'\xfb','\xb2'},{'\xf6','\x73'},{'\x9e','\xfa'}, + {'\xf7','\x75'},{'\xf9','\xb0'},{'\x00','\x00'},{'\x83','\xa5'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x8e','\xae'},{'\x87','\x75'},{'\x8a','\xb2'},{'\x00','\x00'}, + {'\x8b','\xdf'},{'\x00','\x00'},{'\x00','\x00'},{'\x8c','\x61'},{'\x90','\x4a'}, + {'\x97','\xac'},{'\xad','\xb8'},{'\xfd','\xdb'},{'\x00','\x00'},{'\x83','\xa6'}, + {'\xad','\xb9'},{'\x9e','\xfb'},{'\x9e','\xfc'},{'\xb0','\xa7'},{'\xd4','\x48'}, + {'\x00','\x00'},{'\xd8','\x4f'},{'\xfd','\xdc'},{'\xb6','\xb8'},{'\x8c','\xba'}, + {'\xb6','\xbb'},{'\xb6','\xb9'},{'\xdc','\xae'},{'\x9e','\xfd'},{'\xb6','\xbd'}, + {'\x97','\xad'},{'\xb6','\xba'},{'\x00','\x00'},{'\x95','\xda'},{'\xb6','\xbc'}, + {'\x00','\x00'},{'\xb9','\x7e'},{'\x9e','\xfe'},{'\xe0','\xe2'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xe0','\xe3'},{'\xe8','\xc0'},{'\x00','\x00'},{'\xb9','\x7d'}, + {'\xb9','\xa1'},{'\xb9','\xa2'},{'\x00','\x00'},{'\xe4','\xcf'},{'\x00','\x00'}, + {'\xe4','\xce'},{'\xbb','\xe5'},{'\x00','\x00'},{'\xbb','\xe6'},{'\x00','\x00'}, + {'\xe4','\xd0'},{'\xe8','\xbf'},{'\xbb','\xe8'},{'\xbe','\x69'},{'\x00','\x00'}, + {'\xbb','\xe7'},{'\x8d','\x47'},{'\x9f','\x70'},{'\x00','\x00'},{'\xc0','\x5c'}, + {'\xe8','\xc1'},{'\xbe','\x6b'},{'\xbe','\x6a'},{'\xe8','\xc2'},{'\xe8','\xc5'}, + {'\xe8','\xc3'},{'\xe8','\xc4'},{'\xbe','\x6c'},{'\x9f','\x71'},{'\xc0','\x61'}, + {'\xc0','\x5f'},{'\x9f','\x72'},{'\x97','\xae'},{'\xc0','\x5e'},{'\xec','\x5d'}, + {'\x97','\xaf'},{'\xc0','\x60'},{'\x00','\x00'},{'\x00','\x00'},{'\xec','\x5c'}, + {'\xef','\x4b'},{'\x00','\x00'},{'\xec','\x5e'},{'\xc0','\x5d'},{'\xec','\x5f'}, + {'\xef','\x4e'},{'\xef','\x4c'},{'\xef','\x4d'},{'\xef','\x52'},{'\xc3','\x4b'}, + {'\xef','\x51'},{'\xef','\x54'},{'\xef','\x53'},{'\xef','\x50'},{'\xef','\x4f'}, + {'\x00','\x00'},{'\xc1','\xfd'},{'\x00','\x00'},{'\x9f','\x73'},{'\xa0','\x44'}, + {'\xfd','\xde'},{'\xf1','\xae'},{'\xfd','\xdf'},{'\xf1','\xad'},{'\xc3','\x4a'}, + {'\xc3','\x48'},{'\xc3','\x49'},{'\xfb','\xb3'},{'\xf1','\xac'},{'\xfd','\xdd'}, + {'\xf3','\xb1'},{'\x00','\x00'},{'\xc4','\x43'},{'\x00','\x00'},{'\xf3','\xb0'}, + {'\xf3','\xaf'},{'\xc4','\x44'},{'\xfd','\xe1'},{'\xf5','\x58'},{'\xf5','\x57'}, + {'\xfb','\xb4'},{'\xf5','\x55'},{'\x00','\x00'},{'\xf5','\x54'},{'\xc4','\xc8'}, + {'\xc4','\xc7'},{'\xf5','\x59'},{'\xf7','\x76'},{'\xc5','\xb9'},{'\xf6','\x77'}, + {'\xc5','\x57'},{'\xf6','\x76'},{'\xf5','\x56'},{'\x00','\x00'},{'\xf7','\x77'}, + {'\xc5','\xe4'},{'\x9f','\x74'},{'\xc6','\x61'},{'\xf9','\x59'},{'\x00','\x00'}, + {'\xf9','\xb1'},{'\x9f','\x75'},{'\x97','\xb0'},{'\x00','\x00'},{'\x83','\xe8'}, + {'\x00','\x00'},{'\x8f','\x6d'},{'\x85','\xaa'},{'\x8f','\xac'},{'\x85','\xa8'}, + {'\x8d','\xfb'},{'\x85','\xac'},{'\x85','\xa9'},{'\x85','\xab'},{'\x89','\xb7'}, + {'\x86','\xa6'},{'\x86','\xa5'},{'\x86','\xa3'},{'\x00','\x00'},{'\x86','\xa4'}, + {'\x87','\x78'},{'\x8c','\x62'},{'\x87','\x79'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x87','\x76'},{'\x00','\x00'},{'\x87','\x77'},{'\x8e','\xdd'},{'\x00','\x00'}, + {'\x88','\xb6'},{'\x97','\xb1'},{'\x88','\xb7'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x89','\xb8'},{'\x89','\xb9'},{'\x89','\xb6'},{'\x97','\xb2'},{'\x8b','\x64'}, + {'\x00','\x00'},{'\x8b','\x63'},{'\x8d','\x78'},{'\x00','\x00'},{'\x97','\xb3'}, + {'\x00','\x00'},{'\x8b','\x62'},{'\x8f','\xd0'},{'\x8b','\xe1'},{'\x8b','\xe0'}, + {'\x97','\xb4'},{'\x8f','\xf1'},{'\x97','\xb5'},{'\xad','\xba'},{'\xd8','\x50'}, + {'\xef','\x55'},{'\xad','\xbb'},{'\x00','\x00'},{'\x9f','\x76'},{'\xe4','\xd2'}, + {'\xe4','\xd1'},{'\xec','\x60'},{'\x00','\x00'},{'\x00','\x00'},{'\xef','\x57'}, + {'\x00','\x00'},{'\xef','\x56'},{'\x9f','\x77'},{'\xc3','\x4c'},{'\xf3','\xb2'}, + {'\xf3','\xb3'},{'\xc4','\xc9'},{'\x00','\x00'},{'\x9f','\x78'},{'\xf9','\xb2'}, + {'\xb0','\xa8'},{'\xb6','\xbf'},{'\xb6','\xbe'},{'\xe0','\xe4'},{'\xe0','\xe6'}, + {'\xb9','\xa4'},{'\xe0','\xe5'},{'\xb9','\xa3'},{'\xb9','\xa5'},{'\xe0','\xe7'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x9f','\x79'},{'\xe4','\xd4'},{'\xe4','\xd6'}, + {'\xe4','\xd5'},{'\x97','\xb6'},{'\xe4','\xd8'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xbb','\xe9'},{'\xe4','\xd7'},{'\xe4','\xd3'},{'\x94','\x4b'}, + {'\x92','\x4a'},{'\x92','\xa3'},{'\xe4','\xd9'},{'\x97','\xb7'},{'\xe8','\xcc'}, + {'\x00','\x00'},{'\xe8','\xcf'},{'\xe8','\xd1'},{'\xe8','\xc7'},{'\xe8','\xcb'}, + {'\xe8','\xc8'},{'\xbe','\x6e'},{'\xbe','\x71'},{'\xbe','\x73'},{'\xe8','\xc9'}, + {'\xe8','\xca'},{'\xbe','\x72'},{'\xe8','\xcd'},{'\xe8','\xd0'},{'\xe8','\xce'}, + {'\xbe','\x74'},{'\xfd','\xe4'},{'\xbe','\x70'},{'\xe8','\xc6'},{'\xbe','\x6d'}, + {'\x00','\x00'},{'\xbe','\x6f'},{'\x9f','\x7a'},{'\x95','\xc4'},{'\xc0','\x63'}, + {'\xec','\x66'},{'\xec','\x64'},{'\xec','\x63'},{'\x9f','\x7b'},{'\xec','\x69'}, + {'\x00','\x00'},{'\xec','\x68'},{'\xec','\x67'},{'\x00','\x00'},{'\xec','\x62'}, + {'\xc0','\x62'},{'\xec','\x61'},{'\x00','\x00'},{'\xec','\x65'},{'\xc0','\x64'}, + {'\x97','\xb8'},{'\x00','\x00'},{'\xef','\x5a'},{'\x9f','\x7c'},{'\xef','\x5e'}, + {'\xef','\x5b'},{'\xef','\x5d'},{'\xef','\x5c'},{'\xef','\x59'},{'\xef','\x5f'}, + {'\xef','\x62'},{'\xef','\x60'},{'\xef','\x61'},{'\xc2','\x40'},{'\x00','\x00'}, + {'\xc1','\xfe'},{'\xef','\x58'},{'\xef','\x63'},{'\xf1','\xb3'},{'\xf1','\xb6'}, + {'\xf1','\xb8'},{'\xf1','\xb7'},{'\x00','\x00'},{'\xf1','\xb1'},{'\xf1','\xb5'}, + {'\xf1','\xb0'},{'\xfb','\xb5'},{'\xf1','\xb2'},{'\xc3','\x4d'},{'\xf1','\xaf'}, + {'\x95','\xe1'},{'\xf1','\xb4'},{'\x93','\x5d'},{'\x92','\xb9'},{'\xf3','\xc0'}, + {'\xf3','\xb5'},{'\xc4','\x45'},{'\x00','\x00'},{'\x00','\x00'},{'\xc4','\x46'}, + {'\xf3','\xb4'},{'\xf3','\xb9'},{'\xf3','\xbf'},{'\xf3','\xb7'},{'\xf3','\xbe'}, + {'\x9f','\x7d'},{'\xf3','\xbb'},{'\x9a','\xfb'},{'\xf3','\xba'},{'\xf3','\xbd'}, + {'\xf3','\xb8'},{'\xf3','\xb6'},{'\x9a','\xfc'},{'\xf3','\xbc'},{'\x82','\x55'}, + {'\xf5','\x60'},{'\xf5','\x5e'},{'\xc4','\xca'},{'\xf5','\x5d'},{'\xf5','\x63'}, + {'\xf5','\x61'},{'\x9a','\xfd'},{'\xc4','\xcb'},{'\xf5','\x5c'},{'\xf5','\x5a'}, + {'\x00','\x00'},{'\xf5','\x5b'},{'\xc4','\xcd'},{'\xf5','\x5f'},{'\xc4','\xcc'}, + {'\xf5','\x62'},{'\xf6','\x78'},{'\xf6','\x7e'},{'\x9c','\xfa'},{'\x9c','\xfb'}, + {'\xf6','\x79'},{'\xc5','\x5b'},{'\xf6','\xa1'},{'\xc5','\x5a'},{'\xf6','\x7d'}, + {'\xf6','\x7c'},{'\xc5','\x59'},{'\xf6','\x7b'},{'\xc5','\x58'},{'\xf6','\x7a'}, + {'\x00','\x00'},{'\xf7','\x7d'},{'\xf7','\xa1'},{'\xf7','\x7e'},{'\x00','\x00'}, + {'\xf7','\x7b'},{'\xc5','\xbb'},{'\xf7','\x78'},{'\xf7','\x7c'},{'\xf7','\xa3'}, + {'\x00','\x00'},{'\xf7','\xa2'},{'\xf7','\x79'},{'\xf7','\x7a'},{'\xc5','\xba'}, + {'\xf8','\x52'},{'\xc5','\xe7'},{'\x9c','\xfc'},{'\xf8','\x53'},{'\xc5','\xe5'}, + {'\xc5','\xe6'},{'\x9c','\xfd'},{'\x00','\x00'},{'\xf8','\xd3'},{'\xc6','\x4a'}, + {'\xf9','\x76'},{'\x00','\x00'},{'\xc6','\x6a'},{'\x9c','\xfe'},{'\xf9','\xb3'}, + {'\xc6','\x6b'},{'\xf9','\xb4'},{'\xf9','\xb5'},{'\xf9','\xc3'},{'\xf9','\xc2'}, + {'\xc6','\x7a'},{'\xf9','\xcd'},{'\x83','\xe9'},{'\x85','\xae'},{'\x86','\xa8'}, + {'\x86','\xa9'},{'\x86','\xa7'},{'\x8c','\xbb'},{'\x00','\x00'},{'\x87','\x7a'}, + {'\x8d','\xa1'},{'\x8e','\xde'},{'\x88','\xbb'},{'\x88','\xba'},{'\x88','\xbf'}, + {'\x88','\xbe'},{'\x8f','\xf2'},{'\x88','\xb9'},{'\x88','\xb8'},{'\x88','\xbc'}, + {'\x88','\xbd'},{'\x8d','\x49'},{'\x8e','\xdf'},{'\x8c','\xeb'},{'\x88','\x4c'}, + {'\x00','\x00'},{'\x8c','\xea'},{'\x90','\x63'},{'\x89','\xbc'},{'\x89','\xba'}, + {'\x89','\xbb'},{'\x00','\x00'},{'\x8d','\xaf'},{'\x8a','\xb3'},{'\x8d','\x4a'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x8a','\xb4'},{'\x8f','\xad'},{'\x8b','\x65'}, + {'\x8f','\xae'},{'\x8f','\xaf'},{'\x00','\x00'},{'\x00','\x00'},{'\x90','\x4c'}, + {'\x8b','\xe3'},{'\x8f','\xf5'},{'\x00','\x00'},{'\x8c','\x66'},{'\x8b','\xe2'}, + {'\x90','\x4d'},{'\x8f','\xf3'},{'\x8c','\x64'},{'\x8f','\xf4'},{'\x8c','\xbc'}, + {'\x8c','\xbe'},{'\x90','\x4b'},{'\x90','\x62'},{'\x8d','\x62'},{'\x8d','\xa2'}, + {'\x00','\x00'},{'\x90','\xa9'},{'\xb0','\xa9'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xe0','\xe9'},{'\x00','\x00'},{'\xe0','\xe8'},{'\x00','\x00'},{'\xbb','\xea'}, + {'\xbb','\xeb'},{'\xe4','\xda'},{'\x9d','\xb0'},{'\xe8','\xd2'},{'\xec','\x6c'}, + {'\x00','\x00'},{'\x97','\xb9'},{'\xbe','\x75'},{'\xc0','\x65'},{'\xec','\x6a'}, + {'\xfd','\xe6'},{'\xec','\x6d'},{'\xc0','\x66'},{'\xfd','\xe7'},{'\xef','\x64'}, + {'\xec','\x6b'},{'\xf1','\xb9'},{'\xc3','\x4e'},{'\xf3','\xc1'},{'\x00','\x00'}, + {'\x92','\xfb'},{'\x8c','\xbf'},{'\xf5','\x66'},{'\xf5','\x64'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xf5','\x65'},{'\x8d','\x79'},{'\x90','\x79'},{'\xf6','\xa2'}, + {'\x00','\x00'},{'\xc5','\x5c'},{'\xf7','\xa4'},{'\xc5','\xea'},{'\xc5','\xbc'}, + {'\xc5','\xe8'},{'\xc5','\xe9'},{'\xf8','\xd4'},{'\xc6','\x62'},{'\xfb','\xb6'}, + {'\xb0','\xaa'},{'\x97','\xba'},{'\x00','\x00'},{'\x00','\x00'},{'\xf1','\xba'}, + {'\x00','\x00'},{'\x97','\xbb'},{'\xd4','\x49'},{'\x9d','\xb1'},{'\xb9','\xa6'}, + {'\xfd','\xec'},{'\xe4','\xdb'},{'\x00','\x00'},{'\x00','\x00'},{'\xbb','\xec'}, + {'\xe4','\xdc'},{'\x00','\x00'},{'\x00','\x00'},{'\x93','\xba'},{'\xe8','\xd4'}, + {'\xe8','\xd3'},{'\xc0','\x68'},{'\xbe','\x76'},{'\xbe','\x77'},{'\x00','\x00'}, + {'\xe8','\xd7'},{'\xe8','\xd6'},{'\xe8','\xd5'},{'\xfe','\x57'},{'\x00','\x00'}, + {'\xec','\x6e'},{'\xec','\x71'},{'\x00','\x00'},{'\xec','\x70'},{'\xec','\x6f'}, + {'\xc0','\x67'},{'\xef','\x68'},{'\xef','\x66'},{'\xef','\x65'},{'\xfd','\xee'}, + {'\x00','\x00'},{'\xef','\x67'},{'\xfd','\xed'},{'\xc3','\x4f'},{'\xf1','\xbc'}, + {'\xf1','\xbd'},{'\xc3','\x50'},{'\x00','\x00'},{'\xf1','\xbb'},{'\xfd','\xf0'}, + {'\xf3','\xc3'},{'\xf3','\xc2'},{'\xf3','\xc5'},{'\xc4','\x47'},{'\xf3','\xc4'}, + {'\x97','\xbc'},{'\xf5','\x67'},{'\xf5','\x69'},{'\xf5','\x68'},{'\x8d','\x63'}, + {'\x9d','\xb2'},{'\xf6','\xa3'},{'\xf6','\xa6'},{'\xf6','\xa4'},{'\xf6','\xa5'}, + {'\xf7','\xa5'},{'\xc5','\xbd'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xf8','\x54'},{'\xf8','\x55'},{'\xf8','\x56'},{'\x00','\x00'},{'\xc6','\x4b'}, + {'\xc6','\x63'},{'\xf9','\xb6'},{'\xb0','\xab'},{'\x00','\x00'},{'\xbe','\x78'}, + {'\xc0','\x69'},{'\xf1','\xbe'},{'\xfd','\xe9'},{'\xf7','\xa6'},{'\x00','\x00'}, + {'\xfd','\xeb'},{'\xf9','\xc4'},{'\xd4','\x4a'},{'\x00','\x00'},{'\xc6','\x7b'}, + {'\xb0','\xac'},{'\xec','\x72'},{'\x9d','\xb3'},{'\xf1','\xbf'},{'\x00','\x00'}, + {'\xf3','\xc6'},{'\x00','\x00'},{'\x9d','\xb4'},{'\xf6','\xa7'},{'\xf7','\xa7'}, + {'\xb0','\xad'},{'\x00','\x00'},{'\xe4','\xdd'},{'\xe4','\xde'},{'\x9d','\xb5'}, + {'\xbb','\xed'},{'\xbb','\xee'},{'\xe8','\xd9'},{'\xbe','\x7a'},{'\xbe','\x79'}, + {'\xe8','\xd8'},{'\x8d','\x64'},{'\xef','\x69'},{'\x97','\xbd'},{'\xf1','\xc0'}, + {'\xf1','\xc2'},{'\xf1','\xc1'},{'\xc3','\x53'},{'\xc3','\x52'},{'\xc3','\x51'}, + {'\x9d','\xb6'},{'\xc5','\x5e'},{'\xf6','\xa8'},{'\x00','\x00'},{'\xc5','\x5d'}, + {'\xf7','\xa9'},{'\xf7','\xa8'},{'\x00','\x00'},{'\xc6','\x4c'},{'\xf8','\xd5'}, + {'\xb3','\xbd'},{'\xe0','\xea'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xe4','\xe1'},{'\xe4','\xdf'},{'\xe4','\xe0'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xe8','\xe2'},{'\x00','\x00'},{'\xe8','\xdd'},{'\xe8','\xda'},{'\xe8','\xe1'}, + {'\xfe','\xaf'},{'\x00','\x00'},{'\x00','\x00'},{'\xe8','\xe3'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xbe','\x7c'},{'\xe8','\xe0'},{'\xe8','\xdc'},{'\x97','\xbe'}, + {'\x00','\x00'},{'\xe8','\xdb'},{'\xe8','\xdf'},{'\xe8','\xde'},{'\xbe','\x7b'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xec','\x7d'},{'\xec','\x78'},{'\xec','\x76'}, + {'\xec','\xa1'},{'\xec','\x77'},{'\x9d','\xb7'},{'\xec','\x73'},{'\x9d','\xee'}, + {'\xec','\x79'},{'\x97','\xbf'},{'\x00','\x00'},{'\xec','\x74'},{'\xef','\x72'}, + {'\xec','\x75'},{'\xec','\xa2'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\xef'}, + {'\x00','\x00'},{'\x9d','\xf0'},{'\x94','\xfe'},{'\xfd','\xf3'},{'\xec','\x7c'}, + {'\xc0','\x6a'},{'\xec','\x7b'},{'\xec','\x7a'},{'\x00','\x00'},{'\xec','\x7e'}, + {'\x94','\xe3'},{'\x94','\xe4'},{'\x00','\x00'},{'\x00','\x00'},{'\xef','\x6a'}, + {'\xef','\x6d'},{'\x00','\x00'},{'\xfd','\xf4'},{'\xef','\x6c'},{'\x97','\xc0'}, + {'\xef','\x74'},{'\xef','\x6f'},{'\xef','\x73'},{'\x00','\x00'},{'\xef','\x71'}, + {'\xef','\x70'},{'\xef','\x6e'},{'\x00','\x00'},{'\xef','\x6b'},{'\x00','\x00'}, + {'\xc2','\x43'},{'\xc2','\x42'},{'\x00','\x00'},{'\xc2','\x44'},{'\xc2','\x41'}, + {'\xef','\x75'},{'\xfd','\xf5'},{'\x94','\xf5'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x94','\xe5'},{'\xf1','\xc8'},{'\xf1','\xcb'},{'\x00','\x00'},{'\xf1','\xc9'}, + {'\xf1','\xcd'},{'\x00','\x00'},{'\x97','\xc1'},{'\x00','\x00'},{'\xf1','\xce'}, + {'\x00','\x00'},{'\xf1','\xc6'},{'\xc3','\x58'},{'\xf1','\xc7'},{'\x00','\x00'}, + {'\xf1','\xc5'},{'\xf1','\xcc'},{'\x00','\x00'},{'\xf1','\xc4'},{'\xf1','\xc3'}, + {'\xc3','\x57'},{'\xc3','\x55'},{'\xc3','\x54'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x94','\xe6'},{'\x00','\x00'},{'\x94','\xe7'}, + {'\x94','\xe8'},{'\xf1','\xca'},{'\xf3','\xcf'},{'\xf3','\xd5'},{'\xc4','\x4a'}, + {'\xf3','\xd0'},{'\x00','\x00'},{'\xf3','\xd3'},{'\xf3','\xd7'},{'\xc4','\x4b'}, + {'\xf3','\xd2'},{'\x9d','\xf1'},{'\xf3','\xca'},{'\x00','\x00'},{'\xf3','\xc9'}, + {'\xf3','\xd6'},{'\xf3','\xcd'},{'\x97','\xc2'},{'\xf3','\xcb'},{'\xf3','\xd4'}, + {'\xf3','\xcc'},{'\xc4','\x49'},{'\xc4','\x48'},{'\x9d','\xf2'},{'\xf3','\xc7'}, + {'\xf3','\xc8'},{'\xf3','\xd1'},{'\x9d','\xf3'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xf3','\xce'},{'\x94','\xea'},{'\x94','\xe9'},{'\x00','\x00'},{'\x9d','\xf4'}, + {'\x97','\xc3'},{'\x00','\x00'},{'\xf5','\x6c'},{'\xf5','\x6f'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xc3','\x56'},{'\x00','\x00'}, + {'\xfd','\xf9'},{'\x97','\xc4'},{'\x00','\x00'},{'\xfe','\x50'},{'\x00','\x00'}, + {'\x97','\xc5'},{'\xf5','\x6d'},{'\xf5','\x73'},{'\xf5','\x71'},{'\xf5','\x6b'}, + {'\xf5','\x76'},{'\xfd','\xf8'},{'\xf5','\x6a'},{'\xfd','\xf6'},{'\xc4','\xcf'}, + {'\xf5','\x72'},{'\x00','\x00'},{'\x95','\xfd'},{'\x00','\x00'},{'\xf5','\x6e'}, + {'\xc4','\xce'},{'\xf5','\x75'},{'\xfd','\xf7'},{'\x00','\x00'},{'\xf5','\x74'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x97','\xc6'},{'\xf6','\xab'}, + {'\xf6','\xaa'},{'\x00','\x00'},{'\x9d','\xf5'},{'\x9d','\xf6'},{'\xf6','\xb1'}, + {'\x00','\x00'},{'\xf6','\xad'},{'\xf6','\xb0'},{'\xc5','\x60'},{'\x9d','\xf7'}, + {'\x00','\x00'},{'\xf6','\xae'},{'\xf6','\xaf'},{'\x00','\x00'},{'\xf6','\xa9'}, + {'\xf6','\xac'},{'\xc5','\x5f'},{'\xfd','\xfa'},{'\x94','\xf9'},{'\x94','\xeb'}, + {'\xc5','\xbf'},{'\xf7','\xb4'},{'\xf7','\xaf'},{'\xf7','\xb3'},{'\xfd','\x53'}, + {'\xf7','\xb6'},{'\xf7','\xb2'},{'\x00','\x00'},{'\xf7','\xae'},{'\xfc','\xcb'}, + {'\xc5','\xc1'},{'\xf7','\xb1'},{'\xf7','\xb5'},{'\xc5','\xc0'},{'\xf7','\xac'}, + {'\xf5','\x70'},{'\xf7','\xb0'},{'\x00','\x00'},{'\x00','\x00'},{'\xf7','\xad'}, + {'\xfd','\x70'},{'\xf7','\xaa'},{'\x94','\xec'},{'\xf7','\xab'},{'\xc5','\xbe'}, + {'\xf8','\x5a'},{'\xf8','\x5c'},{'\xf8','\x5f'},{'\xf8','\x5b'},{'\xf8','\x60'}, + {'\x9f','\x50'},{'\xf8','\x59'},{'\x00','\x00'},{'\xf8','\x57'},{'\x9d','\xf8'}, + {'\xc5','\xeb'},{'\xf8','\x5d'},{'\xc5','\xed'},{'\xc5','\xec'},{'\xf8','\x58'}, + {'\xf8','\x5e'},{'\x94','\xed'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\xf9'}, + {'\xf8','\xda'},{'\xc6','\x4d'},{'\xf8','\xdb'},{'\x00','\x00'},{'\xf8','\xd9'}, + {'\xf8','\xd6'},{'\x00','\x00'},{'\x00','\x00'},{'\xf8','\xd8'},{'\xf8','\xd7'}, + {'\xf9','\x5a'},{'\x94','\xf6'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xf9','\x5c'},{'\xf9','\x5b'},{'\x00','\x00'},{'\x00','\x00'},{'\xf9','\x79'}, + {'\xfb','\x78'},{'\xf9','\x78'},{'\xf9','\x77'},{'\xf9','\x7a'},{'\x98','\x40'}, + {'\xc6','\x73'},{'\xc6','\x74'},{'\xf9','\xca'},{'\xf9','\xce'},{'\x9d','\xfa'}, + {'\x84','\xbe'},{'\x00','\x00'},{'\x00','\x00'},{'\x88','\xc2'},{'\x00','\x00'}, + {'\x88','\xc3'},{'\x8e','\xe0'},{'\x00','\x00'},{'\x00','\x00'},{'\x98','\x4b'}, + {'\x98','\x4c'},{'\x98','\x4d'},{'\x8d','\xab'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x98','\x4e'},{'\x00','\x00'},{'\x89','\xbf'},{'\x8d','\x65'},{'\x00','\x00'}, + {'\x98','\x4f'},{'\x8a','\xb8'},{'\x8f','\x6e'},{'\x00','\x00'},{'\x8a','\xb7'}, + {'\x8f','\x6f'},{'\x00','\x00'},{'\x90','\xf2'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x90','\xa2'},{'\x8a','\xb6'},{'\x8a','\xb5'},{'\x00','\x00'},{'\x98','\x50'}, + {'\x90','\x70'},{'\x8f','\xb2'},{'\x90','\xad'},{'\x8c','\xed'},{'\x90','\x65'}, + {'\x8b','\x68'},{'\x90','\x4e'},{'\x90','\x66'},{'\x8b','\x6a'},{'\x8b','\x67'}, + {'\x8f','\xb1'},{'\x00','\x00'},{'\x8b','\x69'},{'\x00','\x00'},{'\x8b','\xe6'}, + {'\x98','\x51'},{'\x00','\x00'},{'\x98','\x52'},{'\x8f','\xd5'},{'\x98','\x53'}, + {'\x8b','\xe5'},{'\x98','\x54'},{'\x8f','\xd2'},{'\x8f','\xd3'},{'\x8b','\xe7'}, + {'\x8b','\xe4'},{'\x00','\x00'},{'\x98','\x55'},{'\x8f','\xd4'},{'\x98','\x56'}, + {'\x98','\x57'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x8c','\x67'},{'\x8d','\xaa'},{'\x8c','\x68'},{'\x98','\x58'}, + {'\x98','\x59'},{'\x00','\x00'},{'\x00','\x00'},{'\x98','\x5a'},{'\x98','\x5b'}, + {'\x8d','\x6a'},{'\x8c','\xc0'},{'\x90','\x4f'},{'\x8c','\xc1'},{'\x90','\x50'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x98','\x5c'},{'\x8c','\xee'},{'\x90','\x64'}, + {'\x8c','\xec'},{'\x8c','\xef'},{'\x98','\x5d'},{'\x98','\x5e'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x8d','\x4f'},{'\x8d','\x4d'},{'\x8d','\x4e'},{'\x90','\x6f'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x98','\x5f'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xb3','\xbe'},{'\xdc','\xaf'},{'\xe0','\xed'},{'\x00','\x00'},{'\xb9','\xa7'}, + {'\xe0','\xeb'},{'\x98','\x60'},{'\x98','\x61'},{'\xe0','\xec'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x94','\xee'},{'\xe4','\xe2'},{'\xe4','\xe3'},{'\xbb','\xf1'}, + {'\xbb','\xef'},{'\xe4','\xe4'},{'\xbb','\xf0'},{'\xe8','\xe8'},{'\x00','\x00'}, + {'\xe8','\xeb'},{'\xe8','\xe5'},{'\xe8','\xec'},{'\xe8','\xe4'},{'\xe8','\xe6'}, + {'\x00','\x00'},{'\xe8','\xe7'},{'\xe8','\xea'},{'\x00','\x00'},{'\xfd','\x61'}, + {'\xbe','\xa1'},{'\xe8','\xef'},{'\xe8','\xee'},{'\xbe','\x7d'},{'\xe8','\xe9'}, + {'\xe8','\xed'},{'\xbe','\x7e'},{'\x00','\x00'},{'\x00','\x00'},{'\x9d','\xfb'}, + {'\x00','\x00'},{'\x82','\x48'},{'\x00','\x00'},{'\xec','\xac'},{'\x00','\x00'}, + {'\xc0','\x6f'},{'\x00','\x00'},{'\xec','\xa7'},{'\xc0','\x6b'},{'\x9d','\xfc'}, + {'\xec','\xa4'},{'\xec','\xaa'},{'\xec','\xad'},{'\x00','\x00'},{'\xc0','\x70'}, + {'\x00','\x00'},{'\xec','\xa9'},{'\xec','\xa6'},{'\xec','\xae'},{'\xec','\xa5'}, + {'\x9f','\x40'},{'\xec','\xab'},{'\xc0','\x6c'},{'\x00','\x00'},{'\xec','\xa3'}, + {'\xc0','\x6d'},{'\x00','\x00'},{'\xc0','\x6e'},{'\xec','\xa8'},{'\x98','\x62'}, + {'\x94','\x47'},{'\x82','\x47'},{'\xef','\xa9'},{'\xef','\x7a'},{'\xef','\x7b'}, + {'\xef','\x7e'},{'\xef','\x7c'},{'\x00','\x00'},{'\xef','\x76'},{'\x9f','\x41'}, + {'\x00','\x00'},{'\xef','\x79'},{'\xef','\xa5'},{'\xef','\x7d'},{'\x9f','\x42'}, + {'\x00','\x00'},{'\xc2','\x45'},{'\x00','\x00'},{'\xef','\xa7'},{'\xef','\xa4'}, + {'\xc2','\x46'},{'\xef','\xa6'},{'\xef','\x77'},{'\xef','\xa2'},{'\xef','\xa3'}, + {'\xfd','\xaa'},{'\xef','\xa1'},{'\x94','\xef'},{'\x94','\xf7'},{'\x98','\x63'}, + {'\x9f','\x43'},{'\xf1','\xd2'},{'\xf1','\xd4'},{'\xf1','\xd7'},{'\x00','\x00'}, + {'\x9f','\x44'},{'\xf1','\xd1'},{'\x98','\x64'},{'\xc3','\x59'},{'\xf1','\xd9'}, + {'\xf1','\xd0'},{'\xf1','\xda'},{'\x00','\x00'},{'\xf1','\xd6'},{'\xf1','\xd8'}, + {'\xf1','\xdc'},{'\xf1','\xd5'},{'\xf1','\xdd'},{'\xf1','\xd3'},{'\xf1','\xcf'}, + {'\xc3','\x5a'},{'\x95','\x72'},{'\xf1','\xdb'},{'\xc3','\x5b'},{'\xc4','\x4d'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x94','\xf0'},{'\x94','\xf8'},{'\x00','\x00'}, + {'\xef','\x78'},{'\xf3','\xf1'},{'\xf3','\xe8'},{'\xc4','\x4f'},{'\xf3','\xe4'}, + {'\xc4','\x50'},{'\x9f','\x45'},{'\x9f','\x47'},{'\xf3','\xed'},{'\xf3','\xe7'}, + {'\xf3','\xdd'},{'\xc4','\x4e'},{'\xf3','\xea'},{'\xf3','\xe5'},{'\xf3','\xe6'}, + {'\x00','\x00'},{'\xf3','\xd8'},{'\xf3','\xdf'},{'\xf3','\xee'},{'\x98','\x65'}, + {'\xf3','\xeb'},{'\x9f','\x48'},{'\xf3','\xe3'},{'\xfc','\xc6'},{'\xf3','\xef'}, + {'\xf3','\xde'},{'\xf3','\xd9'},{'\xf3','\xec'},{'\x9f','\x49'},{'\xf3','\xdb'}, + {'\xf3','\xe9'},{'\xf3','\xe0'},{'\xf3','\xf0'},{'\xf3','\xdc'},{'\xc4','\x4c'}, + {'\xf3','\xda'},{'\xf3','\xe1'},{'\xf3','\xe2'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x92','\xaf'},{'\xf5','\x7d'},{'\x00','\x00'},{'\xf5','\x7b'},{'\x9f','\x4a'}, + {'\xf5','\xa2'},{'\x00','\x00'},{'\xf5','\xae'},{'\xf5','\xa5'},{'\xf5','\x7c'}, + {'\xf5','\x78'},{'\xf5','\xa7'},{'\xf5','\x7e'},{'\xf5','\xa3'},{'\xf5','\x7a'}, + {'\xf5','\xaa'},{'\xf5','\x77'},{'\xf5','\xa1'},{'\xf5','\xa6'},{'\xf5','\xa8'}, + {'\xf5','\xab'},{'\xf5','\x79'},{'\x9f','\x4b'},{'\xf5','\xaf'},{'\xf5','\xb0'}, + {'\xf5','\xa9'},{'\xf5','\xad'},{'\xf5','\xa4'},{'\x94','\xf1'},{'\xf6','\xc1'}, + {'\xf6','\xc4'},{'\x00','\x00'},{'\xc5','\x61'},{'\x00','\x00'},{'\xf6','\xc3'}, + {'\xf6','\xc8'},{'\xf6','\xc6'},{'\xc5','\x62'},{'\xf6','\xbd'},{'\xf6','\xb3'}, + {'\xf6','\xb2'},{'\xc5','\x64'},{'\xf6','\xbf'},{'\xf6','\xc0'},{'\xf6','\xbc'}, + {'\xf6','\xb4'},{'\x9f','\x4d'},{'\xf6','\xb9'},{'\xf5','\xac'},{'\x9f','\x52'}, + {'\xf6','\xb5'},{'\xc5','\x63'},{'\xf6','\xbb'},{'\x95','\x75'},{'\xf6','\xba'}, + {'\x98','\x66'},{'\xf6','\xb6'},{'\xf6','\xc2'},{'\x9f','\x5e'},{'\xf6','\xb7'}, + {'\xf7','\xbb'},{'\xf6','\xc5'},{'\xf6','\xc7'},{'\xf6','\xbe'},{'\xf6','\xb8'}, + {'\xf7','\xbc'},{'\xf7','\xbe'},{'\xf7','\xb8'},{'\xc5','\xc2'},{'\x9f','\x5f'}, + {'\xf7','\xc5'},{'\xf7','\xc3'},{'\xc5','\xc3'},{'\xf7','\xc2'},{'\xf7','\xc1'}, + {'\xf7','\xba'},{'\xf7','\xb7'},{'\xf7','\xbd'},{'\xf7','\xc6'},{'\xf7','\xb9'}, + {'\xf7','\xbf'},{'\x00','\x00'},{'\xf8','\x69'},{'\xf8','\x6e'},{'\xf8','\x64'}, + {'\xf8','\x67'},{'\xc5','\xee'},{'\xf8','\x6b'},{'\x00','\x00'},{'\xf8','\x72'}, + {'\xf7','\xc0'},{'\x00','\x00'},{'\xf8','\x65'},{'\xf8','\x6f'},{'\xf8','\x73'}, + {'\xf8','\x6a'},{'\xf8','\x63'},{'\xf8','\x6d'},{'\x00','\x00'},{'\xf8','\x6c'}, + {'\xf8','\x71'},{'\xf8','\x70'},{'\xf7','\xc4'},{'\xf8','\x68'},{'\xf8','\x62'}, + {'\xf8','\x66'},{'\xc6','\x4e'},{'\xc6','\x4f'},{'\xf8','\x61'},{'\x9f','\x60'}, + {'\xf8','\xe6'},{'\xf8','\xdd'},{'\xf8','\xe5'},{'\xf8','\xe2'},{'\xf8','\xe3'}, + {'\xf8','\xdc'},{'\xf8','\xdf'},{'\xf8','\xe7'},{'\xf8','\xe1'},{'\xf8','\xe0'}, + {'\xf8','\xde'},{'\x00','\x00'},{'\xf8','\xe4'},{'\x9f','\x61'},{'\xf9','\x5d'}, + {'\x9f','\x62'},{'\xf9','\x5e'},{'\x9f','\x63'},{'\xf9','\x60'},{'\xf9','\x5f'}, + {'\xf9','\x62'},{'\xf9','\x61'},{'\xf9','\x7c'},{'\xf9','\x7b'},{'\xf9','\xb7'}, + {'\x00','\x00'},{'\xf9','\xb8'},{'\x9f','\x64'},{'\xf9','\xc5'},{'\xc6','\x78'}, + {'\xc6','\x7c'},{'\xfd','\x4a'},{'\xf9','\xcf'},{'\xc6','\x7d'},{'\x84','\xbf'}, + {'\x86','\xaa'},{'\x8b','\x5c'},{'\x87','\x7e'},{'\x87','\x7d'},{'\x00','\x00'}, + {'\x8c','\xf1'},{'\x88','\xc5'},{'\x00','\x00'},{'\x8e','\xe1'},{'\x88','\xc4'}, + {'\x89','\xc1'},{'\x8f','\xd7'},{'\x90','\xaa'},{'\x89','\xc3'},{'\x00','\x00'}, + {'\x89','\xc2'},{'\x00','\x00'},{'\x8f','\x4e'},{'\x8f','\x4d'},{'\x89','\xc4'}, + {'\x00','\x00'},{'\x89','\xc0'},{'\x8d','\x50'},{'\x90','\x68'},{'\x8f','\x70'}, + {'\x8f','\x71'},{'\x8f','\x72'},{'\x00','\x00'},{'\x00','\x00'},{'\x8a','\xba'}, + {'\x8d','\xb1'},{'\x8a','\xb9'},{'\x00','\x00'},{'\x8f','\xb4'},{'\x90','\xae'}, + {'\x8b','\x6b'},{'\x8b','\x6d'},{'\x8b','\x6c'},{'\x8f','\xb5'},{'\x90','\x75'}, + {'\x8f','\xb3'},{'\x8b','\xe9'},{'\x8b','\xea'},{'\x98','\x67'},{'\x8b','\xeb'}, + {'\x00','\x00'},{'\x8f','\xd6'},{'\x8b','\xec'},{'\x00','\x00'},{'\x8b','\xe8'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x98','\x68'},{'\x00','\x00'}, + {'\x8f','\xf6'},{'\x90','\x52'},{'\x00','\x00'},{'\x8f','\xf7'},{'\x98','\x69'}, + {'\x8f','\xf8'},{'\x00','\x00'},{'\x8c','\xc4'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x90','\x51'},{'\x8c','\xc3'},{'\x00','\x00'}, + {'\x8d','\xae'},{'\x8c','\xf0'},{'\x90','\x67'},{'\x90','\x71'},{'\x90','\x73'}, + {'\x90','\x74'},{'\x90','\x72'},{'\x8d','\x67'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x8d','\x66'},{'\x98','\x6a'},{'\x00','\x00'},{'\x8d','\xb0'},{'\x00','\x00'}, + {'\xb3','\xbf'},{'\x00','\x00'},{'\x00','\x00'},{'\x82','\x5e'},{'\xc4','\xd0'}, + {'\xf6','\xc9'},{'\x9f','\x65'},{'\xc6','\x50'},{'\xc6','\x51'},{'\x90','\x53'}, + {'\xb3','\xc0'},{'\xe0','\xee'},{'\xfc','\xfd'},{'\xb9','\xa8'},{'\xe8','\xf0'}, + {'\xfb','\x5e'},{'\x9f','\x66'},{'\xec','\xb0'},{'\xec','\xb1'},{'\xec','\xaf'}, + {'\xef','\xab'},{'\xef','\xaa'},{'\xc2','\x47'},{'\xf1','\xdf'},{'\xef','\xac'}, + {'\xf1','\xde'},{'\x00','\x00'},{'\x9f','\x51'},{'\xf3','\xf3'},{'\xc4','\x51'}, + {'\xc4','\x53'},{'\xf3','\xf2'},{'\xfc','\xf4'},{'\xfb','\x7c'},{'\xc4','\x52'}, + {'\xfb','\xb7'},{'\xf5','\xb1'},{'\xf5','\xb3'},{'\xf5','\xb2'},{'\xf6','\xca'}, + {'\xc5','\x65'},{'\xfd','\x48'},{'\xc5','\xef'},{'\xf8','\xe8'},{'\xf9','\x63'}, + {'\x9f','\x67'},{'\x00','\x00'},{'\xf9','\xd2'},{'\xb3','\xc1'},{'\x84','\xc1'}, + {'\xe4','\xe5'},{'\xfd','\xb4'},{'\xbe','\xa2'},{'\x98','\x6b'},{'\xfb','\xa2'}, + {'\x9f','\x68'},{'\xec','\xb3'},{'\xec','\xb2'},{'\x95','\x73'},{'\xef','\xad'}, + {'\x9f','\x69'},{'\x00','\x00'},{'\x00','\x00'},{'\xc4','\x54'},{'\xc4','\xd1'}, + {'\xf7','\xc7'},{'\xf9','\xcb'},{'\x88','\xc6'},{'\x82','\x60'},{'\x82','\x61'}, + {'\xb3','\xc2'},{'\xbb','\xf2'},{'\x98','\x6c'},{'\xbe','\xa3'},{'\x94','\xfa'}, + {'\xf3','\xf4'},{'\x9f','\x6a'},{'\xf8','\x74'},{'\xb6','\xc0'},{'\x98','\x6d'}, + {'\x00','\x00'},{'\x9f','\x6b'},{'\x9f','\x6c'},{'\xef','\xae'},{'\x8d','\x7a'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc6','\x64'},{'\xb6','\xc1'},{'\xbe','\xa4'}, + {'\xc2','\x48'},{'\xf8','\x75'},{'\xb6','\xc2'},{'\x92','\xc3'},{'\xe8','\xf1'}, + {'\xc0','\x72'},{'\xec','\xb4'},{'\xec','\xb5'},{'\x00','\x00'},{'\xc0','\x71'}, + {'\x93','\xd4'},{'\xef','\xaf'},{'\xc2','\x4c'},{'\xc2','\x4a'},{'\xc2','\x4b'}, + {'\xc2','\x49'},{'\xf1','\xe0'},{'\xc3','\x5c'},{'\x00','\x00'},{'\x98','\x6e'}, + {'\x00','\x00'},{'\xf5','\xb5'},{'\xf5','\xb4'},{'\xf5','\xb7'},{'\xf5','\xb6'}, + {'\xc4','\xd2'},{'\x8d','\xac'},{'\x98','\x6f'},{'\xf6','\xcb'},{'\x00','\x00'}, + {'\xf6','\xcd'},{'\xf6','\xcc'},{'\xc5','\x66'},{'\xf7','\xc8'},{'\x9f','\x6d'}, + {'\xf8','\x76'},{'\xf8','\x77'},{'\xc5','\xf0'},{'\xf9','\x64'},{'\xf9','\x7d'}, + {'\xc6','\x75'},{'\x9f','\x6e'},{'\xdc','\xb0'},{'\xec','\xb6'},{'\xef','\xb0'}, + {'\xf3','\xf5'},{'\xe0','\xef'},{'\x8e','\x64'},{'\xef','\xb1'},{'\xf1','\xe2'}, + {'\xf1','\xe1'},{'\xfd','\xe8'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xf8','\x78'},{'\xc6','\x52'},{'\x98','\x70'},{'\xf9','\x65'},{'\xf9','\x7e'}, + {'\x98','\x71'},{'\x00','\x00'},{'\x98','\x72'},{'\xb9','\xa9'},{'\xe8','\xf2'}, + {'\xe8','\xf3'},{'\x00','\x00'},{'\xec','\xb7'},{'\xb9','\xaa'},{'\x00','\x00'}, + {'\xc3','\x5d'},{'\xf1','\xe3'},{'\xfc','\xdb'},{'\xf6','\xcf'},{'\xc5','\x67'}, + {'\xf6','\xd0'},{'\xf6','\xce'},{'\xf8','\x79'},{'\x00','\x00'},{'\xf8','\xe9'}, + {'\x00','\x00'},{'\xb9','\xab'},{'\x98','\x73'},{'\xef','\xb4'},{'\xef','\xb3'}, + {'\xef','\xb2'},{'\xf1','\xe4'},{'\xfb','\xb8'},{'\x9f','\x6f'},{'\xf1','\xe8'}, + {'\xf1','\xe7'},{'\xf1','\xe6'},{'\xf1','\xe5'},{'\xc3','\x5e'},{'\xf3','\xf6'}, + {'\xf5','\xb9'},{'\xc4','\xd3'},{'\xf5','\xb8'},{'\xf6','\xd1'},{'\xf7','\xcb'}, + {'\xf7','\xca'},{'\xc5','\xc4'},{'\xf7','\xc9'},{'\xf8','\x7c'},{'\xf8','\x7b'}, + {'\xf8','\x7a'},{'\x8c','\xf2'},{'\x00','\x00'},{'\xbb','\xf3'},{'\x00','\x00'}, + {'\xec','\xb8'},{'\xc2','\x4d'},{'\x00','\x00'},{'\xf3','\xf7'},{'\xf3','\xf8'}, + {'\xf7','\xcc'},{'\xf8','\x7d'},{'\x98','\x74'},{'\xfd','\xe2'},{'\xf8','\xea'}, + {'\xf9','\x66'},{'\xf9','\xb9'},{'\xf9','\xd4'},{'\xbb','\xf4'},{'\xc2','\x4e'}, + {'\xf1','\xe9'},{'\xf3','\xf9'},{'\xf6','\xd2'},{'\xf8','\x7e'},{'\x87','\xa2'}, + {'\x98','\x75'},{'\xbe','\xa6'},{'\xfd','\xe0'},{'\xef','\xb5'},{'\xf1','\xea'}, + {'\xf3','\xfa'},{'\xf3','\xfb'},{'\xf3','\xfc'},{'\xf5','\xbe'},{'\xfd','\xda'}, + {'\xf5','\xba'},{'\xc5','\x68'},{'\xf5','\xbd'},{'\xf5','\xbc'},{'\xc4','\xd4'}, + {'\xf5','\xbb'},{'\xc4','\xd6'},{'\x93','\xee'},{'\xc4','\xd5'},{'\xf6','\xd4'}, + {'\xf6','\xd3'},{'\xc5','\x69'},{'\xc5','\x6a'},{'\x00','\x00'},{'\xfd','\x62'}, + {'\xc5','\xc6'},{'\xf7','\xcd'},{'\xc5','\xc5'},{'\x00','\x00'},{'\xf8','\xa3'}, + {'\xf8','\xa4'},{'\xf8','\xa2'},{'\xf8','\xa1'},{'\xc6','\x54'},{'\x00','\x00'}, + {'\xf8','\xeb'},{'\xf8','\xec'},{'\xf8','\xed'},{'\xc6','\x53'},{'\xf9','\x67'}, + {'\xf9','\x6a'},{'\xf9','\x69'},{'\xf9','\x68'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xf9','\xd3'},{'\x88','\xc7'},{'\x8f','\x73'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x8c','\x6a'},{'\x8c','\x6b'},{'\x8f','\xfa'},{'\x8f','\xf9'},{'\x8c','\xc5'}, + {'\x8c','\xc6'},{'\x8c','\xf3'},{'\x8c','\xf4'},{'\x8d','\x6c'},{'\x8d','\x6b'}, + {'\xc0','\x73'},{'\xfb','\xd8'},{'\x00','\x00'},{'\xc3','\x65'},{'\xf5','\xbf'}, + {'\xf6','\xd5'},{'\x00','\x00'},{'\xc5','\xc7'},{'\xf7','\xce'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xf9','\xd5'},{'\x89','\xc5'},{'\x8c','\xf5'},{'\x90','\x69'}, + {'\xc0','\x74'},{'\x98','\x76'},{'\x00','\x00'},{'\x89','\xc6'},{'\xef','\xb6'}, + {'\x00','\x00'},{'\xf7','\xcf'},{'\x00','\x00'},{'\xf9','\xa1'},{'\xfd','\xd4'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\xc8','\xa1'},{'\xc8','\xa3'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xfa','\x40'}, + {'\xfa','\x41'},{'\xfa','\x42'},{'\xfa','\x43'},{'\xfa','\x44'},{'\xfa','\x45'}, + {'\xfa','\x46'},{'\xfa','\x47'},{'\xfa','\x48'},{'\xfa','\x49'},{'\xfa','\x4a'}, + {'\xfa','\x4b'},{'\xfa','\x4c'},{'\xfa','\x4d'},{'\xfa','\x4e'},{'\xfa','\x4f'}, + {'\xfa','\x50'},{'\xfa','\x51'},{'\xfa','\x52'},{'\xfa','\x53'},{'\xfa','\x54'}, + {'\xfa','\x55'},{'\xfa','\x56'},{'\xfa','\x57'},{'\xfa','\x58'},{'\xfa','\x59'}, + {'\xfa','\x5a'},{'\xfa','\x5b'},{'\xfa','\x5c'},{'\xfa','\x5d'},{'\xfa','\x5e'}, + {'\xfa','\x5f'},{'\xfa','\x60'},{'\xfa','\x61'},{'\xfa','\x62'},{'\xfa','\x63'}, + {'\xfa','\x64'},{'\xfa','\x65'},{'\xfa','\x66'},{'\xfa','\x67'},{'\xfa','\x68'}, + {'\xfa','\x69'},{'\xfa','\x6a'},{'\xfa','\x6b'},{'\xfa','\x6c'},{'\xfa','\x6d'}, + {'\xfa','\x6e'},{'\xfa','\x6f'},{'\xfa','\x70'},{'\xfa','\x71'},{'\xfa','\x72'}, + {'\xfa','\x73'},{'\xfa','\x74'},{'\xfa','\x75'},{'\xfa','\x76'},{'\xfa','\x77'}, + {'\xfa','\x78'},{'\xfa','\x79'},{'\xfa','\x7a'},{'\xfa','\x7b'},{'\xfa','\x7c'}, + {'\xfa','\x7d'},{'\xfa','\x7e'},{'\xfa','\xa1'},{'\xfa','\xa2'},{'\xfa','\xa3'}, + {'\xfa','\xa4'},{'\xfa','\xa5'},{'\xfa','\xa6'},{'\xfa','\xa7'},{'\xfa','\xa8'}, + {'\xfa','\xa9'},{'\xfa','\xaa'},{'\xfa','\xab'},{'\xfa','\xac'},{'\xfa','\xad'}, + {'\xfa','\xae'},{'\xfa','\xaf'},{'\xfa','\xb0'},{'\xfa','\xb1'},{'\xfa','\xb2'}, + {'\xfa','\xb3'},{'\xfa','\xb4'},{'\xfa','\xb5'},{'\xfa','\xb6'},{'\xfa','\xb7'}, + {'\xfa','\xb8'},{'\xfa','\xb9'},{'\xfa','\xba'},{'\xfa','\xbb'},{'\xfa','\xbc'}, + {'\xfa','\xbd'},{'\xfa','\xbe'},{'\xfa','\xbf'},{'\xfa','\xc0'},{'\xfa','\xc1'}, + {'\xfa','\xc2'},{'\xfa','\xc3'},{'\xfa','\xc4'},{'\xfa','\xc5'},{'\xfa','\xc6'}, + {'\xfa','\xc7'},{'\xfa','\xc8'},{'\xfa','\xc9'},{'\xfa','\xca'},{'\xfa','\xcb'}, + {'\xfa','\xcc'},{'\xfa','\xcd'},{'\xfa','\xce'},{'\xfa','\xcf'},{'\xfa','\xd0'}, + {'\xfa','\xd1'},{'\xfa','\xd2'},{'\xfa','\xd3'},{'\xfa','\xd4'},{'\xfa','\xd5'}, + {'\xfa','\xd6'},{'\xfa','\xd7'},{'\xfa','\xd8'},{'\xfa','\xd9'},{'\xfa','\xda'}, + {'\xfa','\xdb'},{'\xfa','\xdc'},{'\xfa','\xdd'},{'\xfa','\xde'},{'\xfa','\xdf'}, + {'\xfa','\xe0'},{'\xfa','\xe1'},{'\xfa','\xe2'},{'\xfa','\xe3'},{'\xfa','\xe4'}, + {'\xfa','\xe5'},{'\xfa','\xe6'},{'\xfa','\xe7'},{'\xfa','\xe8'},{'\xfa','\xe9'}, + {'\xfa','\xea'},{'\xfa','\xeb'},{'\xfa','\xec'},{'\xfa','\xed'},{'\xfa','\xee'}, + {'\xfa','\xef'},{'\xfa','\xf0'},{'\xfa','\xf1'},{'\xfa','\xf2'},{'\xfa','\xf3'}, + {'\xfa','\xf4'},{'\xfa','\xf5'},{'\xfa','\xf6'},{'\xfa','\xf7'},{'\xfa','\xf8'}, + {'\xfa','\xf9'},{'\xfa','\xfa'},{'\xfa','\xfb'},{'\xfa','\xfc'},{'\xfa','\xfd'}, + {'\xfa','\xfe'},{'\xfb','\x40'},{'\xfb','\x41'},{'\xfb','\x42'},{'\xfb','\x43'}, + {'\xfb','\x44'},{'\xfb','\x45'},{'\xfb','\x46'},{'\xfb','\x47'},{'\xfb','\x48'}, + {'\xfb','\x49'},{'\xfb','\x4a'},{'\xfb','\x4b'},{'\xfb','\x4c'},{'\xfb','\x4d'}, + {'\xfb','\x4e'},{'\xfb','\x4f'},{'\xfb','\x50'},{'\xfb','\x51'},{'\xfb','\x52'}, + {'\xfb','\x53'},{'\xfb','\x54'},{'\xfb','\x55'},{'\xfb','\x56'},{'\xfb','\x57'}, + {'\xfb','\x58'},{'\xfb','\x59'},{'\xfb','\x5a'},{'\xfb','\x5b'},{'\xfb','\x5c'}, + {'\xfb','\x5d'},{'\xfb','\x5e'},{'\xfb','\x5f'},{'\xfb','\x60'},{'\xfb','\x61'}, + {'\xfb','\x62'},{'\xfb','\x63'},{'\xfb','\x64'},{'\xfb','\x65'},{'\xfb','\x66'}, + {'\xfb','\x67'},{'\xfb','\x68'},{'\xfb','\x69'},{'\xfb','\x6a'},{'\xfb','\x6b'}, + {'\xfb','\x6c'},{'\xfb','\x6d'},{'\xfb','\x6e'},{'\xfb','\x6f'},{'\xfb','\x70'}, + {'\xfb','\x71'},{'\xfb','\x72'},{'\xfb','\x73'},{'\xfb','\x74'},{'\xfb','\x75'}, + {'\xfb','\x76'},{'\xfb','\x77'},{'\xfb','\x78'},{'\xfb','\x79'},{'\xfb','\x7a'}, + {'\xfb','\x7b'},{'\xfb','\x7c'},{'\xfb','\x7d'},{'\xfb','\x7e'},{'\xfb','\xa1'}, + {'\xfb','\xa2'},{'\xfb','\xa3'},{'\xfb','\xa4'},{'\xfb','\xa5'},{'\xfb','\xa6'}, + {'\xfb','\xa7'},{'\xfb','\xa8'},{'\xfb','\xa9'},{'\xfb','\xaa'},{'\xfb','\xab'}, + {'\xfb','\xac'},{'\xfb','\xad'},{'\xfb','\xae'},{'\xfb','\xaf'},{'\xfb','\xb0'}, + {'\xfb','\xb1'},{'\xfb','\xb2'},{'\xfb','\xb3'},{'\xfb','\xb4'},{'\xfb','\xb5'}, + {'\xfb','\xb6'},{'\xfb','\xb7'},{'\xfb','\xb8'},{'\xfb','\xb9'},{'\xfb','\xba'}, + {'\xfb','\xbb'},{'\xfb','\xbc'},{'\xfb','\xbd'},{'\xfb','\xbe'},{'\xfb','\xbf'}, + {'\xfb','\xc0'},{'\xfb','\xc1'},{'\xfb','\xc2'},{'\xfb','\xc3'},{'\xfb','\xc4'}, + {'\xfb','\xc5'},{'\xfb','\xc6'},{'\xfb','\xc7'},{'\xfb','\xc8'},{'\xfb','\xc9'}, + {'\xfb','\xca'},{'\xfb','\xcb'},{'\xfb','\xcc'},{'\xfb','\xcd'},{'\xfb','\xce'}, + {'\xfb','\xcf'},{'\xfb','\xd0'},{'\xfb','\xd1'},{'\xfb','\xd2'},{'\xfb','\xd3'}, + {'\xfb','\xd4'},{'\xfb','\xd5'},{'\xfb','\xd6'},{'\xfb','\xd7'},{'\xfb','\xd8'}, + {'\xfb','\xd9'},{'\xfb','\xda'},{'\xfb','\xdb'},{'\xfb','\xdc'},{'\xfb','\xdd'}, + {'\xfb','\xde'},{'\xfb','\xdf'},{'\xfb','\xe0'},{'\xfb','\xe1'},{'\xfb','\xe2'}, + {'\xfb','\xe3'},{'\xfb','\xe4'},{'\xfb','\xe5'},{'\xfb','\xe6'},{'\xfb','\xe7'}, + {'\xfb','\xe8'},{'\xfb','\xe9'},{'\xfb','\xea'},{'\xfb','\xeb'},{'\xfb','\xec'}, + {'\xfb','\xed'},{'\xfb','\xee'},{'\xfb','\xef'},{'\xfb','\xf0'},{'\xfb','\xf1'}, + {'\xfb','\xf2'},{'\xfb','\xf3'},{'\xfb','\xf4'},{'\xfb','\xf5'},{'\xfb','\xf6'}, + {'\xfb','\xf7'},{'\xfb','\xf8'},{'\xfb','\xf9'},{'\xfb','\xfa'},{'\xfb','\xfb'}, + {'\xfb','\xfc'},{'\xfb','\xfd'},{'\xfb','\xfe'},{'\xfc','\x40'},{'\xfc','\x41'}, + {'\xfc','\x42'},{'\xfc','\x43'},{'\xfc','\x44'},{'\xfc','\x45'},{'\xfc','\x46'}, + {'\xfc','\x47'},{'\xfc','\x48'},{'\xfc','\x49'},{'\xfc','\x4a'},{'\xfc','\x4b'}, + {'\xfc','\x4c'},{'\xfc','\x4d'},{'\xfc','\x4e'},{'\xfc','\x4f'},{'\xfc','\x50'}, + {'\xfc','\x51'},{'\xfc','\x52'},{'\xfc','\x53'},{'\xfc','\x54'},{'\xfc','\x55'}, + {'\xfc','\x56'},{'\xfc','\x57'},{'\xfc','\x58'},{'\xfc','\x59'},{'\xfc','\x5a'}, + {'\xfc','\x5b'},{'\xfc','\x5c'},{'\xfc','\x5d'},{'\xfc','\x5e'},{'\xfc','\x5f'}, + {'\xfc','\x60'},{'\xfc','\x61'},{'\xfc','\x62'},{'\xfc','\x63'},{'\xfc','\x64'}, + {'\xfc','\x65'},{'\xfc','\x66'},{'\xfc','\x67'},{'\xfc','\x68'},{'\xfc','\x69'}, + {'\xfc','\x6a'},{'\xfc','\x6b'},{'\xfc','\x6c'},{'\xfc','\x6d'},{'\xfc','\x6e'}, + {'\xfc','\x6f'},{'\xfc','\x70'},{'\xfc','\x71'},{'\xfc','\x72'},{'\xfc','\x73'}, + {'\xfc','\x74'},{'\xfc','\x75'},{'\xfc','\x76'},{'\xfc','\x77'},{'\xfc','\x78'}, + {'\xfc','\x79'},{'\xfc','\x7a'},{'\xfc','\x7b'},{'\xfc','\x7c'},{'\xfc','\x7d'}, + {'\xfc','\x7e'},{'\xfc','\xa1'},{'\xfc','\xa2'},{'\xfc','\xa3'},{'\xfc','\xa4'}, + {'\xfc','\xa5'},{'\xfc','\xa6'},{'\xfc','\xa7'},{'\xfc','\xa8'},{'\xfc','\xa9'}, + {'\xfc','\xaa'},{'\xfc','\xab'},{'\xfc','\xac'},{'\xfc','\xad'},{'\xfc','\xae'}, + {'\xfc','\xaf'},{'\xfc','\xb0'},{'\xfc','\xb1'},{'\xfc','\xb2'},{'\xfc','\xb3'}, + {'\xfc','\xb4'},{'\xfc','\xb5'},{'\xfc','\xb6'},{'\xfc','\xb7'},{'\xfc','\xb8'}, + {'\xfc','\xb9'},{'\xfc','\xba'},{'\xfc','\xbb'},{'\xfc','\xbc'},{'\xfc','\xbd'}, + {'\xfc','\xbe'},{'\xfc','\xbf'},{'\xfc','\xc0'},{'\xfc','\xc1'},{'\xfc','\xc2'}, + {'\xfc','\xc3'},{'\xfc','\xc4'},{'\xfc','\xc5'},{'\xfc','\xc6'},{'\xfc','\xc7'}, + {'\xfc','\xc8'},{'\xfc','\xc9'},{'\xfc','\xca'},{'\xfc','\xcb'},{'\xfc','\xcc'}, + {'\xfc','\xcd'},{'\xfc','\xce'},{'\xfc','\xcf'},{'\xfc','\xd0'},{'\xfc','\xd1'}, + {'\xfc','\xd2'},{'\xfc','\xd3'},{'\xfc','\xd4'},{'\xfc','\xd5'},{'\xfc','\xd6'}, + {'\xfc','\xd7'},{'\xfc','\xd8'},{'\xfc','\xd9'},{'\xfc','\xda'},{'\xfc','\xdb'}, + {'\xfc','\xdc'},{'\xfc','\xdd'},{'\xfc','\xde'},{'\xfc','\xdf'},{'\xfc','\xe0'}, + {'\xfc','\xe1'},{'\xfc','\xe2'},{'\xfc','\xe3'},{'\xfc','\xe4'},{'\xfc','\xe5'}, + {'\xfc','\xe6'},{'\xfc','\xe7'},{'\xfc','\xe8'},{'\xfc','\xe9'},{'\xfc','\xea'}, + {'\xfc','\xeb'},{'\xfc','\xec'},{'\xfc','\xed'},{'\xfc','\xee'},{'\xfc','\xef'}, + {'\xfc','\xf0'},{'\xfc','\xf1'},{'\xfc','\xf2'},{'\xfc','\xf3'},{'\xfc','\xf4'}, + {'\xfc','\xf5'},{'\xfc','\xf6'},{'\xfc','\xf7'},{'\xfc','\xf8'},{'\xfc','\xf9'}, + {'\xfc','\xfa'},{'\xfc','\xfb'},{'\xfc','\xfc'},{'\xfc','\xfd'},{'\xfc','\xfe'}, + {'\xfd','\x40'},{'\xfd','\x41'},{'\xfd','\x42'},{'\xfd','\x43'},{'\xfd','\x44'}, + {'\xfd','\x45'},{'\xfd','\x46'},{'\xfd','\x47'},{'\xfd','\x48'},{'\xfd','\x49'}, + {'\xfd','\x4a'},{'\xfd','\x4b'},{'\xfd','\x4c'},{'\xfd','\x4d'},{'\xfd','\x4e'}, + {'\xfd','\x4f'},{'\xfd','\x50'},{'\xfd','\x51'},{'\xfd','\x52'},{'\xfd','\x53'}, + {'\xfd','\x54'},{'\xfd','\x55'},{'\xfd','\x56'},{'\xfd','\x57'},{'\xfd','\x58'}, + {'\xfd','\x59'},{'\xfd','\x5a'},{'\xfd','\x5b'},{'\xfd','\x5c'},{'\xfd','\x5d'}, + {'\xfd','\x5e'},{'\xfd','\x5f'},{'\xfd','\x60'},{'\xfd','\x61'},{'\xfd','\x62'}, + {'\xfd','\x63'},{'\xfd','\x64'},{'\xfd','\x65'},{'\xfd','\x66'},{'\xfd','\x67'}, + {'\xfd','\x68'},{'\xfd','\x69'},{'\xfd','\x6a'},{'\xfd','\x6b'},{'\xfd','\x6c'}, + {'\xfd','\x6d'},{'\xfd','\x6e'},{'\xfd','\x6f'},{'\xfd','\x70'},{'\xfd','\x71'}, + {'\xfd','\x72'},{'\xfd','\x73'},{'\xfd','\x74'},{'\xfd','\x75'},{'\xfd','\x76'}, + {'\xfd','\x77'},{'\xfd','\x78'},{'\xfd','\x79'},{'\xfd','\x7a'},{'\xfd','\x7b'}, + {'\xfd','\x7c'},{'\xfd','\x7d'},{'\xfd','\x7e'},{'\xfd','\xa1'},{'\xfd','\xa2'}, + {'\xfd','\xa3'},{'\xfd','\xa4'},{'\xfd','\xa5'},{'\xfd','\xa6'},{'\xfd','\xa7'}, + {'\xfd','\xa8'},{'\xfd','\xa9'},{'\xfd','\xaa'},{'\xfd','\xab'},{'\xfd','\xac'}, + {'\xfd','\xad'},{'\xfd','\xae'},{'\xfd','\xaf'},{'\xfd','\xb0'},{'\xfd','\xb1'}, + {'\xfd','\xb2'},{'\xfd','\xb3'},{'\xfd','\xb4'},{'\xfd','\xb5'},{'\xfd','\xb6'}, + {'\xfd','\xb7'},{'\xfd','\xb8'},{'\xfd','\xb9'},{'\xfd','\xba'},{'\xfd','\xbb'}, + {'\xfd','\xbc'},{'\xfd','\xbd'},{'\xfd','\xbe'},{'\xfd','\xbf'},{'\xfd','\xc0'}, + {'\xfd','\xc1'},{'\xfd','\xc2'},{'\xfd','\xc3'},{'\xfd','\xc4'},{'\xfd','\xc5'}, + {'\xfd','\xc6'},{'\xfd','\xc7'},{'\xfd','\xc8'},{'\xfd','\xc9'},{'\xfd','\xca'}, + {'\xfd','\xcb'},{'\xfd','\xcc'},{'\xfd','\xcd'},{'\xfd','\xce'},{'\xfd','\xcf'}, + {'\xfd','\xd0'},{'\xfd','\xd1'},{'\xfd','\xd2'},{'\xfd','\xd3'},{'\xfd','\xd4'}, + {'\xfd','\xd5'},{'\xfd','\xd6'},{'\xfd','\xd7'},{'\xfd','\xd8'},{'\xfd','\xd9'}, + {'\xfd','\xda'},{'\xfd','\xdb'},{'\xfd','\xdc'},{'\xfd','\xdd'},{'\xfd','\xde'}, + {'\xfd','\xdf'},{'\xfd','\xe0'},{'\xfd','\xe1'},{'\xfd','\xe2'},{'\xfd','\xe3'}, + {'\xfd','\xe4'},{'\xfd','\xe5'},{'\xfd','\xe6'},{'\xfd','\xe7'},{'\xfd','\xe8'}, + {'\xfd','\xe9'},{'\xfd','\xea'},{'\xfd','\xeb'},{'\xfd','\xec'},{'\xfd','\xed'}, + {'\xfd','\xee'},{'\xfd','\xef'},{'\xfd','\xf0'},{'\xfd','\xf1'},{'\xfd','\xf2'}, + {'\xfd','\xf3'},{'\xfd','\xf4'},{'\xfd','\xf5'},{'\xfd','\xf6'},{'\xfd','\xf7'}, + {'\xfd','\xf8'},{'\xfd','\xf9'},{'\xfd','\xfa'},{'\xfd','\xfb'},{'\xfd','\xfc'}, + {'\xfd','\xfd'},{'\xfd','\xfe'},{'\xfe','\x40'},{'\xfe','\x41'},{'\xfe','\x42'}, + {'\xfe','\x43'},{'\xfe','\x44'},{'\xfe','\x45'},{'\xfe','\x46'},{'\xfe','\x47'}, + {'\xfe','\x48'},{'\xfe','\x49'},{'\xfe','\x4a'},{'\xfe','\x4b'},{'\xfe','\x4c'}, + {'\xfe','\x4d'},{'\xfe','\x4e'},{'\xfe','\x4f'},{'\xfe','\x50'},{'\xfe','\x51'}, + {'\xfe','\x52'},{'\xfe','\x53'},{'\xfe','\x54'},{'\xfe','\x55'},{'\xfe','\x56'}, + {'\xfe','\x57'},{'\xfe','\x58'},{'\xfe','\x59'},{'\xfe','\x5a'},{'\xfe','\x5b'}, + {'\xfe','\x5c'},{'\xfe','\x5d'},{'\xfe','\x5e'},{'\xfe','\x5f'},{'\xfe','\x60'}, + {'\xfe','\x61'},{'\xfe','\x62'},{'\xfe','\x63'},{'\xfe','\x64'},{'\xfe','\x65'}, + {'\xfe','\x66'},{'\xfe','\x67'},{'\xfe','\x68'},{'\xfe','\x69'},{'\xfe','\x6a'}, + {'\xfe','\x6b'},{'\xfe','\x6c'},{'\xfe','\x6d'},{'\xfe','\x6e'},{'\xfe','\x6f'}, + {'\xfe','\x70'},{'\xfe','\x71'},{'\xfe','\x72'},{'\xfe','\x73'},{'\xfe','\x74'}, + {'\xfe','\x75'},{'\xfe','\x76'},{'\xfe','\x77'},{'\xfe','\x78'},{'\xfe','\x79'}, + {'\xfe','\x7a'},{'\xfe','\x7b'},{'\xfe','\x7c'},{'\xfe','\x7d'},{'\xfe','\x7e'}, + {'\xfe','\xa1'},{'\xfe','\xa2'},{'\xfe','\xa3'},{'\xfe','\xa4'},{'\xfe','\xa5'}, + {'\xfe','\xa6'},{'\xfe','\xa7'},{'\xfe','\xa8'},{'\xfe','\xa9'},{'\xfe','\xaa'}, + {'\xfe','\xab'},{'\xfe','\xac'},{'\xfe','\xad'},{'\xfe','\xae'},{'\xfe','\xaf'}, + {'\xfe','\xb0'},{'\xfe','\xb1'},{'\xfe','\xb2'},{'\xfe','\xb3'},{'\xfe','\xb4'}, + {'\xfe','\xb5'},{'\xfe','\xb6'},{'\xfe','\xb7'},{'\xfe','\xb8'},{'\xfe','\xb9'}, + {'\xfe','\xba'},{'\xfe','\xbb'},{'\xfe','\xbc'},{'\xfe','\xbd'},{'\xfe','\xbe'}, + {'\xfe','\xbf'},{'\xfe','\xc0'},{'\xfe','\xc1'},{'\xfe','\xc2'},{'\xfe','\xc3'}, + {'\xfe','\xc4'},{'\xfe','\xc5'},{'\xfe','\xc6'},{'\xfe','\xc7'},{'\xfe','\xc8'}, + {'\xfe','\xc9'},{'\xfe','\xca'},{'\xfe','\xcb'},{'\xfe','\xcc'},{'\xfe','\xcd'}, + {'\xfe','\xce'},{'\xfe','\xcf'},{'\xfe','\xd0'},{'\xfe','\xd1'},{'\xfe','\xd2'}, + {'\xfe','\xd3'},{'\xfe','\xd4'},{'\xfe','\xd5'},{'\xfe','\xd6'},{'\xfe','\xd7'}, + {'\xfe','\xd8'},{'\xfe','\xd9'},{'\xfe','\xda'},{'\xfe','\xdb'},{'\xfe','\xdc'}, + {'\xfe','\xdd'},{'\xfe','\xde'},{'\xfe','\xdf'},{'\xfe','\xe0'},{'\xfe','\xe1'}, + {'\xfe','\xe2'},{'\xfe','\xe3'},{'\xfe','\xe4'},{'\xfe','\xe5'},{'\xfe','\xe6'}, + {'\xfe','\xe7'},{'\xfe','\xe8'},{'\xfe','\xe9'},{'\xfe','\xea'},{'\xfe','\xeb'}, + {'\xfe','\xec'},{'\xfe','\xed'},{'\xfe','\xee'},{'\xfe','\xef'},{'\xfe','\xf0'}, + {'\xfe','\xf1'},{'\xfe','\xf2'},{'\xfe','\xf3'},{'\xfe','\xf4'},{'\xfe','\xf5'}, + {'\xfe','\xf6'},{'\xfe','\xf7'},{'\xfe','\xf8'},{'\xfe','\xf9'},{'\xfe','\xfa'}, + {'\xfe','\xfb'},{'\xfe','\xfc'},{'\xfe','\xfd'},{'\xfe','\xfe'},{'\x8e','\x40'}, + {'\x8e','\x41'},{'\x8e','\x42'},{'\x8e','\x43'},{'\x8e','\x44'},{'\x8e','\x45'}, + {'\x8e','\x46'},{'\x8e','\x47'},{'\x8e','\x48'},{'\x8e','\x49'},{'\x8e','\x4a'}, + {'\x8e','\x4b'},{'\x8e','\x4c'},{'\x8e','\x4d'},{'\x8e','\x4e'},{'\x8e','\x4f'}, + {'\x8e','\x50'},{'\x8e','\x51'},{'\x8e','\x52'},{'\x8e','\x53'},{'\x8e','\x54'}, + {'\x8e','\x55'},{'\x8e','\x56'},{'\x8e','\x57'},{'\x8e','\x58'},{'\x8e','\x59'}, + {'\x8e','\x5a'},{'\x8e','\x5b'},{'\x8e','\x5c'},{'\x8e','\x5d'},{'\x8e','\x5e'}, + {'\x8e','\x5f'},{'\x8e','\x60'},{'\x8e','\x61'},{'\x8e','\x62'},{'\x8e','\x63'}, + {'\x8e','\x64'},{'\x8e','\x65'},{'\x8e','\x66'},{'\x8e','\x67'},{'\x8e','\x68'}, + {'\x8e','\x69'},{'\x8e','\x6a'},{'\x8e','\x6b'},{'\x8e','\x6c'},{'\x8e','\x6d'}, + {'\x8e','\x6e'},{'\x8e','\x6f'},{'\x8e','\x70'},{'\x8e','\x71'},{'\x8e','\x72'}, + {'\x8e','\x73'},{'\x8e','\x74'},{'\x8e','\x75'},{'\x8e','\x76'},{'\x8e','\x77'}, + {'\x8e','\x78'},{'\x8e','\x79'},{'\x8e','\x7a'},{'\x8e','\x7b'},{'\x8e','\x7c'}, + {'\x8e','\x7d'},{'\x8e','\x7e'},{'\x8e','\xa1'},{'\x8e','\xa2'},{'\x8e','\xa3'}, + {'\x8e','\xa4'},{'\x8e','\xa5'},{'\x8e','\xa6'},{'\x8e','\xa7'},{'\x8e','\xa8'}, + {'\x8e','\xa9'},{'\x8e','\xaa'},{'\x8e','\xab'},{'\x8e','\xac'},{'\x8e','\xad'}, + {'\x8e','\xae'},{'\x8e','\xaf'},{'\x8e','\xb0'},{'\x8e','\xb1'},{'\x8e','\xb2'}, + {'\x8e','\xb3'},{'\x8e','\xb4'},{'\x8e','\xb5'},{'\x8e','\xb6'},{'\x8e','\xb7'}, + {'\x8e','\xb8'},{'\x8e','\xb9'},{'\x8e','\xba'},{'\x8e','\xbb'},{'\x8e','\xbc'}, + {'\x8e','\xbd'},{'\x8e','\xbe'},{'\x8e','\xbf'},{'\x8e','\xc0'},{'\x8e','\xc1'}, + {'\x8e','\xc2'},{'\x8e','\xc3'},{'\x8e','\xc4'},{'\x8e','\xc5'},{'\x8e','\xc6'}, + {'\x8e','\xc7'},{'\x8e','\xc8'},{'\x8e','\xc9'},{'\x8e','\xca'},{'\x8e','\xcb'}, + {'\x8e','\xcc'},{'\x8e','\xcd'},{'\x8e','\xce'},{'\x8e','\xcf'},{'\x8e','\xd0'}, + {'\x8e','\xd1'},{'\x8e','\xd2'},{'\x8e','\xd3'},{'\x8e','\xd4'},{'\x8e','\xd5'}, + {'\x8e','\xd6'},{'\x8e','\xd7'},{'\x8e','\xd8'},{'\x8e','\xd9'},{'\x8e','\xda'}, + {'\x8e','\xdb'},{'\x8e','\xdc'},{'\x8e','\xdd'},{'\x8e','\xde'},{'\x8e','\xdf'}, + {'\x8e','\xe0'},{'\x8e','\xe1'},{'\x8e','\xe2'},{'\x8e','\xe3'},{'\x8e','\xe4'}, + {'\x8e','\xe5'},{'\x8e','\xe6'},{'\x8e','\xe7'},{'\x8e','\xe8'},{'\x8e','\xe9'}, + {'\x8e','\xea'},{'\x8e','\xeb'},{'\x8e','\xec'},{'\x8e','\xed'},{'\x8e','\xee'}, + {'\x8e','\xef'},{'\x8e','\xf0'},{'\x8e','\xf1'},{'\x8e','\xf2'},{'\x8e','\xf3'}, + {'\x8e','\xf4'},{'\x8e','\xf5'},{'\x8e','\xf6'},{'\x8e','\xf7'},{'\x8e','\xf8'}, + {'\x8e','\xf9'},{'\x8e','\xfa'},{'\x8e','\xfb'},{'\x8e','\xfc'},{'\x8e','\xfd'}, + {'\x8e','\xfe'},{'\x8f','\x40'},{'\x8f','\x41'},{'\x8f','\x42'},{'\x8f','\x43'}, + {'\x8f','\x44'},{'\x8f','\x45'},{'\x8f','\x46'},{'\x8f','\x47'},{'\x8f','\x48'}, + {'\x8f','\x49'},{'\x8f','\x4a'},{'\x8f','\x4b'},{'\x8f','\x4c'},{'\x8f','\x4d'}, + {'\x8f','\x4e'},{'\x8f','\x4f'},{'\x8f','\x50'},{'\x8f','\x51'},{'\x8f','\x52'}, + {'\x8f','\x53'},{'\x8f','\x54'},{'\x8f','\x55'},{'\x8f','\x56'},{'\x8f','\x57'}, + {'\x8f','\x58'},{'\x8f','\x59'},{'\x8f','\x5a'},{'\x8f','\x5b'},{'\x8f','\x5c'}, + {'\x8f','\x5d'},{'\x8f','\x5e'},{'\x8f','\x5f'},{'\x8f','\x60'},{'\x8f','\x61'}, + {'\x8f','\x62'},{'\x8f','\x63'},{'\x8f','\x64'},{'\x8f','\x65'},{'\x8f','\x66'}, + {'\x8f','\x67'},{'\x8f','\x68'},{'\x8f','\x69'},{'\x8f','\x6a'},{'\x8f','\x6b'}, + {'\x8f','\x6c'},{'\x8f','\x6d'},{'\x8f','\x6e'},{'\x8f','\x6f'},{'\x8f','\x70'}, + {'\x8f','\x71'},{'\x8f','\x72'},{'\x8f','\x73'},{'\x8f','\x74'},{'\x8f','\x75'}, + {'\x8f','\x76'},{'\x8f','\x77'},{'\x8f','\x78'},{'\x8f','\x79'},{'\x8f','\x7a'}, + {'\x8f','\x7b'},{'\x8f','\x7c'},{'\x8f','\x7d'},{'\x8f','\x7e'},{'\x8f','\xa1'}, + {'\x8f','\xa2'},{'\x8f','\xa3'},{'\x8f','\xa4'},{'\x8f','\xa5'},{'\x8f','\xa6'}, + {'\x8f','\xa7'},{'\x8f','\xa8'},{'\x8f','\xa9'},{'\x8f','\xaa'},{'\x8f','\xab'}, + {'\x8f','\xac'},{'\x8f','\xad'},{'\x8f','\xae'},{'\x8f','\xaf'},{'\x8f','\xb0'}, + {'\x8f','\xb1'},{'\x8f','\xb2'},{'\x8f','\xb3'},{'\x8f','\xb4'},{'\x8f','\xb5'}, + {'\x8f','\xb6'},{'\x8f','\xb7'},{'\x8f','\xb8'},{'\x8f','\xb9'},{'\x8f','\xba'}, + {'\x8f','\xbb'},{'\x8f','\xbc'},{'\x8f','\xbd'},{'\x8f','\xbe'},{'\x8f','\xbf'}, + {'\x8f','\xc0'},{'\x8f','\xc1'},{'\x8f','\xc2'},{'\x8f','\xc3'},{'\x8f','\xc4'}, + {'\x8f','\xc5'},{'\x8f','\xc6'},{'\x8f','\xc7'},{'\x8f','\xc8'},{'\x8f','\xc9'}, + {'\x8f','\xca'},{'\x8f','\xcb'},{'\x8f','\xcc'},{'\x8f','\xcd'},{'\x8f','\xce'}, + {'\x8f','\xcf'},{'\x8f','\xd0'},{'\x8f','\xd1'},{'\x8f','\xd2'},{'\x8f','\xd3'}, + {'\x8f','\xd4'},{'\x8f','\xd5'},{'\x8f','\xd6'},{'\x8f','\xd7'},{'\x8f','\xd8'}, + {'\x8f','\xd9'},{'\x8f','\xda'},{'\x8f','\xdb'},{'\x8f','\xdc'},{'\x8f','\xdd'}, + {'\x8f','\xde'},{'\x8f','\xdf'},{'\x8f','\xe0'},{'\x8f','\xe1'},{'\x8f','\xe2'}, + {'\x8f','\xe3'},{'\x8f','\xe4'},{'\x8f','\xe5'},{'\x8f','\xe6'},{'\x8f','\xe7'}, + {'\x8f','\xe8'},{'\x8f','\xe9'},{'\x8f','\xea'},{'\x8f','\xeb'},{'\x8f','\xec'}, + {'\x8f','\xed'},{'\x8f','\xee'},{'\x8f','\xef'},{'\x8f','\xf0'},{'\x8f','\xf1'}, + {'\x8f','\xf2'},{'\x8f','\xf3'},{'\x8f','\xf4'},{'\x8f','\xf5'},{'\x8f','\xf6'}, + {'\x8f','\xf7'},{'\x8f','\xf8'},{'\x8f','\xf9'},{'\x8f','\xfa'},{'\x8f','\xfb'}, + {'\x8f','\xfc'},{'\x8f','\xfd'},{'\x8f','\xfe'},{'\x90','\x40'},{'\x90','\x41'}, + {'\x90','\x42'},{'\x90','\x43'},{'\x90','\x44'},{'\x90','\x45'},{'\x90','\x46'}, + {'\x90','\x47'},{'\x90','\x48'},{'\x90','\x49'},{'\x90','\x4a'},{'\x90','\x4b'}, + {'\x90','\x4c'},{'\x90','\x4d'},{'\x90','\x4e'},{'\x90','\x4f'},{'\x90','\x50'}, + {'\x90','\x51'},{'\x90','\x52'},{'\x90','\x53'},{'\x90','\x54'},{'\x90','\x55'}, + {'\x90','\x56'},{'\x90','\x57'},{'\x90','\x58'},{'\x90','\x59'},{'\x90','\x5a'}, + {'\x90','\x5b'},{'\x90','\x5c'},{'\x90','\x5d'},{'\x90','\x5e'},{'\x90','\x5f'}, + {'\x90','\x60'},{'\x90','\x61'},{'\x90','\x62'},{'\x90','\x63'},{'\x90','\x64'}, + {'\x90','\x65'},{'\x90','\x66'},{'\x90','\x67'},{'\x90','\x68'},{'\x90','\x69'}, + {'\x90','\x6a'},{'\x90','\x6b'},{'\x90','\x6c'},{'\x90','\x6d'},{'\x90','\x6e'}, + {'\x90','\x6f'},{'\x90','\x70'},{'\x90','\x71'},{'\x90','\x72'},{'\x90','\x73'}, + {'\x90','\x74'},{'\x90','\x75'},{'\x90','\x76'},{'\x90','\x77'},{'\x90','\x78'}, + {'\x90','\x79'},{'\x90','\x7a'},{'\x90','\x7b'},{'\x90','\x7c'},{'\x90','\x7d'}, + {'\x90','\x7e'},{'\x90','\xa1'},{'\x90','\xa2'},{'\x90','\xa3'},{'\x90','\xa4'}, + {'\x90','\xa5'},{'\x90','\xa6'},{'\x90','\xa7'},{'\x90','\xa8'},{'\x90','\xa9'}, + {'\x90','\xaa'},{'\x90','\xab'},{'\x90','\xac'},{'\x90','\xad'},{'\x90','\xae'}, + {'\x90','\xaf'},{'\x90','\xb0'},{'\x90','\xb1'},{'\x90','\xb2'},{'\x90','\xb3'}, + {'\x90','\xb4'},{'\x90','\xb5'},{'\x90','\xb6'},{'\x90','\xb7'},{'\x90','\xb8'}, + {'\x90','\xb9'},{'\x90','\xba'},{'\x90','\xbb'},{'\x90','\xbc'},{'\x90','\xbd'}, + {'\x90','\xbe'},{'\x90','\xbf'},{'\x90','\xc0'},{'\x90','\xc1'},{'\x90','\xc2'}, + {'\x90','\xc3'},{'\x90','\xc4'},{'\x90','\xc5'},{'\x90','\xc6'},{'\x90','\xc7'}, + {'\x90','\xc8'},{'\x90','\xc9'},{'\x90','\xca'},{'\x90','\xcb'},{'\x90','\xcc'}, + {'\x90','\xcd'},{'\x90','\xce'},{'\x90','\xcf'},{'\x90','\xd0'},{'\x90','\xd1'}, + {'\x90','\xd2'},{'\x90','\xd3'},{'\x90','\xd4'},{'\x90','\xd5'},{'\x90','\xd6'}, + {'\x90','\xd7'},{'\x90','\xd8'},{'\x90','\xd9'},{'\x90','\xda'},{'\x90','\xdb'}, + {'\x90','\xdc'},{'\x90','\xdd'},{'\x90','\xde'},{'\x90','\xdf'},{'\x90','\xe0'}, + {'\x90','\xe1'},{'\x90','\xe2'},{'\x90','\xe3'},{'\x90','\xe4'},{'\x90','\xe5'}, + {'\x90','\xe6'},{'\x90','\xe7'},{'\x90','\xe8'},{'\x90','\xe9'},{'\x90','\xea'}, + {'\x90','\xeb'},{'\x90','\xec'},{'\x90','\xed'},{'\x90','\xee'},{'\x90','\xef'}, + {'\x90','\xf0'},{'\x90','\xf1'},{'\x90','\xf2'},{'\x90','\xf3'},{'\x90','\xf4'}, + {'\x90','\xf5'},{'\x90','\xf6'},{'\x90','\xf7'},{'\x90','\xf8'},{'\x90','\xf9'}, + {'\x90','\xfa'},{'\x90','\xfb'},{'\x90','\xfc'},{'\x90','\xfd'},{'\x90','\xfe'}, + {'\x91','\x40'},{'\x91','\x41'},{'\x91','\x42'},{'\x91','\x43'},{'\x91','\x44'}, + {'\x91','\x45'},{'\x91','\x46'},{'\x91','\x47'},{'\x91','\x48'},{'\x91','\x49'}, + {'\x91','\x4a'},{'\x91','\x4b'},{'\x91','\x4c'},{'\x91','\x4d'},{'\x91','\x4e'}, + {'\x91','\x4f'},{'\x91','\x50'},{'\x91','\x51'},{'\x91','\x52'},{'\x91','\x53'}, + {'\x91','\x54'},{'\x91','\x55'},{'\x91','\x56'},{'\x91','\x57'},{'\x91','\x58'}, + {'\x91','\x59'},{'\x91','\x5a'},{'\x91','\x5b'},{'\x91','\x5c'},{'\x91','\x5d'}, + {'\x91','\x5e'},{'\x91','\x5f'},{'\x91','\x60'},{'\x91','\x61'},{'\x91','\x62'}, + {'\x91','\x63'},{'\x91','\x64'},{'\x91','\x65'},{'\x91','\x66'},{'\x91','\x67'}, + {'\x91','\x68'},{'\x91','\x69'},{'\x91','\x6a'},{'\x91','\x6b'},{'\x91','\x6c'}, + {'\x91','\x6d'},{'\x91','\x6e'},{'\x91','\x6f'},{'\x91','\x70'},{'\x91','\x71'}, + {'\x91','\x72'},{'\x91','\x73'},{'\x91','\x74'},{'\x91','\x75'},{'\x91','\x76'}, + {'\x91','\x77'},{'\x91','\x78'},{'\x91','\x79'},{'\x91','\x7a'},{'\x91','\x7b'}, + {'\x91','\x7c'},{'\x91','\x7d'},{'\x91','\x7e'},{'\x91','\xa1'},{'\x91','\xa2'}, + {'\x91','\xa3'},{'\x91','\xa4'},{'\x91','\xa5'},{'\x91','\xa6'},{'\x91','\xa7'}, + {'\x91','\xa8'},{'\x91','\xa9'},{'\x91','\xaa'},{'\x91','\xab'},{'\x91','\xac'}, + {'\x91','\xad'},{'\x91','\xae'},{'\x91','\xaf'},{'\x91','\xb0'},{'\x91','\xb1'}, + {'\x91','\xb2'},{'\x91','\xb3'},{'\x91','\xb4'},{'\x91','\xb5'},{'\x91','\xb6'}, + {'\x91','\xb7'},{'\x91','\xb8'},{'\x91','\xb9'},{'\x91','\xba'},{'\x91','\xbb'}, + {'\x91','\xbc'},{'\x91','\xbd'},{'\x91','\xbe'},{'\x91','\xbf'},{'\x91','\xc0'}, + {'\x91','\xc1'},{'\x91','\xc2'},{'\x91','\xc3'},{'\x91','\xc4'},{'\x91','\xc5'}, + {'\x91','\xc6'},{'\x91','\xc7'},{'\x91','\xc8'},{'\x91','\xc9'},{'\x91','\xca'}, + {'\x91','\xcb'},{'\x91','\xcc'},{'\x91','\xcd'},{'\x91','\xce'},{'\x91','\xcf'}, + {'\x91','\xd0'},{'\x91','\xd1'},{'\x91','\xd2'},{'\x91','\xd3'},{'\x91','\xd4'}, + {'\x91','\xd5'},{'\x91','\xd6'},{'\x91','\xd7'},{'\x91','\xd8'},{'\x91','\xd9'}, + {'\x91','\xda'},{'\x91','\xdb'},{'\x91','\xdc'},{'\x91','\xdd'},{'\x91','\xde'}, + {'\x91','\xdf'},{'\x91','\xe0'},{'\x91','\xe1'},{'\x91','\xe2'},{'\x91','\xe3'}, + {'\x91','\xe4'},{'\x91','\xe5'},{'\x91','\xe6'},{'\x91','\xe7'},{'\x91','\xe8'}, + {'\x91','\xe9'},{'\x91','\xea'},{'\x91','\xeb'},{'\x91','\xec'},{'\x91','\xed'}, + {'\x91','\xee'},{'\x91','\xef'},{'\x91','\xf0'},{'\x91','\xf1'},{'\x91','\xf2'}, + {'\x91','\xf3'},{'\x91','\xf4'},{'\x91','\xf5'},{'\x91','\xf6'},{'\x91','\xf7'}, + {'\x91','\xf8'},{'\x91','\xf9'},{'\x91','\xfa'},{'\x91','\xfb'},{'\x91','\xfc'}, + {'\x91','\xfd'},{'\x91','\xfe'},{'\x92','\x40'},{'\x92','\x41'},{'\x92','\x42'}, + {'\x92','\x43'},{'\x92','\x44'},{'\x92','\x45'},{'\x92','\x46'},{'\x92','\x47'}, + {'\x92','\x48'},{'\x92','\x49'},{'\x92','\x4a'},{'\x92','\x4b'},{'\x92','\x4c'}, + {'\x92','\x4d'},{'\x92','\x4e'},{'\x92','\x4f'},{'\x92','\x50'},{'\x92','\x51'}, + {'\x92','\x52'},{'\x92','\x53'},{'\x92','\x54'},{'\x92','\x55'},{'\x92','\x56'}, + {'\x92','\x57'},{'\x92','\x58'},{'\x92','\x59'},{'\x92','\x5a'},{'\x92','\x5b'}, + {'\x92','\x5c'},{'\x92','\x5d'},{'\x92','\x5e'},{'\x92','\x5f'},{'\x92','\x60'}, + {'\x92','\x61'},{'\x92','\x62'},{'\x92','\x63'},{'\x92','\x64'},{'\x92','\x65'}, + {'\x92','\x66'},{'\x92','\x67'},{'\x92','\x68'},{'\x92','\x69'},{'\x92','\x6a'}, + {'\x92','\x6b'},{'\x92','\x6c'},{'\x92','\x6d'},{'\x92','\x6e'},{'\x92','\x6f'}, + {'\x92','\x70'},{'\x92','\x71'},{'\x92','\x72'},{'\x92','\x73'},{'\x92','\x74'}, + {'\x92','\x75'},{'\x92','\x76'},{'\x92','\x77'},{'\x92','\x78'},{'\x92','\x79'}, + {'\x92','\x7a'},{'\x92','\x7b'},{'\x92','\x7c'},{'\x92','\x7d'},{'\x92','\x7e'}, + {'\x92','\xa1'},{'\x92','\xa2'},{'\x92','\xa3'},{'\x92','\xa4'},{'\x92','\xa5'}, + {'\x92','\xa6'},{'\x92','\xa7'},{'\x92','\xa8'},{'\x92','\xa9'},{'\x92','\xaa'}, + {'\x92','\xab'},{'\x92','\xac'},{'\x92','\xad'},{'\x92','\xae'},{'\x92','\xaf'}, + {'\x92','\xb0'},{'\x92','\xb1'},{'\x92','\xb2'},{'\x92','\xb3'},{'\x92','\xb4'}, + {'\x92','\xb5'},{'\x92','\xb6'},{'\x92','\xb7'},{'\x92','\xb8'},{'\x92','\xb9'}, + {'\x92','\xba'},{'\x92','\xbb'},{'\x92','\xbc'},{'\x92','\xbd'},{'\x92','\xbe'}, + {'\x92','\xbf'},{'\x92','\xc0'},{'\x92','\xc1'},{'\x92','\xc2'},{'\x92','\xc3'}, + {'\x92','\xc4'},{'\x92','\xc5'},{'\x92','\xc6'},{'\x92','\xc7'},{'\x92','\xc8'}, + {'\x92','\xc9'},{'\x92','\xca'},{'\x92','\xcb'},{'\x92','\xcc'},{'\x92','\xcd'}, + {'\x92','\xce'},{'\x92','\xcf'},{'\x92','\xd0'},{'\x92','\xd1'},{'\x92','\xd2'}, + {'\x92','\xd3'},{'\x92','\xd4'},{'\x92','\xd5'},{'\x92','\xd6'},{'\x92','\xd7'}, + {'\x92','\xd8'},{'\x92','\xd9'},{'\x92','\xda'},{'\x92','\xdb'},{'\x92','\xdc'}, + {'\x92','\xdd'},{'\x92','\xde'},{'\x92','\xdf'},{'\x92','\xe0'},{'\x92','\xe1'}, + {'\x92','\xe2'},{'\x92','\xe3'},{'\x92','\xe4'},{'\x92','\xe5'},{'\x92','\xe6'}, + {'\x92','\xe7'},{'\x92','\xe8'},{'\x92','\xe9'},{'\x92','\xea'},{'\x92','\xeb'}, + {'\x92','\xec'},{'\x92','\xed'},{'\x92','\xee'},{'\x92','\xef'},{'\x92','\xf0'}, + {'\x92','\xf1'},{'\x92','\xf2'},{'\x92','\xf3'},{'\x92','\xf4'},{'\x92','\xf5'}, + {'\x92','\xf6'},{'\x92','\xf7'},{'\x92','\xf8'},{'\x92','\xf9'},{'\x92','\xfa'}, + {'\x92','\xfb'},{'\x92','\xfc'},{'\x92','\xfd'},{'\x92','\xfe'},{'\x93','\x40'}, + {'\x93','\x41'},{'\x93','\x42'},{'\x93','\x43'},{'\x93','\x44'},{'\x93','\x45'}, + {'\x93','\x46'},{'\x93','\x47'},{'\x93','\x48'},{'\x93','\x49'},{'\x93','\x4a'}, + {'\x93','\x4b'},{'\x93','\x4c'},{'\x93','\x4d'},{'\x93','\x4e'},{'\x93','\x4f'}, + {'\x93','\x50'},{'\x93','\x51'},{'\x93','\x52'},{'\x93','\x53'},{'\x93','\x54'}, + {'\x93','\x55'},{'\x93','\x56'},{'\x93','\x57'},{'\x93','\x58'},{'\x93','\x59'}, + {'\x93','\x5a'},{'\x93','\x5b'},{'\x93','\x5c'},{'\x93','\x5d'},{'\x93','\x5e'}, + {'\x93','\x5f'},{'\x93','\x60'},{'\x93','\x61'},{'\x93','\x62'},{'\x93','\x63'}, + {'\x93','\x64'},{'\x93','\x65'},{'\x93','\x66'},{'\x93','\x67'},{'\x93','\x68'}, + {'\x93','\x69'},{'\x93','\x6a'},{'\x93','\x6b'},{'\x93','\x6c'},{'\x93','\x6d'}, + {'\x93','\x6e'},{'\x93','\x6f'},{'\x93','\x70'},{'\x93','\x71'},{'\x93','\x72'}, + {'\x93','\x73'},{'\x93','\x74'},{'\x93','\x75'},{'\x93','\x76'},{'\x93','\x77'}, + {'\x93','\x78'},{'\x93','\x79'},{'\x93','\x7a'},{'\x93','\x7b'},{'\x93','\x7c'}, + {'\x93','\x7d'},{'\x93','\x7e'},{'\x93','\xa1'},{'\x93','\xa2'},{'\x93','\xa3'}, + {'\x93','\xa4'},{'\x93','\xa5'},{'\x93','\xa6'},{'\x93','\xa7'},{'\x93','\xa8'}, + {'\x93','\xa9'},{'\x93','\xaa'},{'\x93','\xab'},{'\x93','\xac'},{'\x93','\xad'}, + {'\x93','\xae'},{'\x93','\xaf'},{'\x93','\xb0'},{'\x93','\xb1'},{'\x93','\xb2'}, + {'\x93','\xb3'},{'\x93','\xb4'},{'\x93','\xb5'},{'\x93','\xb6'},{'\x93','\xb7'}, + {'\x93','\xb8'},{'\x93','\xb9'},{'\x93','\xba'},{'\x93','\xbb'},{'\x93','\xbc'}, + {'\x93','\xbd'},{'\x93','\xbe'},{'\x93','\xbf'},{'\x93','\xc0'},{'\x93','\xc1'}, + {'\x93','\xc2'},{'\x93','\xc3'},{'\x93','\xc4'},{'\x93','\xc5'},{'\x93','\xc6'}, + {'\x93','\xc7'},{'\x93','\xc8'},{'\x93','\xc9'},{'\x93','\xca'},{'\x93','\xcb'}, + {'\x93','\xcc'},{'\x93','\xcd'},{'\x93','\xce'},{'\x93','\xcf'},{'\x93','\xd0'}, + {'\x93','\xd1'},{'\x93','\xd2'},{'\x93','\xd3'},{'\x93','\xd4'},{'\x93','\xd5'}, + {'\x93','\xd6'},{'\x93','\xd7'},{'\x93','\xd8'},{'\x93','\xd9'},{'\x93','\xda'}, + {'\x93','\xdb'},{'\x93','\xdc'},{'\x93','\xdd'},{'\x93','\xde'},{'\x93','\xdf'}, + {'\x93','\xe0'},{'\x93','\xe1'},{'\x93','\xe2'},{'\x93','\xe3'},{'\x93','\xe4'}, + {'\x93','\xe5'},{'\x93','\xe6'},{'\x93','\xe7'},{'\x93','\xe8'},{'\x93','\xe9'}, + {'\x93','\xea'},{'\x93','\xeb'},{'\x93','\xec'},{'\x93','\xed'},{'\x93','\xee'}, + {'\x93','\xef'},{'\x93','\xf0'},{'\x93','\xf1'},{'\x93','\xf2'},{'\x93','\xf3'}, + {'\x93','\xf4'},{'\x93','\xf5'},{'\x93','\xf6'},{'\x93','\xf7'},{'\x93','\xf8'}, + {'\x93','\xf9'},{'\x93','\xfa'},{'\x93','\xfb'},{'\x93','\xfc'},{'\x93','\xfd'}, + {'\x93','\xfe'},{'\x94','\x40'},{'\x94','\x41'},{'\x94','\x42'},{'\x94','\x43'}, + {'\x94','\x44'},{'\x94','\x45'},{'\x94','\x46'},{'\x94','\x47'},{'\x94','\x48'}, + {'\x94','\x49'},{'\x94','\x4a'},{'\x94','\x4b'},{'\x94','\x4c'},{'\x94','\x4d'}, + {'\x94','\x4e'},{'\x94','\x4f'},{'\x94','\x50'},{'\x94','\x51'},{'\x94','\x52'}, + {'\x94','\x53'},{'\x94','\x54'},{'\x94','\x55'},{'\x94','\x56'},{'\x94','\x57'}, + {'\x94','\x58'},{'\x94','\x59'},{'\x94','\x5a'},{'\x94','\x5b'},{'\x94','\x5c'}, + {'\x94','\x5d'},{'\x94','\x5e'},{'\x94','\x5f'},{'\x94','\x60'},{'\x94','\x61'}, + {'\x94','\x62'},{'\x94','\x63'},{'\x94','\x64'},{'\x94','\x65'},{'\x94','\x66'}, + {'\x94','\x67'},{'\x94','\x68'},{'\x94','\x69'},{'\x94','\x6a'},{'\x94','\x6b'}, + {'\x94','\x6c'},{'\x94','\x6d'},{'\x94','\x6e'},{'\x94','\x6f'},{'\x94','\x70'}, + {'\x94','\x71'},{'\x94','\x72'},{'\x94','\x73'},{'\x94','\x74'},{'\x94','\x75'}, + {'\x94','\x76'},{'\x94','\x77'},{'\x94','\x78'},{'\x94','\x79'},{'\x94','\x7a'}, + {'\x94','\x7b'},{'\x94','\x7c'},{'\x94','\x7d'},{'\x94','\x7e'},{'\x94','\xa1'}, + {'\x94','\xa2'},{'\x94','\xa3'},{'\x94','\xa4'},{'\x94','\xa5'},{'\x94','\xa6'}, + {'\x94','\xa7'},{'\x94','\xa8'},{'\x94','\xa9'},{'\x94','\xaa'},{'\x94','\xab'}, + {'\x94','\xac'},{'\x94','\xad'},{'\x94','\xae'},{'\x94','\xaf'},{'\x94','\xb0'}, + {'\x94','\xb1'},{'\x94','\xb2'},{'\x94','\xb3'},{'\x94','\xb4'},{'\x94','\xb5'}, + {'\x94','\xb6'},{'\x94','\xb7'},{'\x94','\xb8'},{'\x94','\xb9'},{'\x94','\xba'}, + {'\x94','\xbb'},{'\x94','\xbc'},{'\x94','\xbd'},{'\x94','\xbe'},{'\x94','\xbf'}, + {'\x94','\xc0'},{'\x94','\xc1'},{'\x94','\xc2'},{'\x94','\xc3'},{'\x94','\xc4'}, + {'\x94','\xc5'},{'\x94','\xc6'},{'\x94','\xc7'},{'\x94','\xc8'},{'\x94','\xc9'}, + {'\x94','\xca'},{'\x94','\xcb'},{'\x94','\xcc'},{'\x94','\xcd'},{'\x94','\xce'}, + {'\x94','\xcf'},{'\x94','\xd0'},{'\x94','\xd1'},{'\x94','\xd2'},{'\x94','\xd3'}, + {'\x94','\xd4'},{'\x94','\xd5'},{'\x94','\xd6'},{'\x94','\xd7'},{'\x94','\xd8'}, + {'\x94','\xd9'},{'\x94','\xda'},{'\x94','\xdb'},{'\x94','\xdc'},{'\x94','\xdd'}, + {'\x94','\xde'},{'\x94','\xdf'},{'\x94','\xe0'},{'\x94','\xe1'},{'\x94','\xe2'}, + {'\x94','\xe3'},{'\x94','\xe4'},{'\x94','\xe5'},{'\x94','\xe6'},{'\x94','\xe7'}, + {'\x94','\xe8'},{'\x94','\xe9'},{'\x94','\xea'},{'\x94','\xeb'},{'\x94','\xec'}, + {'\x94','\xed'},{'\x94','\xee'},{'\x94','\xef'},{'\x94','\xf0'},{'\x94','\xf1'}, + {'\x94','\xf2'},{'\x94','\xf3'},{'\x94','\xf4'},{'\x94','\xf5'},{'\x94','\xf6'}, + {'\x94','\xf7'},{'\x94','\xf8'},{'\x94','\xf9'},{'\x94','\xfa'},{'\x94','\xfb'}, + {'\x94','\xfc'},{'\x94','\xfd'},{'\x94','\xfe'},{'\x95','\x40'},{'\x95','\x41'}, + {'\x95','\x42'},{'\x95','\x43'},{'\x95','\x44'},{'\x95','\x45'},{'\x95','\x46'}, + {'\x95','\x47'},{'\x95','\x48'},{'\x95','\x49'},{'\x95','\x4a'},{'\x95','\x4b'}, + {'\x95','\x4c'},{'\x95','\x4d'},{'\x95','\x4e'},{'\x95','\x4f'},{'\x95','\x50'}, + {'\x95','\x51'},{'\x95','\x52'},{'\x95','\x53'},{'\x95','\x54'},{'\x95','\x55'}, + {'\x95','\x56'},{'\x95','\x57'},{'\x95','\x58'},{'\x95','\x59'},{'\x95','\x5a'}, + {'\x95','\x5b'},{'\x95','\x5c'},{'\x95','\x5d'},{'\x95','\x5e'},{'\x95','\x5f'}, + {'\x95','\x60'},{'\x95','\x61'},{'\x95','\x62'},{'\x95','\x63'},{'\x95','\x64'}, + {'\x95','\x65'},{'\x95','\x66'},{'\x95','\x67'},{'\x95','\x68'},{'\x95','\x69'}, + {'\x95','\x6a'},{'\x95','\x6b'},{'\x95','\x6c'},{'\x95','\x6d'},{'\x95','\x6e'}, + {'\x95','\x6f'},{'\x95','\x70'},{'\x95','\x71'},{'\x95','\x72'},{'\x95','\x73'}, + {'\x95','\x74'},{'\x95','\x75'},{'\x95','\x76'},{'\x95','\x77'},{'\x95','\x78'}, + {'\x95','\x79'},{'\x95','\x7a'},{'\x95','\x7b'},{'\x95','\x7c'},{'\x95','\x7d'}, + {'\x95','\x7e'},{'\x95','\xa1'},{'\x95','\xa2'},{'\x95','\xa3'},{'\x95','\xa4'}, + {'\x95','\xa5'},{'\x95','\xa6'},{'\x95','\xa7'},{'\x95','\xa8'},{'\x95','\xa9'}, + {'\x95','\xaa'},{'\x95','\xab'},{'\x95','\xac'},{'\x95','\xad'},{'\x95','\xae'}, + {'\x95','\xaf'},{'\x95','\xb0'},{'\x95','\xb1'},{'\x95','\xb2'},{'\x95','\xb3'}, + {'\x95','\xb4'},{'\x95','\xb5'},{'\x95','\xb6'},{'\x95','\xb7'},{'\x95','\xb8'}, + {'\x95','\xb9'},{'\x95','\xba'},{'\x95','\xbb'},{'\x95','\xbc'},{'\x95','\xbd'}, + {'\x95','\xbe'},{'\x95','\xbf'},{'\x95','\xc0'},{'\x95','\xc1'},{'\x95','\xc2'}, + {'\x95','\xc3'},{'\x95','\xc4'},{'\x95','\xc5'},{'\x95','\xc6'},{'\x95','\xc7'}, + {'\x95','\xc8'},{'\x95','\xc9'},{'\x95','\xca'},{'\x95','\xcb'},{'\x95','\xcc'}, + {'\x95','\xcd'},{'\x95','\xce'},{'\x95','\xcf'},{'\x95','\xd0'},{'\x95','\xd1'}, + {'\x95','\xd2'},{'\x95','\xd3'},{'\x95','\xd4'},{'\x95','\xd5'},{'\x95','\xd6'}, + {'\x95','\xd7'},{'\x95','\xd8'},{'\x95','\xd9'},{'\x95','\xda'},{'\x95','\xdb'}, + {'\x95','\xdc'},{'\x95','\xdd'},{'\x95','\xde'},{'\x95','\xdf'},{'\x95','\xe0'}, + {'\x95','\xe1'},{'\x95','\xe2'},{'\x95','\xe3'},{'\x95','\xe4'},{'\x95','\xe5'}, + {'\x95','\xe6'},{'\x95','\xe7'},{'\x95','\xe8'},{'\x95','\xe9'},{'\x95','\xea'}, + {'\x95','\xeb'},{'\x95','\xec'},{'\x95','\xed'},{'\x95','\xee'},{'\x95','\xef'}, + {'\x95','\xf0'},{'\x95','\xf1'},{'\x95','\xf2'},{'\x95','\xf3'},{'\x95','\xf4'}, + {'\x95','\xf5'},{'\x95','\xf6'},{'\x95','\xf7'},{'\x95','\xf8'},{'\x95','\xf9'}, + {'\x95','\xfa'},{'\x95','\xfb'},{'\x95','\xfc'},{'\x95','\xfd'},{'\x95','\xfe'}, + {'\x96','\x40'},{'\x96','\x41'},{'\x96','\x42'},{'\x96','\x43'},{'\x96','\x44'}, + {'\x96','\x45'},{'\x96','\x46'},{'\x96','\x47'},{'\x96','\x48'},{'\x96','\x49'}, + {'\x96','\x4a'},{'\x96','\x4b'},{'\x96','\x4c'},{'\x96','\x4d'},{'\x96','\x4e'}, + {'\x96','\x4f'},{'\x96','\x50'},{'\x96','\x51'},{'\x96','\x52'},{'\x96','\x53'}, + {'\x96','\x54'},{'\x96','\x55'},{'\x96','\x56'},{'\x96','\x57'},{'\x96','\x58'}, + {'\x96','\x59'},{'\x96','\x5a'},{'\x96','\x5b'},{'\x96','\x5c'},{'\x96','\x5d'}, + {'\x96','\x5e'},{'\x96','\x5f'},{'\x96','\x60'},{'\x96','\x61'},{'\x96','\x62'}, + {'\x96','\x63'},{'\x96','\x64'},{'\x96','\x65'},{'\x96','\x66'},{'\x96','\x67'}, + {'\x96','\x68'},{'\x96','\x69'},{'\x96','\x6a'},{'\x96','\x6b'},{'\x96','\x6c'}, + {'\x96','\x6d'},{'\x96','\x6e'},{'\x96','\x6f'},{'\x96','\x70'},{'\x96','\x71'}, + {'\x96','\x72'},{'\x96','\x73'},{'\x96','\x74'},{'\x96','\x75'},{'\x96','\x76'}, + {'\x96','\x77'},{'\x96','\x78'},{'\x96','\x79'},{'\x96','\x7a'},{'\x96','\x7b'}, + {'\x96','\x7c'},{'\x96','\x7d'},{'\x96','\x7e'},{'\x96','\xa1'},{'\x96','\xa2'}, + {'\x96','\xa3'},{'\x96','\xa4'},{'\x96','\xa5'},{'\x96','\xa6'},{'\x96','\xa7'}, + {'\x96','\xa8'},{'\x96','\xa9'},{'\x96','\xaa'},{'\x96','\xab'},{'\x96','\xac'}, + {'\x96','\xad'},{'\x96','\xae'},{'\x96','\xaf'},{'\x96','\xb0'},{'\x96','\xb1'}, + {'\x96','\xb2'},{'\x96','\xb3'},{'\x96','\xb4'},{'\x96','\xb5'},{'\x96','\xb6'}, + {'\x96','\xb7'},{'\x96','\xb8'},{'\x96','\xb9'},{'\x96','\xba'},{'\x96','\xbb'}, + {'\x96','\xbc'},{'\x96','\xbd'},{'\x96','\xbe'},{'\x96','\xbf'},{'\x96','\xc0'}, + {'\x96','\xc1'},{'\x96','\xc2'},{'\x96','\xc3'},{'\x96','\xc4'},{'\x96','\xc5'}, + {'\x96','\xc6'},{'\x96','\xc7'},{'\x96','\xc8'},{'\x96','\xc9'},{'\x96','\xca'}, + {'\x96','\xcb'},{'\x96','\xcc'},{'\x96','\xcd'},{'\x96','\xce'},{'\x96','\xcf'}, + {'\x96','\xd0'},{'\x96','\xd1'},{'\x96','\xd2'},{'\x96','\xd3'},{'\x96','\xd4'}, + {'\x96','\xd5'},{'\x96','\xd6'},{'\x96','\xd7'},{'\x96','\xd8'},{'\x96','\xd9'}, + {'\x96','\xda'},{'\x96','\xdb'},{'\x96','\xdc'},{'\x96','\xdd'},{'\x96','\xde'}, + {'\x96','\xdf'},{'\x96','\xe0'},{'\x96','\xe1'},{'\x96','\xe2'},{'\x96','\xe3'}, + {'\x96','\xe4'},{'\x96','\xe5'},{'\x96','\xe6'},{'\x96','\xe7'},{'\x96','\xe8'}, + {'\x96','\xe9'},{'\x96','\xea'},{'\x96','\xeb'},{'\x96','\xec'},{'\x96','\xed'}, + {'\x96','\xee'},{'\x96','\xef'},{'\x96','\xf0'},{'\x96','\xf1'},{'\x96','\xf2'}, + {'\x96','\xf3'},{'\x96','\xf4'},{'\x96','\xf5'},{'\x96','\xf6'},{'\x96','\xf7'}, + {'\x96','\xf8'},{'\x96','\xf9'},{'\x96','\xfa'},{'\x96','\xfb'},{'\x96','\xfc'}, + {'\x96','\xfd'},{'\x96','\xfe'},{'\x97','\x40'},{'\x97','\x41'},{'\x97','\x42'}, + {'\x97','\x43'},{'\x97','\x44'},{'\x97','\x45'},{'\x97','\x46'},{'\x97','\x47'}, + {'\x97','\x48'},{'\x97','\x49'},{'\x97','\x4a'},{'\x97','\x4b'},{'\x97','\x4c'}, + {'\x97','\x4d'},{'\x97','\x4e'},{'\x97','\x4f'},{'\x97','\x50'},{'\x97','\x51'}, + {'\x97','\x52'},{'\x97','\x53'},{'\x97','\x54'},{'\x97','\x55'},{'\x97','\x56'}, + {'\x97','\x57'},{'\x97','\x58'},{'\x97','\x59'},{'\x97','\x5a'},{'\x97','\x5b'}, + {'\x97','\x5c'},{'\x97','\x5d'},{'\x97','\x5e'},{'\x97','\x5f'},{'\x97','\x60'}, + {'\x97','\x61'},{'\x97','\x62'},{'\x97','\x63'},{'\x97','\x64'},{'\x97','\x65'}, + {'\x97','\x66'},{'\x97','\x67'},{'\x97','\x68'},{'\x97','\x69'},{'\x97','\x6a'}, + {'\x97','\x6b'},{'\x97','\x6c'},{'\x97','\x6d'},{'\x97','\x6e'},{'\x97','\x6f'}, + {'\x97','\x70'},{'\x97','\x71'},{'\x97','\x72'},{'\x97','\x73'},{'\x97','\x74'}, + {'\x97','\x75'},{'\x97','\x76'},{'\x97','\x77'},{'\x97','\x78'},{'\x97','\x79'}, + {'\x97','\x7a'},{'\x97','\x7b'},{'\x97','\x7c'},{'\x97','\x7d'},{'\x97','\x7e'}, + {'\x97','\xa1'},{'\x97','\xa2'},{'\x97','\xa3'},{'\x97','\xa4'},{'\x97','\xa5'}, + {'\x97','\xa6'},{'\x97','\xa7'},{'\x97','\xa8'},{'\x97','\xa9'},{'\x97','\xaa'}, + {'\x97','\xab'},{'\x97','\xac'},{'\x97','\xad'},{'\x97','\xae'},{'\x97','\xaf'}, + {'\x97','\xb0'},{'\x97','\xb1'},{'\x97','\xb2'},{'\x97','\xb3'},{'\x97','\xb4'}, + {'\x97','\xb5'},{'\x97','\xb6'},{'\x97','\xb7'},{'\x97','\xb8'},{'\x97','\xb9'}, + {'\x97','\xba'},{'\x97','\xbb'},{'\x97','\xbc'},{'\x97','\xbd'},{'\x97','\xbe'}, + {'\x97','\xbf'},{'\x97','\xc0'},{'\x97','\xc1'},{'\x97','\xc2'},{'\x97','\xc3'}, + {'\x97','\xc4'},{'\x97','\xc5'},{'\x97','\xc6'},{'\x97','\xc7'},{'\x97','\xc8'}, + {'\x97','\xc9'},{'\x97','\xca'},{'\x97','\xcb'},{'\x97','\xcc'},{'\x97','\xcd'}, + {'\x97','\xce'},{'\x97','\xcf'},{'\x97','\xd0'},{'\x97','\xd1'},{'\x97','\xd2'}, + {'\x97','\xd3'},{'\x97','\xd4'},{'\x97','\xd5'},{'\x97','\xd6'},{'\x97','\xd7'}, + {'\x97','\xd8'},{'\x97','\xd9'},{'\x97','\xda'},{'\x97','\xdb'},{'\x97','\xdc'}, + {'\x97','\xdd'},{'\x97','\xde'},{'\x97','\xdf'},{'\x97','\xe0'},{'\x97','\xe1'}, + {'\x97','\xe2'},{'\x97','\xe3'},{'\x97','\xe4'},{'\x97','\xe5'},{'\x97','\xe6'}, + {'\x97','\xe7'},{'\x97','\xe8'},{'\x97','\xe9'},{'\x97','\xea'},{'\x97','\xeb'}, + {'\x97','\xec'},{'\x97','\xed'},{'\x97','\xee'},{'\x97','\xef'},{'\x97','\xf0'}, + {'\x97','\xf1'},{'\x97','\xf2'},{'\x97','\xf3'},{'\x97','\xf4'},{'\x97','\xf5'}, + {'\x97','\xf6'},{'\x97','\xf7'},{'\x97','\xf8'},{'\x97','\xf9'},{'\x97','\xfa'}, + {'\x97','\xfb'},{'\x97','\xfc'},{'\x97','\xfd'},{'\x97','\xfe'},{'\x98','\x40'}, + {'\x98','\x41'},{'\x98','\x42'},{'\x98','\x43'},{'\x98','\x44'},{'\x98','\x45'}, + {'\x98','\x46'},{'\x98','\x47'},{'\x98','\x48'},{'\x98','\x49'},{'\x98','\x4a'}, + {'\x98','\x4b'},{'\x98','\x4c'},{'\x98','\x4d'},{'\x98','\x4e'},{'\x98','\x4f'}, + {'\x98','\x50'},{'\x98','\x51'},{'\x98','\x52'},{'\x98','\x53'},{'\x98','\x54'}, + {'\x98','\x55'},{'\x98','\x56'},{'\x98','\x57'},{'\x98','\x58'},{'\x98','\x59'}, + {'\x98','\x5a'},{'\x98','\x5b'},{'\x98','\x5c'},{'\x98','\x5d'},{'\x98','\x5e'}, + {'\x98','\x5f'},{'\x98','\x60'},{'\x98','\x61'},{'\x98','\x62'},{'\x98','\x63'}, + {'\x98','\x64'},{'\x98','\x65'},{'\x98','\x66'},{'\x98','\x67'},{'\x98','\x68'}, + {'\x98','\x69'},{'\x98','\x6a'},{'\x98','\x6b'},{'\x98','\x6c'},{'\x98','\x6d'}, + {'\x98','\x6e'},{'\x98','\x6f'},{'\x98','\x70'},{'\x98','\x71'},{'\x98','\x72'}, + {'\x98','\x73'},{'\x98','\x74'},{'\x98','\x75'},{'\x98','\x76'},{'\x98','\x77'}, + {'\x98','\x78'},{'\x98','\x79'},{'\x98','\x7a'},{'\x98','\x7b'},{'\x98','\x7c'}, + {'\x98','\x7d'},{'\x98','\x7e'},{'\x98','\xa1'},{'\x98','\xa2'},{'\x98','\xa3'}, + {'\x98','\xa4'},{'\x98','\xa5'},{'\x98','\xa6'},{'\x98','\xa7'},{'\x98','\xa8'}, + {'\x98','\xa9'},{'\x98','\xaa'},{'\x98','\xab'},{'\x98','\xac'},{'\x98','\xad'}, + {'\x98','\xae'},{'\x98','\xaf'},{'\x98','\xb0'},{'\x98','\xb1'},{'\x98','\xb2'}, + {'\x98','\xb3'},{'\x98','\xb4'},{'\x98','\xb5'},{'\x98','\xb6'},{'\x98','\xb7'}, + {'\x98','\xb8'},{'\x98','\xb9'},{'\x98','\xba'},{'\x98','\xbb'},{'\x98','\xbc'}, + {'\x98','\xbd'},{'\x98','\xbe'},{'\x98','\xbf'},{'\x98','\xc0'},{'\x98','\xc1'}, + {'\x98','\xc2'},{'\x98','\xc3'},{'\x98','\xc4'},{'\x98','\xc5'},{'\x98','\xc6'}, + {'\x98','\xc7'},{'\x98','\xc8'},{'\x98','\xc9'},{'\x98','\xca'},{'\x98','\xcb'}, + {'\x98','\xcc'},{'\x98','\xcd'},{'\x98','\xce'},{'\x98','\xcf'},{'\x98','\xd0'}, + {'\x98','\xd1'},{'\x98','\xd2'},{'\x98','\xd3'},{'\x98','\xd4'},{'\x98','\xd5'}, + {'\x98','\xd6'},{'\x98','\xd7'},{'\x98','\xd8'},{'\x98','\xd9'},{'\x98','\xda'}, + {'\x98','\xdb'},{'\x98','\xdc'},{'\x98','\xdd'},{'\x98','\xde'},{'\x98','\xdf'}, + {'\x98','\xe0'},{'\x98','\xe1'},{'\x98','\xe2'},{'\x98','\xe3'},{'\x98','\xe4'}, + {'\x98','\xe5'},{'\x98','\xe6'},{'\x98','\xe7'},{'\x98','\xe8'},{'\x98','\xe9'}, + {'\x98','\xea'},{'\x98','\xeb'},{'\x98','\xec'},{'\x98','\xed'},{'\x98','\xee'}, + {'\x98','\xef'},{'\x98','\xf0'},{'\x98','\xf1'},{'\x98','\xf2'},{'\x98','\xf3'}, + {'\x98','\xf4'},{'\x98','\xf5'},{'\x98','\xf6'},{'\x98','\xf7'},{'\x98','\xf8'}, + {'\x98','\xf9'},{'\x98','\xfa'},{'\x98','\xfb'},{'\x98','\xfc'},{'\x98','\xfd'}, + {'\x98','\xfe'},{'\x99','\x40'},{'\x99','\x41'},{'\x99','\x42'},{'\x99','\x43'}, + {'\x99','\x44'},{'\x99','\x45'},{'\x99','\x46'},{'\x99','\x47'},{'\x99','\x48'}, + {'\x99','\x49'},{'\x99','\x4a'},{'\x99','\x4b'},{'\x99','\x4c'},{'\x99','\x4d'}, + {'\x99','\x4e'},{'\x99','\x4f'},{'\x99','\x50'},{'\x99','\x51'},{'\x99','\x52'}, + {'\x99','\x53'},{'\x99','\x54'},{'\x99','\x55'},{'\x99','\x56'},{'\x99','\x57'}, + {'\x99','\x58'},{'\x99','\x59'},{'\x99','\x5a'},{'\x99','\x5b'},{'\x99','\x5c'}, + {'\x99','\x5d'},{'\x99','\x5e'},{'\x99','\x5f'},{'\x99','\x60'},{'\x99','\x61'}, + {'\x99','\x62'},{'\x99','\x63'},{'\x99','\x64'},{'\x99','\x65'},{'\x99','\x66'}, + {'\x99','\x67'},{'\x99','\x68'},{'\x99','\x69'},{'\x99','\x6a'},{'\x99','\x6b'}, + {'\x99','\x6c'},{'\x99','\x6d'},{'\x99','\x6e'},{'\x99','\x6f'},{'\x99','\x70'}, + {'\x99','\x71'},{'\x99','\x72'},{'\x99','\x73'},{'\x99','\x74'},{'\x99','\x75'}, + {'\x99','\x76'},{'\x99','\x77'},{'\x99','\x78'},{'\x99','\x79'},{'\x99','\x7a'}, + {'\x99','\x7b'},{'\x99','\x7c'},{'\x99','\x7d'},{'\x99','\x7e'},{'\x99','\xa1'}, + {'\x99','\xa2'},{'\x99','\xa3'},{'\x99','\xa4'},{'\x99','\xa5'},{'\x99','\xa6'}, + {'\x99','\xa7'},{'\x99','\xa8'},{'\x99','\xa9'},{'\x99','\xaa'},{'\x99','\xab'}, + {'\x99','\xac'},{'\x99','\xad'},{'\x99','\xae'},{'\x99','\xaf'},{'\x99','\xb0'}, + {'\x99','\xb1'},{'\x99','\xb2'},{'\x99','\xb3'},{'\x99','\xb4'},{'\x99','\xb5'}, + {'\x99','\xb6'},{'\x99','\xb7'},{'\x99','\xb8'},{'\x99','\xb9'},{'\x99','\xba'}, + {'\x99','\xbb'},{'\x99','\xbc'},{'\x99','\xbd'},{'\x99','\xbe'},{'\x99','\xbf'}, + {'\x99','\xc0'},{'\x99','\xc1'},{'\x99','\xc2'},{'\x99','\xc3'},{'\x99','\xc4'}, + {'\x99','\xc5'},{'\x99','\xc6'},{'\x99','\xc7'},{'\x99','\xc8'},{'\x99','\xc9'}, + {'\x99','\xca'},{'\x99','\xcb'},{'\x99','\xcc'},{'\x99','\xcd'},{'\x99','\xce'}, + {'\x99','\xcf'},{'\x99','\xd0'},{'\x99','\xd1'},{'\x99','\xd2'},{'\x99','\xd3'}, + {'\x99','\xd4'},{'\x99','\xd5'},{'\x99','\xd6'},{'\x99','\xd7'},{'\x99','\xd8'}, + {'\x99','\xd9'},{'\x99','\xda'},{'\x99','\xdb'},{'\x99','\xdc'},{'\x99','\xdd'}, + {'\x99','\xde'},{'\x99','\xdf'},{'\x99','\xe0'},{'\x99','\xe1'},{'\x99','\xe2'}, + {'\x99','\xe3'},{'\x99','\xe4'},{'\x99','\xe5'},{'\x99','\xe6'},{'\x99','\xe7'}, + {'\x99','\xe8'},{'\x99','\xe9'},{'\x99','\xea'},{'\x99','\xeb'},{'\x99','\xec'}, + {'\x99','\xed'},{'\x99','\xee'},{'\x99','\xef'},{'\x99','\xf0'},{'\x99','\xf1'}, + {'\x99','\xf2'},{'\x99','\xf3'},{'\x99','\xf4'},{'\x99','\xf5'},{'\x99','\xf6'}, + {'\x99','\xf7'},{'\x99','\xf8'},{'\x99','\xf9'},{'\x99','\xfa'},{'\x99','\xfb'}, + {'\x99','\xfc'},{'\x99','\xfd'},{'\x99','\xfe'},{'\x9a','\x40'},{'\x9a','\x41'}, + {'\x9a','\x42'},{'\x9a','\x43'},{'\x9a','\x44'},{'\x9a','\x45'},{'\x9a','\x46'}, + {'\x9a','\x47'},{'\x9a','\x48'},{'\x9a','\x49'},{'\x9a','\x4a'},{'\x9a','\x4b'}, + {'\x9a','\x4c'},{'\x9a','\x4d'},{'\x9a','\x4e'},{'\x9a','\x4f'},{'\x9a','\x50'}, + {'\x9a','\x51'},{'\x9a','\x52'},{'\x9a','\x53'},{'\x9a','\x54'},{'\x9a','\x55'}, + {'\x9a','\x56'},{'\x9a','\x57'},{'\x9a','\x58'},{'\x9a','\x59'},{'\x9a','\x5a'}, + {'\x9a','\x5b'},{'\x9a','\x5c'},{'\x9a','\x5d'},{'\x9a','\x5e'},{'\x9a','\x5f'}, + {'\x9a','\x60'},{'\x9a','\x61'},{'\x9a','\x62'},{'\x9a','\x63'},{'\x9a','\x64'}, + {'\x9a','\x65'},{'\x9a','\x66'},{'\x9a','\x67'},{'\x9a','\x68'},{'\x9a','\x69'}, + {'\x9a','\x6a'},{'\x9a','\x6b'},{'\x9a','\x6c'},{'\x9a','\x6d'},{'\x9a','\x6e'}, + {'\x9a','\x6f'},{'\x9a','\x70'},{'\x9a','\x71'},{'\x9a','\x72'},{'\x9a','\x73'}, + {'\x9a','\x74'},{'\x9a','\x75'},{'\x9a','\x76'},{'\x9a','\x77'},{'\x9a','\x78'}, + {'\x9a','\x79'},{'\x9a','\x7a'},{'\x9a','\x7b'},{'\x9a','\x7c'},{'\x9a','\x7d'}, + {'\x9a','\x7e'},{'\x9a','\xa1'},{'\x9a','\xa2'},{'\x9a','\xa3'},{'\x9a','\xa4'}, + {'\x9a','\xa5'},{'\x9a','\xa6'},{'\x9a','\xa7'},{'\x9a','\xa8'},{'\x9a','\xa9'}, + {'\x9a','\xaa'},{'\x9a','\xab'},{'\x9a','\xac'},{'\x9a','\xad'},{'\x9a','\xae'}, + {'\x9a','\xaf'},{'\x9a','\xb0'},{'\x9a','\xb1'},{'\x9a','\xb2'},{'\x9a','\xb3'}, + {'\x9a','\xb4'},{'\x9a','\xb5'},{'\x9a','\xb6'},{'\x9a','\xb7'},{'\x9a','\xb8'}, + {'\x9a','\xb9'},{'\x9a','\xba'},{'\x9a','\xbb'},{'\x9a','\xbc'},{'\x9a','\xbd'}, + {'\x9a','\xbe'},{'\x9a','\xbf'},{'\x9a','\xc0'},{'\x9a','\xc1'},{'\x9a','\xc2'}, + {'\x9a','\xc3'},{'\x9a','\xc4'},{'\x9a','\xc5'},{'\x9a','\xc6'},{'\x9a','\xc7'}, + {'\x9a','\xc8'},{'\x9a','\xc9'},{'\x9a','\xca'},{'\x9a','\xcb'},{'\x9a','\xcc'}, + {'\x9a','\xcd'},{'\x9a','\xce'},{'\x9a','\xcf'},{'\x9a','\xd0'},{'\x9a','\xd1'}, + {'\x9a','\xd2'},{'\x9a','\xd3'},{'\x9a','\xd4'},{'\x9a','\xd5'},{'\x9a','\xd6'}, + {'\x9a','\xd7'},{'\x9a','\xd8'},{'\x9a','\xd9'},{'\x9a','\xda'},{'\x9a','\xdb'}, + {'\x9a','\xdc'},{'\x9a','\xdd'},{'\x9a','\xde'},{'\x9a','\xdf'},{'\x9a','\xe0'}, + {'\x9a','\xe1'},{'\x9a','\xe2'},{'\x9a','\xe3'},{'\x9a','\xe4'},{'\x9a','\xe5'}, + {'\x9a','\xe6'},{'\x9a','\xe7'},{'\x9a','\xe8'},{'\x9a','\xe9'},{'\x9a','\xea'}, + {'\x9a','\xeb'},{'\x9a','\xec'},{'\x9a','\xed'},{'\x9a','\xee'},{'\x9a','\xef'}, + {'\x9a','\xf0'},{'\x9a','\xf1'},{'\x9a','\xf2'},{'\x9a','\xf3'},{'\x9a','\xf4'}, + {'\x9a','\xf5'},{'\x9a','\xf6'},{'\x9a','\xf7'},{'\x9a','\xf8'},{'\x9a','\xf9'}, + {'\x9a','\xfa'},{'\x9a','\xfb'},{'\x9a','\xfc'},{'\x9a','\xfd'},{'\x9a','\xfe'}, + {'\x9b','\x40'},{'\x9b','\x41'},{'\x9b','\x42'},{'\x9b','\x43'},{'\x9b','\x44'}, + {'\x9b','\x45'},{'\x9b','\x46'},{'\x9b','\x47'},{'\x9b','\x48'},{'\x9b','\x49'}, + {'\x9b','\x4a'},{'\x9b','\x4b'},{'\x9b','\x4c'},{'\x9b','\x4d'},{'\x9b','\x4e'}, + {'\x9b','\x4f'},{'\x9b','\x50'},{'\x9b','\x51'},{'\x9b','\x52'},{'\x9b','\x53'}, + {'\x9b','\x54'},{'\x9b','\x55'},{'\x9b','\x56'},{'\x9b','\x57'},{'\x9b','\x58'}, + {'\x9b','\x59'},{'\x9b','\x5a'},{'\x9b','\x5b'},{'\x9b','\x5c'},{'\x9b','\x5d'}, + {'\x9b','\x5e'},{'\x9b','\x5f'},{'\x9b','\x60'},{'\x9b','\x61'},{'\x9b','\x62'}, + {'\x9b','\x63'},{'\x9b','\x64'},{'\x9b','\x65'},{'\x9b','\x66'},{'\x9b','\x67'}, + {'\x9b','\x68'},{'\x9b','\x69'},{'\x9b','\x6a'},{'\x9b','\x6b'},{'\x9b','\x6c'}, + {'\x9b','\x6d'},{'\x9b','\x6e'},{'\x9b','\x6f'},{'\x9b','\x70'},{'\x9b','\x71'}, + {'\x9b','\x72'},{'\x9b','\x73'},{'\x9b','\x74'},{'\x9b','\x75'},{'\x9b','\x76'}, + {'\x9b','\x77'},{'\x9b','\x78'},{'\x9b','\x79'},{'\x9b','\x7a'},{'\x9b','\x7b'}, + {'\x9b','\x7c'},{'\x9b','\x7d'},{'\x9b','\x7e'},{'\x9b','\xa1'},{'\x9b','\xa2'}, + {'\x9b','\xa3'},{'\x9b','\xa4'},{'\x9b','\xa5'},{'\x9b','\xa6'},{'\x9b','\xa7'}, + {'\x9b','\xa8'},{'\x9b','\xa9'},{'\x9b','\xaa'},{'\x9b','\xab'},{'\x9b','\xac'}, + {'\x9b','\xad'},{'\x9b','\xae'},{'\x9b','\xaf'},{'\x9b','\xb0'},{'\x9b','\xb1'}, + {'\x9b','\xb2'},{'\x9b','\xb3'},{'\x9b','\xb4'},{'\x9b','\xb5'},{'\x9b','\xb6'}, + {'\x9b','\xb7'},{'\x9b','\xb8'},{'\x9b','\xb9'},{'\x9b','\xba'},{'\x9b','\xbb'}, + {'\x9b','\xbc'},{'\x9b','\xbd'},{'\x9b','\xbe'},{'\x9b','\xbf'},{'\x9b','\xc0'}, + {'\x9b','\xc1'},{'\x9b','\xc2'},{'\x9b','\xc3'},{'\x9b','\xc4'},{'\x9b','\xc5'}, + {'\x9b','\xc6'},{'\x9b','\xc7'},{'\x9b','\xc8'},{'\x9b','\xc9'},{'\x9b','\xca'}, + {'\x9b','\xcb'},{'\x9b','\xcc'},{'\x9b','\xcd'},{'\x9b','\xce'},{'\x9b','\xcf'}, + {'\x9b','\xd0'},{'\x9b','\xd1'},{'\x9b','\xd2'},{'\x9b','\xd3'},{'\x9b','\xd4'}, + {'\x9b','\xd5'},{'\x9b','\xd6'},{'\x9b','\xd7'},{'\x9b','\xd8'},{'\x9b','\xd9'}, + {'\x9b','\xda'},{'\x9b','\xdb'},{'\x9b','\xdc'},{'\x9b','\xdd'},{'\x9b','\xde'}, + {'\x9b','\xdf'},{'\x9b','\xe0'},{'\x9b','\xe1'},{'\x9b','\xe2'},{'\x9b','\xe3'}, + {'\x9b','\xe4'},{'\x9b','\xe5'},{'\x9b','\xe6'},{'\x9b','\xe7'},{'\x9b','\xe8'}, + {'\x9b','\xe9'},{'\x9b','\xea'},{'\x9b','\xeb'},{'\x9b','\xec'},{'\x9b','\xed'}, + {'\x9b','\xee'},{'\x9b','\xef'},{'\x9b','\xf0'},{'\x9b','\xf1'},{'\x9b','\xf2'}, + {'\x9b','\xf3'},{'\x9b','\xf4'},{'\x9b','\xf5'},{'\x9b','\xf6'},{'\x9b','\xf7'}, + {'\x9b','\xf8'},{'\x9b','\xf9'},{'\x9b','\xfa'},{'\x9b','\xfb'},{'\x9b','\xfc'}, + {'\x9b','\xfd'},{'\x9b','\xfe'},{'\x9c','\x40'},{'\x9c','\x41'},{'\x9c','\x42'}, + {'\x9c','\x43'},{'\x9c','\x44'},{'\x9c','\x45'},{'\x9c','\x46'},{'\x9c','\x47'}, + {'\x9c','\x48'},{'\x9c','\x49'},{'\x9c','\x4a'},{'\x9c','\x4b'},{'\x9c','\x4c'}, + {'\x9c','\x4d'},{'\x9c','\x4e'},{'\x9c','\x4f'},{'\x9c','\x50'},{'\x9c','\x51'}, + {'\x9c','\x52'},{'\x9c','\x53'},{'\x9c','\x54'},{'\x9c','\x55'},{'\x9c','\x56'}, + {'\x9c','\x57'},{'\x9c','\x58'},{'\x9c','\x59'},{'\x9c','\x5a'},{'\x9c','\x5b'}, + {'\x9c','\x5c'},{'\x9c','\x5d'},{'\x9c','\x5e'},{'\x9c','\x5f'},{'\x9c','\x60'}, + {'\x9c','\x61'},{'\x9c','\x62'},{'\x9c','\x63'},{'\x9c','\x64'},{'\x9c','\x65'}, + {'\x9c','\x66'},{'\x9c','\x67'},{'\x9c','\x68'},{'\x9c','\x69'},{'\x9c','\x6a'}, + {'\x9c','\x6b'},{'\x9c','\x6c'},{'\x9c','\x6d'},{'\x9c','\x6e'},{'\x9c','\x6f'}, + {'\x9c','\x70'},{'\x9c','\x71'},{'\x9c','\x72'},{'\x9c','\x73'},{'\x9c','\x74'}, + {'\x9c','\x75'},{'\x9c','\x76'},{'\x9c','\x77'},{'\x9c','\x78'},{'\x9c','\x79'}, + {'\x9c','\x7a'},{'\x9c','\x7b'},{'\x9c','\x7c'},{'\x9c','\x7d'},{'\x9c','\x7e'}, + {'\x9c','\xa1'},{'\x9c','\xa2'},{'\x9c','\xa3'},{'\x9c','\xa4'},{'\x9c','\xa5'}, + {'\x9c','\xa6'},{'\x9c','\xa7'},{'\x9c','\xa8'},{'\x9c','\xa9'},{'\x9c','\xaa'}, + {'\x9c','\xab'},{'\x9c','\xac'},{'\x9c','\xad'},{'\x9c','\xae'},{'\x9c','\xaf'}, + {'\x9c','\xb0'},{'\x9c','\xb1'},{'\x9c','\xb2'},{'\x9c','\xb3'},{'\x9c','\xb4'}, + {'\x9c','\xb5'},{'\x9c','\xb6'},{'\x9c','\xb7'},{'\x9c','\xb8'},{'\x9c','\xb9'}, + {'\x9c','\xba'},{'\x9c','\xbb'},{'\x9c','\xbc'},{'\x9c','\xbd'},{'\x9c','\xbe'}, + {'\x9c','\xbf'},{'\x9c','\xc0'},{'\x9c','\xc1'},{'\x9c','\xc2'},{'\x9c','\xc3'}, + {'\x9c','\xc4'},{'\x9c','\xc5'},{'\x9c','\xc6'},{'\x9c','\xc7'},{'\x9c','\xc8'}, + {'\x9c','\xc9'},{'\x9c','\xca'},{'\x9c','\xcb'},{'\x9c','\xcc'},{'\x9c','\xcd'}, + {'\x9c','\xce'},{'\x9c','\xcf'},{'\x9c','\xd0'},{'\x9c','\xd1'},{'\x9c','\xd2'}, + {'\x9c','\xd3'},{'\x9c','\xd4'},{'\x9c','\xd5'},{'\x9c','\xd6'},{'\x9c','\xd7'}, + {'\x9c','\xd8'},{'\x9c','\xd9'},{'\x9c','\xda'},{'\x9c','\xdb'},{'\x9c','\xdc'}, + {'\x9c','\xdd'},{'\x9c','\xde'},{'\x9c','\xdf'},{'\x9c','\xe0'},{'\x9c','\xe1'}, + {'\x9c','\xe2'},{'\x9c','\xe3'},{'\x9c','\xe4'},{'\x9c','\xe5'},{'\x9c','\xe6'}, + {'\x9c','\xe7'},{'\x9c','\xe8'},{'\x9c','\xe9'},{'\x9c','\xea'},{'\x9c','\xeb'}, + {'\x9c','\xec'},{'\x9c','\xed'},{'\x9c','\xee'},{'\x9c','\xef'},{'\x9c','\xf0'}, + {'\x9c','\xf1'},{'\x9c','\xf2'},{'\x9c','\xf3'},{'\x9c','\xf4'},{'\x9c','\xf5'}, + {'\x9c','\xf6'},{'\x9c','\xf7'},{'\x9c','\xf8'},{'\x9c','\xf9'},{'\x9c','\xfa'}, + {'\x9c','\xfb'},{'\x9c','\xfc'},{'\x9c','\xfd'},{'\x9c','\xfe'},{'\x9d','\x40'}, + {'\x9d','\x41'},{'\x9d','\x42'},{'\x9d','\x43'},{'\x9d','\x44'},{'\x9d','\x45'}, + {'\x9d','\x46'},{'\x9d','\x47'},{'\x9d','\x48'},{'\x9d','\x49'},{'\x9d','\x4a'}, + {'\x9d','\x4b'},{'\x9d','\x4c'},{'\x9d','\x4d'},{'\x9d','\x4e'},{'\x9d','\x4f'}, + {'\x9d','\x50'},{'\x9d','\x51'},{'\x9d','\x52'},{'\x9d','\x53'},{'\x9d','\x54'}, + {'\x9d','\x55'},{'\x9d','\x56'},{'\x9d','\x57'},{'\x9d','\x58'},{'\x9d','\x59'}, + {'\x9d','\x5a'},{'\x9d','\x5b'},{'\x9d','\x5c'},{'\x9d','\x5d'},{'\x9d','\x5e'}, + {'\x9d','\x5f'},{'\x9d','\x60'},{'\x9d','\x61'},{'\x9d','\x62'},{'\x9d','\x63'}, + {'\x9d','\x64'},{'\x9d','\x65'},{'\x9d','\x66'},{'\x9d','\x67'},{'\x9d','\x68'}, + {'\x9d','\x69'},{'\x9d','\x6a'},{'\x9d','\x6b'},{'\x9d','\x6c'},{'\x9d','\x6d'}, + {'\x9d','\x6e'},{'\x9d','\x6f'},{'\x9d','\x70'},{'\x9d','\x71'},{'\x9d','\x72'}, + {'\x9d','\x73'},{'\x9d','\x74'},{'\x9d','\x75'},{'\x9d','\x76'},{'\x9d','\x77'}, + {'\x9d','\x78'},{'\x9d','\x79'},{'\x9d','\x7a'},{'\x9d','\x7b'},{'\x9d','\x7c'}, + {'\x9d','\x7d'},{'\x9d','\x7e'},{'\x9d','\xa1'},{'\x9d','\xa2'},{'\x9d','\xa3'}, + {'\x9d','\xa4'},{'\x9d','\xa5'},{'\x9d','\xa6'},{'\x9d','\xa7'},{'\x9d','\xa8'}, + {'\x9d','\xa9'},{'\x9d','\xaa'},{'\x9d','\xab'},{'\x9d','\xac'},{'\x9d','\xad'}, + {'\x9d','\xae'},{'\x9d','\xaf'},{'\x9d','\xb0'},{'\x9d','\xb1'},{'\x9d','\xb2'}, + {'\x9d','\xb3'},{'\x9d','\xb4'},{'\x9d','\xb5'},{'\x9d','\xb6'},{'\x9d','\xb7'}, + {'\x9d','\xb8'},{'\x9d','\xb9'},{'\x9d','\xba'},{'\x9d','\xbb'},{'\x9d','\xbc'}, + {'\x9d','\xbd'},{'\x9d','\xbe'},{'\x9d','\xbf'},{'\x9d','\xc0'},{'\x9d','\xc1'}, + {'\x9d','\xc2'},{'\x9d','\xc3'},{'\x9d','\xc4'},{'\x9d','\xc5'},{'\x9d','\xc6'}, + {'\x9d','\xc7'},{'\x9d','\xc8'},{'\x9d','\xc9'},{'\x9d','\xca'},{'\x9d','\xcb'}, + {'\x9d','\xcc'},{'\x9d','\xcd'},{'\x9d','\xce'},{'\x9d','\xcf'},{'\x9d','\xd0'}, + {'\x9d','\xd1'},{'\x9d','\xd2'},{'\x9d','\xd3'},{'\x9d','\xd4'},{'\x9d','\xd5'}, + {'\x9d','\xd6'},{'\x9d','\xd7'},{'\x9d','\xd8'},{'\x9d','\xd9'},{'\x9d','\xda'}, + {'\x9d','\xdb'},{'\x9d','\xdc'},{'\x9d','\xdd'},{'\x9d','\xde'},{'\x9d','\xdf'}, + {'\x9d','\xe0'},{'\x9d','\xe1'},{'\x9d','\xe2'},{'\x9d','\xe3'},{'\x9d','\xe4'}, + {'\x9d','\xe5'},{'\x9d','\xe6'},{'\x9d','\xe7'},{'\x9d','\xe8'},{'\x9d','\xe9'}, + {'\x9d','\xea'},{'\x9d','\xeb'},{'\x9d','\xec'},{'\x9d','\xed'},{'\x9d','\xee'}, + {'\x9d','\xef'},{'\x9d','\xf0'},{'\x9d','\xf1'},{'\x9d','\xf2'},{'\x9d','\xf3'}, + {'\x9d','\xf4'},{'\x9d','\xf5'},{'\x9d','\xf6'},{'\x9d','\xf7'},{'\x9d','\xf8'}, + {'\x9d','\xf9'},{'\x9d','\xfa'},{'\x9d','\xfb'},{'\x9d','\xfc'},{'\x9d','\xfd'}, + {'\x9d','\xfe'},{'\x9e','\x40'},{'\x9e','\x41'},{'\x9e','\x42'},{'\x9e','\x43'}, + {'\x9e','\x44'},{'\x9e','\x45'},{'\x9e','\x46'},{'\x9e','\x47'},{'\x9e','\x48'}, + {'\x9e','\x49'},{'\x9e','\x4a'},{'\x9e','\x4b'},{'\x9e','\x4c'},{'\x9e','\x4d'}, + {'\x9e','\x4e'},{'\x9e','\x4f'},{'\x9e','\x50'},{'\x9e','\x51'},{'\x9e','\x52'}, + {'\x9e','\x53'},{'\x9e','\x54'},{'\x9e','\x55'},{'\x9e','\x56'},{'\x9e','\x57'}, + {'\x9e','\x58'},{'\x9e','\x59'},{'\x9e','\x5a'},{'\x9e','\x5b'},{'\x9e','\x5c'}, + {'\x9e','\x5d'},{'\x9e','\x5e'},{'\x9e','\x5f'},{'\x9e','\x60'},{'\x9e','\x61'}, + {'\x9e','\x62'},{'\x9e','\x63'},{'\x9e','\x64'},{'\x9e','\x65'},{'\x9e','\x66'}, + {'\x9e','\x67'},{'\x9e','\x68'},{'\x9e','\x69'},{'\x9e','\x6a'},{'\x9e','\x6b'}, + {'\x9e','\x6c'},{'\x9e','\x6d'},{'\x9e','\x6e'},{'\x9e','\x6f'},{'\x9e','\x70'}, + {'\x9e','\x71'},{'\x9e','\x72'},{'\x9e','\x73'},{'\x9e','\x74'},{'\x9e','\x75'}, + {'\x9e','\x76'},{'\x9e','\x77'},{'\x9e','\x78'},{'\x9e','\x79'},{'\x9e','\x7a'}, + {'\x9e','\x7b'},{'\x9e','\x7c'},{'\x9e','\x7d'},{'\x9e','\x7e'},{'\x9e','\xa1'}, + {'\x9e','\xa2'},{'\x9e','\xa3'},{'\x9e','\xa4'},{'\x9e','\xa5'},{'\x9e','\xa6'}, + {'\x9e','\xa7'},{'\x9e','\xa8'},{'\x9e','\xa9'},{'\x9e','\xaa'},{'\x9e','\xab'}, + {'\x9e','\xac'},{'\x9e','\xad'},{'\x9e','\xae'},{'\x9e','\xaf'},{'\x9e','\xb0'}, + {'\x9e','\xb1'},{'\x9e','\xb2'},{'\x9e','\xb3'},{'\x9e','\xb4'},{'\x9e','\xb5'}, + {'\x9e','\xb6'},{'\x9e','\xb7'},{'\x9e','\xb8'},{'\x9e','\xb9'},{'\x9e','\xba'}, + {'\x9e','\xbb'},{'\x9e','\xbc'},{'\x9e','\xbd'},{'\x9e','\xbe'},{'\x9e','\xbf'}, + {'\x9e','\xc0'},{'\x9e','\xc1'},{'\x9e','\xc2'},{'\x9e','\xc3'},{'\x9e','\xc4'}, + {'\x9e','\xc5'},{'\x9e','\xc6'},{'\x9e','\xc7'},{'\x9e','\xc8'},{'\x9e','\xc9'}, + {'\x9e','\xca'},{'\x9e','\xcb'},{'\x9e','\xcc'},{'\x9e','\xcd'},{'\x9e','\xce'}, + {'\x9e','\xcf'},{'\x9e','\xd0'},{'\x9e','\xd1'},{'\x9e','\xd2'},{'\x9e','\xd3'}, + {'\x9e','\xd4'},{'\x9e','\xd5'},{'\x9e','\xd6'},{'\x9e','\xd7'},{'\x9e','\xd8'}, + {'\x9e','\xd9'},{'\x9e','\xda'},{'\x9e','\xdb'},{'\x9e','\xdc'},{'\x9e','\xdd'}, + {'\x9e','\xde'},{'\x9e','\xdf'},{'\x9e','\xe0'},{'\x9e','\xe1'},{'\x9e','\xe2'}, + {'\x9e','\xe3'},{'\x9e','\xe4'},{'\x9e','\xe5'},{'\x9e','\xe6'},{'\x9e','\xe7'}, + {'\x9e','\xe8'},{'\x9e','\xe9'},{'\x9e','\xea'},{'\x9e','\xeb'},{'\x9e','\xec'}, + {'\x9e','\xed'},{'\x9e','\xee'},{'\x9e','\xef'},{'\x9e','\xf0'},{'\x9e','\xf1'}, + {'\x9e','\xf2'},{'\x9e','\xf3'},{'\x9e','\xf4'},{'\x9e','\xf5'},{'\x9e','\xf6'}, + {'\x9e','\xf7'},{'\x9e','\xf8'},{'\x9e','\xf9'},{'\x9e','\xfa'},{'\x9e','\xfb'}, + {'\x9e','\xfc'},{'\x9e','\xfd'},{'\x9e','\xfe'},{'\x9f','\x40'},{'\x9f','\x41'}, + {'\x9f','\x42'},{'\x9f','\x43'},{'\x9f','\x44'},{'\x9f','\x45'},{'\x9f','\x46'}, + {'\x9f','\x47'},{'\x9f','\x48'},{'\x9f','\x49'},{'\x9f','\x4a'},{'\x9f','\x4b'}, + {'\x9f','\x4c'},{'\x9f','\x4d'},{'\x9f','\x4e'},{'\x9f','\x4f'},{'\x9f','\x50'}, + {'\x9f','\x51'},{'\x9f','\x52'},{'\x9f','\x53'},{'\x9f','\x54'},{'\x9f','\x55'}, + {'\x9f','\x56'},{'\x9f','\x57'},{'\x9f','\x58'},{'\x9f','\x59'},{'\x9f','\x5a'}, + {'\x9f','\x5b'},{'\x9f','\x5c'},{'\x9f','\x5d'},{'\x9f','\x5e'},{'\x9f','\x5f'}, + {'\x9f','\x60'},{'\x9f','\x61'},{'\x9f','\x62'},{'\x9f','\x63'},{'\x9f','\x64'}, + {'\x9f','\x65'},{'\x9f','\x66'},{'\x9f','\x67'},{'\x9f','\x68'},{'\x9f','\x69'}, + {'\x9f','\x6a'},{'\x9f','\x6b'},{'\x9f','\x6c'},{'\x9f','\x6d'},{'\x9f','\x6e'}, + {'\x9f','\x6f'},{'\x9f','\x70'},{'\x9f','\x71'},{'\x9f','\x72'},{'\x9f','\x73'}, + {'\x9f','\x74'},{'\x9f','\x75'},{'\x9f','\x76'},{'\x9f','\x77'},{'\x9f','\x78'}, + {'\x9f','\x79'},{'\x9f','\x7a'},{'\x9f','\x7b'},{'\x9f','\x7c'},{'\x9f','\x7d'}, + {'\x9f','\x7e'},{'\x9f','\xa1'},{'\x9f','\xa2'},{'\x9f','\xa3'},{'\x9f','\xa4'}, + {'\x9f','\xa5'},{'\x9f','\xa6'},{'\x9f','\xa7'},{'\x9f','\xa8'},{'\x9f','\xa9'}, + {'\x9f','\xaa'},{'\x9f','\xab'},{'\x9f','\xac'},{'\x9f','\xad'},{'\x9f','\xae'}, + {'\x9f','\xaf'},{'\x9f','\xb0'},{'\x9f','\xb1'},{'\x9f','\xb2'},{'\x9f','\xb3'}, + {'\x9f','\xb4'},{'\x9f','\xb5'},{'\x9f','\xb6'},{'\x9f','\xb7'},{'\x9f','\xb8'}, + {'\x9f','\xb9'},{'\x9f','\xba'},{'\x9f','\xbb'},{'\x9f','\xbc'},{'\x9f','\xbd'}, + {'\x9f','\xbe'},{'\x9f','\xbf'},{'\x9f','\xc0'},{'\x9f','\xc1'},{'\x9f','\xc2'}, + {'\x9f','\xc3'},{'\x9f','\xc4'},{'\x9f','\xc5'},{'\x9f','\xc6'},{'\x9f','\xc7'}, + {'\x9f','\xc8'},{'\x9f','\xc9'},{'\x9f','\xca'},{'\x9f','\xcb'},{'\x9f','\xcc'}, + {'\x9f','\xcd'},{'\x9f','\xce'},{'\x9f','\xcf'},{'\x9f','\xd0'},{'\x9f','\xd1'}, + {'\x9f','\xd2'},{'\x9f','\xd3'},{'\x9f','\xd4'},{'\x9f','\xd5'},{'\x9f','\xd6'}, + {'\x9f','\xd7'},{'\x9f','\xd8'},{'\x9f','\xd9'},{'\x9f','\xda'},{'\x9f','\xdb'}, + {'\x9f','\xdc'},{'\x9f','\xdd'},{'\x9f','\xde'},{'\x9f','\xdf'},{'\x9f','\xe0'}, + {'\x9f','\xe1'},{'\x9f','\xe2'},{'\x9f','\xe3'},{'\x9f','\xe4'},{'\x9f','\xe5'}, + {'\x9f','\xe6'},{'\x9f','\xe7'},{'\x9f','\xe8'},{'\x9f','\xe9'},{'\x9f','\xea'}, + {'\x9f','\xeb'},{'\x9f','\xec'},{'\x9f','\xed'},{'\x9f','\xee'},{'\x9f','\xef'}, + {'\x9f','\xf0'},{'\x9f','\xf1'},{'\x9f','\xf2'},{'\x9f','\xf3'},{'\x9f','\xf4'}, + {'\x9f','\xf5'},{'\x9f','\xf6'},{'\x9f','\xf7'},{'\x9f','\xf8'},{'\x9f','\xf9'}, + {'\x9f','\xfa'},{'\x9f','\xfb'},{'\x9f','\xfc'},{'\x9f','\xfd'},{'\x9f','\xfe'}, + {'\xa0','\x40'},{'\xa0','\x41'},{'\xa0','\x42'},{'\xa0','\x43'},{'\xa0','\x44'}, + {'\xa0','\x45'},{'\xa0','\x46'},{'\xa0','\x47'},{'\xa0','\x48'},{'\xa0','\x49'}, + {'\xa0','\x4a'},{'\xa0','\x4b'},{'\xa0','\x4c'},{'\xa0','\x4d'},{'\xa0','\x4e'}, + {'\xa0','\x4f'},{'\xa0','\x50'},{'\xa0','\x51'},{'\xa0','\x52'},{'\xa0','\x53'}, + {'\xa0','\x54'},{'\xa0','\x55'},{'\xa0','\x56'},{'\xa0','\x57'},{'\xa0','\x58'}, + {'\xa0','\x59'},{'\xa0','\x5a'},{'\xa0','\x5b'},{'\xa0','\x5c'},{'\xa0','\x5d'}, + {'\xa0','\x5e'},{'\xa0','\x5f'},{'\xa0','\x60'},{'\xa0','\x61'},{'\xa0','\x62'}, + {'\xa0','\x63'},{'\xa0','\x64'},{'\xa0','\x65'},{'\xa0','\x66'},{'\xa0','\x67'}, + {'\xa0','\x68'},{'\xa0','\x69'},{'\xa0','\x6a'},{'\xa0','\x6b'},{'\xa0','\x6c'}, + {'\xa0','\x6d'},{'\xa0','\x6e'},{'\xa0','\x6f'},{'\xa0','\x70'},{'\xa0','\x71'}, + {'\xa0','\x72'},{'\xa0','\x73'},{'\xa0','\x74'},{'\xa0','\x75'},{'\xa0','\x76'}, + {'\xa0','\x77'},{'\xa0','\x78'},{'\xa0','\x79'},{'\xa0','\x7a'},{'\xa0','\x7b'}, + {'\xa0','\x7c'},{'\xa0','\x7d'},{'\xa0','\x7e'},{'\xa0','\xa1'},{'\xa0','\xa2'}, + {'\xa0','\xa3'},{'\xa0','\xa4'},{'\xa0','\xa5'},{'\xa0','\xa6'},{'\xa0','\xa7'}, + {'\xa0','\xa8'},{'\xa0','\xa9'},{'\xa0','\xaa'},{'\xa0','\xab'},{'\xa0','\xac'}, + {'\xa0','\xad'},{'\xa0','\xae'},{'\xa0','\xaf'},{'\xa0','\xb0'},{'\xa0','\xb1'}, + {'\xa0','\xb2'},{'\xa0','\xb3'},{'\xa0','\xb4'},{'\xa0','\xb5'},{'\xa0','\xb6'}, + {'\xa0','\xb7'},{'\xa0','\xb8'},{'\xa0','\xb9'},{'\xa0','\xba'},{'\xa0','\xbb'}, + {'\xa0','\xbc'},{'\xa0','\xbd'},{'\xa0','\xbe'},{'\xa0','\xbf'},{'\xa0','\xc0'}, + {'\xa0','\xc1'},{'\xa0','\xc2'},{'\xa0','\xc3'},{'\xa0','\xc4'},{'\xa0','\xc5'}, + {'\xa0','\xc6'},{'\xa0','\xc7'},{'\xa0','\xc8'},{'\xa0','\xc9'},{'\xa0','\xca'}, + {'\xa0','\xcb'},{'\xa0','\xcc'},{'\xa0','\xcd'},{'\xa0','\xce'},{'\xa0','\xcf'}, + {'\xa0','\xd0'},{'\xa0','\xd1'},{'\xa0','\xd2'},{'\xa0','\xd3'},{'\xa0','\xd4'}, + {'\xa0','\xd5'},{'\xa0','\xd6'},{'\xa0','\xd7'},{'\xa0','\xd8'},{'\xa0','\xd9'}, + {'\xa0','\xda'},{'\xa0','\xdb'},{'\xa0','\xdc'},{'\xa0','\xdd'},{'\xa0','\xde'}, + {'\xa0','\xdf'},{'\xa0','\xe0'},{'\xa0','\xe1'},{'\xa0','\xe2'},{'\xa0','\xe3'}, + {'\xa0','\xe4'},{'\xa0','\xe5'},{'\xa0','\xe6'},{'\xa0','\xe7'},{'\xa0','\xe8'}, + {'\xa0','\xe9'},{'\xa0','\xea'},{'\xa0','\xeb'},{'\xa0','\xec'},{'\xa0','\xed'}, + {'\xa0','\xee'},{'\xa0','\xef'},{'\xa0','\xf0'},{'\xa0','\xf1'},{'\xa0','\xf2'}, + {'\xa0','\xf3'},{'\xa0','\xf4'},{'\xa0','\xf5'},{'\xa0','\xf6'},{'\xa0','\xf7'}, + {'\xa0','\xf8'},{'\xa0','\xf9'},{'\xa0','\xfa'},{'\xa0','\xfb'},{'\xa0','\xfc'}, + {'\xa0','\xfd'},{'\xa0','\xfe'},{'\x81','\x40'},{'\x81','\x41'},{'\x81','\x42'}, + {'\x81','\x43'},{'\x81','\x44'},{'\x81','\x45'},{'\x81','\x46'},{'\x81','\x47'}, + {'\x81','\x48'},{'\x81','\x49'},{'\x81','\x4a'},{'\x81','\x4b'},{'\x81','\x4c'}, + {'\x81','\x4d'},{'\x81','\x4e'},{'\x81','\x4f'},{'\x81','\x50'},{'\x81','\x51'}, + {'\x81','\x52'},{'\x81','\x53'},{'\x81','\x54'},{'\x81','\x55'},{'\x81','\x56'}, + {'\x81','\x57'},{'\x81','\x58'},{'\x81','\x59'},{'\x81','\x5a'},{'\x81','\x5b'}, + {'\x81','\x5c'},{'\x81','\x5d'},{'\x81','\x5e'},{'\x81','\x5f'},{'\x81','\x60'}, + {'\x81','\x61'},{'\x81','\x62'},{'\x81','\x63'},{'\x81','\x64'},{'\x81','\x65'}, + {'\x81','\x66'},{'\x81','\x67'},{'\x81','\x68'},{'\x81','\x69'},{'\x81','\x6a'}, + {'\x81','\x6b'},{'\x81','\x6c'},{'\x81','\x6d'},{'\x81','\x6e'},{'\x81','\x6f'}, + {'\x81','\x70'},{'\x81','\x71'},{'\x81','\x72'},{'\x81','\x73'},{'\x81','\x74'}, + {'\x81','\x75'},{'\x81','\x76'},{'\x81','\x77'},{'\x81','\x78'},{'\x81','\x79'}, + {'\x81','\x7a'},{'\x81','\x7b'},{'\x81','\x7c'},{'\x81','\x7d'},{'\x81','\x7e'}, + {'\x81','\xa1'},{'\x81','\xa2'},{'\x81','\xa3'},{'\x81','\xa4'},{'\x81','\xa5'}, + {'\x81','\xa6'},{'\x81','\xa7'},{'\x81','\xa8'},{'\x81','\xa9'},{'\x81','\xaa'}, + {'\x81','\xab'},{'\x81','\xac'},{'\x81','\xad'},{'\x81','\xae'},{'\x81','\xaf'}, + {'\x81','\xb0'},{'\x81','\xb1'},{'\x81','\xb2'},{'\x81','\xb3'},{'\x81','\xb4'}, + {'\x81','\xb5'},{'\x81','\xb6'},{'\x81','\xb7'},{'\x81','\xb8'},{'\x81','\xb9'}, + {'\x81','\xba'},{'\x81','\xbb'},{'\x81','\xbc'},{'\x81','\xbd'},{'\x81','\xbe'}, + {'\x81','\xbf'},{'\x81','\xc0'},{'\x81','\xc1'},{'\x81','\xc2'},{'\x81','\xc3'}, + {'\x81','\xc4'},{'\x81','\xc5'},{'\x81','\xc6'},{'\x81','\xc7'},{'\x81','\xc8'}, + {'\x81','\xc9'},{'\x81','\xca'},{'\x81','\xcb'},{'\x81','\xcc'},{'\x81','\xcd'}, + {'\x81','\xce'},{'\x81','\xcf'},{'\x81','\xd0'},{'\x81','\xd1'},{'\x81','\xd2'}, + {'\x81','\xd3'},{'\x81','\xd4'},{'\x81','\xd5'},{'\x81','\xd6'},{'\x81','\xd7'}, + {'\x81','\xd8'},{'\x81','\xd9'},{'\x81','\xda'},{'\x81','\xdb'},{'\x81','\xdc'}, + {'\x81','\xdd'},{'\x81','\xde'},{'\x81','\xdf'},{'\x81','\xe0'},{'\x81','\xe1'}, + {'\x81','\xe2'},{'\x81','\xe3'},{'\x81','\xe4'},{'\x81','\xe5'},{'\x81','\xe6'}, + {'\x81','\xe7'},{'\x81','\xe8'},{'\x81','\xe9'},{'\x81','\xea'},{'\x81','\xeb'}, + {'\x81','\xec'},{'\x81','\xed'},{'\x81','\xee'},{'\x81','\xef'},{'\x81','\xf0'}, + {'\x81','\xf1'},{'\x81','\xf2'},{'\x81','\xf3'},{'\x81','\xf4'},{'\x81','\xf5'}, + {'\x81','\xf6'},{'\x81','\xf7'},{'\x81','\xf8'},{'\x81','\xf9'},{'\x81','\xfa'}, + {'\x81','\xfb'},{'\x81','\xfc'},{'\x81','\xfd'},{'\x81','\xfe'},{'\x82','\x40'}, + {'\x82','\x41'},{'\x82','\x42'},{'\x82','\x43'},{'\x82','\x44'},{'\x82','\x45'}, + {'\x82','\x46'},{'\x82','\x47'},{'\x82','\x48'},{'\x82','\x49'},{'\x82','\x4a'}, + {'\x82','\x4b'},{'\x82','\x4c'},{'\x82','\x4d'},{'\x82','\x4e'},{'\x82','\x4f'}, + {'\x82','\x50'},{'\x82','\x51'},{'\x82','\x52'},{'\x82','\x53'},{'\x82','\x54'}, + {'\x82','\x55'},{'\x82','\x56'},{'\x82','\x57'},{'\x82','\x58'},{'\x82','\x59'}, + {'\x82','\x5a'},{'\x82','\x5b'},{'\x82','\x5c'},{'\x82','\x5d'},{'\x82','\x5e'}, + {'\x82','\x5f'},{'\x82','\x60'},{'\x82','\x61'},{'\x82','\x62'},{'\x82','\x63'}, + {'\x82','\x64'},{'\x82','\x65'},{'\x82','\x66'},{'\x82','\x67'},{'\x82','\x68'}, + {'\x82','\x69'},{'\x82','\x6a'},{'\x82','\x6b'},{'\x82','\x6c'},{'\x82','\x6d'}, + {'\x82','\x6e'},{'\x82','\x6f'},{'\x82','\x70'},{'\x82','\x71'},{'\x82','\x72'}, + {'\x82','\x73'},{'\x82','\x74'},{'\x82','\x75'},{'\x82','\x76'},{'\x82','\x77'}, + {'\x82','\x78'},{'\x82','\x79'},{'\x82','\x7a'},{'\x82','\x7b'},{'\x82','\x7c'}, + {'\x82','\x7d'},{'\x82','\x7e'},{'\x82','\xa1'},{'\x82','\xa2'},{'\x82','\xa3'}, + {'\x82','\xa4'},{'\x82','\xa5'},{'\x82','\xa6'},{'\x82','\xa7'},{'\x82','\xa8'}, + {'\x82','\xa9'},{'\x82','\xaa'},{'\x82','\xab'},{'\x82','\xac'},{'\x82','\xad'}, + {'\x82','\xae'},{'\x82','\xaf'},{'\x82','\xb0'},{'\x82','\xb1'},{'\x82','\xb2'}, + {'\x82','\xb3'},{'\x82','\xb4'},{'\x82','\xb5'},{'\x82','\xb6'},{'\x82','\xb7'}, + {'\x82','\xb8'},{'\x82','\xb9'},{'\x82','\xba'},{'\x82','\xbb'},{'\x82','\xbc'}, + {'\x82','\xbd'},{'\x82','\xbe'},{'\x82','\xbf'},{'\x82','\xc0'},{'\x82','\xc1'}, + {'\x82','\xc2'},{'\x82','\xc3'},{'\x82','\xc4'},{'\x82','\xc5'},{'\x82','\xc6'}, + {'\x82','\xc7'},{'\x82','\xc8'},{'\x82','\xc9'},{'\x82','\xca'},{'\x82','\xcb'}, + {'\x82','\xcc'},{'\x82','\xcd'},{'\x82','\xce'},{'\x82','\xcf'},{'\x82','\xd0'}, + {'\x82','\xd1'},{'\x82','\xd2'},{'\x82','\xd3'},{'\x82','\xd4'},{'\x82','\xd5'}, + {'\x82','\xd6'},{'\x82','\xd7'},{'\x82','\xd8'},{'\x82','\xd9'},{'\x82','\xda'}, + {'\x82','\xdb'},{'\x82','\xdc'},{'\x82','\xdd'},{'\x82','\xde'},{'\x82','\xdf'}, + {'\x82','\xe0'},{'\x82','\xe1'},{'\x82','\xe2'},{'\x82','\xe3'},{'\x82','\xe4'}, + {'\x82','\xe5'},{'\x82','\xe6'},{'\x82','\xe7'},{'\x82','\xe8'},{'\x82','\xe9'}, + {'\x82','\xea'},{'\x82','\xeb'},{'\x82','\xec'},{'\x82','\xed'},{'\x82','\xee'}, + {'\x82','\xef'},{'\x82','\xf0'},{'\x82','\xf1'},{'\x82','\xf2'},{'\x82','\xf3'}, + {'\x82','\xf4'},{'\x82','\xf5'},{'\x82','\xf6'},{'\x82','\xf7'},{'\x82','\xf8'}, + {'\x82','\xf9'},{'\x82','\xfa'},{'\x82','\xfb'},{'\x82','\xfc'},{'\x82','\xfd'}, + {'\x82','\xfe'},{'\x83','\x40'},{'\x83','\x41'},{'\x83','\x42'},{'\x83','\x43'}, + {'\x83','\x44'},{'\x83','\x45'},{'\x83','\x46'},{'\x83','\x47'},{'\x83','\x48'}, + {'\x83','\x49'},{'\x83','\x4a'},{'\x83','\x4b'},{'\x83','\x4c'},{'\x83','\x4d'}, + {'\x83','\x4e'},{'\x83','\x4f'},{'\x83','\x50'},{'\x83','\x51'},{'\x83','\x52'}, + {'\x83','\x53'},{'\x83','\x54'},{'\x83','\x55'},{'\x83','\x56'},{'\x83','\x57'}, + {'\x83','\x58'},{'\x83','\x59'},{'\x83','\x5a'},{'\x83','\x5b'},{'\x83','\x5c'}, + {'\x83','\x5d'},{'\x83','\x5e'},{'\x83','\x5f'},{'\x83','\x60'},{'\x83','\x61'}, + {'\x83','\x62'},{'\x83','\x63'},{'\x83','\x64'},{'\x83','\x65'},{'\x83','\x66'}, + {'\x83','\x67'},{'\x83','\x68'},{'\x83','\x69'},{'\x83','\x6a'},{'\x83','\x6b'}, + {'\x83','\x6c'},{'\x83','\x6d'},{'\x83','\x6e'},{'\x83','\x6f'},{'\x83','\x70'}, + {'\x83','\x71'},{'\x83','\x72'},{'\x83','\x73'},{'\x83','\x74'},{'\x83','\x75'}, + {'\x83','\x76'},{'\x83','\x77'},{'\x83','\x78'},{'\x83','\x79'},{'\x83','\x7a'}, + {'\x83','\x7b'},{'\x83','\x7c'},{'\x83','\x7d'},{'\x83','\x7e'},{'\x83','\xa1'}, + {'\x83','\xa2'},{'\x83','\xa3'},{'\x83','\xa4'},{'\x83','\xa5'},{'\x83','\xa6'}, + {'\x83','\xa7'},{'\x83','\xa8'},{'\x83','\xa9'},{'\x83','\xaa'},{'\x83','\xab'}, + {'\x83','\xac'},{'\x83','\xad'},{'\x83','\xae'},{'\x83','\xaf'},{'\x83','\xb0'}, + {'\x83','\xb1'},{'\x83','\xb2'},{'\x83','\xb3'},{'\x83','\xb4'},{'\x83','\xb5'}, + {'\x83','\xb6'},{'\x83','\xb7'},{'\x83','\xb8'},{'\x83','\xb9'},{'\x83','\xba'}, + {'\x83','\xbb'},{'\x83','\xbc'},{'\x83','\xbd'},{'\x83','\xbe'},{'\x83','\xbf'}, + {'\x83','\xc0'},{'\x83','\xc1'},{'\x83','\xc2'},{'\x83','\xc3'},{'\x83','\xc4'}, + {'\x83','\xc5'},{'\x83','\xc6'},{'\x83','\xc7'},{'\x83','\xc8'},{'\x83','\xc9'}, + {'\x83','\xca'},{'\x83','\xcb'},{'\x83','\xcc'},{'\x83','\xcd'},{'\x83','\xce'}, + {'\x83','\xcf'},{'\x83','\xd0'},{'\x83','\xd1'},{'\x83','\xd2'},{'\x83','\xd3'}, + {'\x83','\xd4'},{'\x83','\xd5'},{'\x83','\xd6'},{'\x83','\xd7'},{'\x83','\xd8'}, + {'\x83','\xd9'},{'\x83','\xda'},{'\x83','\xdb'},{'\x83','\xdc'},{'\x83','\xdd'}, + {'\x83','\xde'},{'\x83','\xdf'},{'\x83','\xe0'},{'\x83','\xe1'},{'\x83','\xe2'}, + {'\x83','\xe3'},{'\x83','\xe4'},{'\x83','\xe5'},{'\x83','\xe6'},{'\x83','\xe7'}, + {'\x83','\xe8'},{'\x83','\xe9'},{'\x83','\xea'},{'\x83','\xeb'},{'\x83','\xec'}, + {'\x83','\xed'},{'\x83','\xee'},{'\x83','\xef'},{'\x83','\xf0'},{'\x83','\xf1'}, + {'\x83','\xf2'},{'\x83','\xf3'},{'\x83','\xf4'},{'\x83','\xf5'},{'\x83','\xf6'}, + {'\x83','\xf7'},{'\x83','\xf8'},{'\x83','\xf9'},{'\x83','\xfa'},{'\x83','\xfb'}, + {'\x83','\xfc'},{'\x83','\xfd'},{'\x83','\xfe'},{'\x84','\x40'},{'\x84','\x41'}, + {'\x84','\x42'},{'\x84','\x43'},{'\x84','\x44'},{'\x84','\x45'},{'\x84','\x46'}, + {'\x84','\x47'},{'\x84','\x48'},{'\x84','\x49'},{'\x84','\x4a'},{'\x84','\x4b'}, + {'\x84','\x4c'},{'\x84','\x4d'},{'\x84','\x4e'},{'\x84','\x4f'},{'\x84','\x50'}, + {'\x84','\x51'},{'\x84','\x52'},{'\x84','\x53'},{'\x84','\x54'},{'\x84','\x55'}, + {'\x84','\x56'},{'\x84','\x57'},{'\x84','\x58'},{'\x84','\x59'},{'\x84','\x5a'}, + {'\x84','\x5b'},{'\x84','\x5c'},{'\x84','\x5d'},{'\x84','\x5e'},{'\x84','\x5f'}, + {'\x84','\x60'},{'\x84','\x61'},{'\x84','\x62'},{'\x84','\x63'},{'\x84','\x64'}, + {'\x84','\x65'},{'\x84','\x66'},{'\x84','\x67'},{'\x84','\x68'},{'\x84','\x69'}, + {'\x84','\x6a'},{'\x84','\x6b'},{'\x84','\x6c'},{'\x84','\x6d'},{'\x84','\x6e'}, + {'\x84','\x6f'},{'\x84','\x70'},{'\x84','\x71'},{'\x84','\x72'},{'\x84','\x73'}, + {'\x84','\x74'},{'\x84','\x75'},{'\x84','\x76'},{'\x84','\x77'},{'\x84','\x78'}, + {'\x84','\x79'},{'\x84','\x7a'},{'\x84','\x7b'},{'\x84','\x7c'},{'\x84','\x7d'}, + {'\x84','\x7e'},{'\x84','\xa1'},{'\x84','\xa2'},{'\x84','\xa3'},{'\x84','\xa4'}, + {'\x84','\xa5'},{'\x84','\xa6'},{'\x84','\xa7'},{'\x84','\xa8'},{'\x84','\xa9'}, + {'\x84','\xaa'},{'\x84','\xab'},{'\x84','\xac'},{'\x84','\xad'},{'\x84','\xae'}, + {'\x84','\xaf'},{'\x84','\xb0'},{'\x84','\xb1'},{'\x84','\xb2'},{'\x84','\xb3'}, + {'\x84','\xb4'},{'\x84','\xb5'},{'\x84','\xb6'},{'\x84','\xb7'},{'\x84','\xb8'}, + {'\x84','\xb9'},{'\x84','\xba'},{'\x84','\xbb'},{'\x84','\xbc'},{'\x84','\xbd'}, + {'\x84','\xbe'},{'\x84','\xbf'},{'\x84','\xc0'},{'\x84','\xc1'},{'\x84','\xc2'}, + {'\x84','\xc3'},{'\x84','\xc4'},{'\x84','\xc5'},{'\x84','\xc6'},{'\x84','\xc7'}, + {'\x84','\xc8'},{'\x84','\xc9'},{'\x84','\xca'},{'\x84','\xcb'},{'\x84','\xcc'}, + {'\x84','\xcd'},{'\x84','\xce'},{'\x84','\xcf'},{'\x84','\xd0'},{'\x84','\xd1'}, + {'\x84','\xd2'},{'\x84','\xd3'},{'\x84','\xd4'},{'\x84','\xd5'},{'\x84','\xd6'}, + {'\x84','\xd7'},{'\x84','\xd8'},{'\x84','\xd9'},{'\x84','\xda'},{'\x84','\xdb'}, + {'\x84','\xdc'},{'\x84','\xdd'},{'\x84','\xde'},{'\x84','\xdf'},{'\x84','\xe0'}, + {'\x84','\xe1'},{'\x84','\xe2'},{'\x84','\xe3'},{'\x84','\xe4'},{'\x84','\xe5'}, + {'\x84','\xe6'},{'\x84','\xe7'},{'\x84','\xe8'},{'\x84','\xe9'},{'\x84','\xea'}, + {'\x84','\xeb'},{'\x84','\xec'},{'\x84','\xed'},{'\x84','\xee'},{'\x84','\xef'}, + {'\x84','\xf0'},{'\x84','\xf1'},{'\x84','\xf2'},{'\x84','\xf3'},{'\x84','\xf4'}, + {'\x84','\xf5'},{'\x84','\xf6'},{'\x84','\xf7'},{'\x84','\xf8'},{'\x84','\xf9'}, + {'\x84','\xfa'},{'\x84','\xfb'},{'\x84','\xfc'},{'\x84','\xfd'},{'\x84','\xfe'}, + {'\x85','\x40'},{'\x85','\x41'},{'\x85','\x42'},{'\x85','\x43'},{'\x85','\x44'}, + {'\x85','\x45'},{'\x85','\x46'},{'\x85','\x47'},{'\x85','\x48'},{'\x85','\x49'}, + {'\x85','\x4a'},{'\x85','\x4b'},{'\x85','\x4c'},{'\x85','\x4d'},{'\x85','\x4e'}, + {'\x85','\x4f'},{'\x85','\x50'},{'\x85','\x51'},{'\x85','\x52'},{'\x85','\x53'}, + {'\x85','\x54'},{'\x85','\x55'},{'\x85','\x56'},{'\x85','\x57'},{'\x85','\x58'}, + {'\x85','\x59'},{'\x85','\x5a'},{'\x85','\x5b'},{'\x85','\x5c'},{'\x85','\x5d'}, + {'\x85','\x5e'},{'\x85','\x5f'},{'\x85','\x60'},{'\x85','\x61'},{'\x85','\x62'}, + {'\x85','\x63'},{'\x85','\x64'},{'\x85','\x65'},{'\x85','\x66'},{'\x85','\x67'}, + {'\x85','\x68'},{'\x85','\x69'},{'\x85','\x6a'},{'\x85','\x6b'},{'\x85','\x6c'}, + {'\x85','\x6d'},{'\x85','\x6e'},{'\x85','\x6f'},{'\x85','\x70'},{'\x85','\x71'}, + {'\x85','\x72'},{'\x85','\x73'},{'\x85','\x74'},{'\x85','\x75'},{'\x85','\x76'}, + {'\x85','\x77'},{'\x85','\x78'},{'\x85','\x79'},{'\x85','\x7a'},{'\x85','\x7b'}, + {'\x85','\x7c'},{'\x85','\x7d'},{'\x85','\x7e'},{'\x85','\xa1'},{'\x85','\xa2'}, + {'\x85','\xa3'},{'\x85','\xa4'},{'\x85','\xa5'},{'\x85','\xa6'},{'\x85','\xa7'}, + {'\x85','\xa8'},{'\x85','\xa9'},{'\x85','\xaa'},{'\x85','\xab'},{'\x85','\xac'}, + {'\x85','\xad'},{'\x85','\xae'},{'\x85','\xaf'},{'\x85','\xb0'},{'\x85','\xb1'}, + {'\x85','\xb2'},{'\x85','\xb3'},{'\x85','\xb4'},{'\x85','\xb5'},{'\x85','\xb6'}, + {'\x85','\xb7'},{'\x85','\xb8'},{'\x85','\xb9'},{'\x85','\xba'},{'\x85','\xbb'}, + {'\x85','\xbc'},{'\x85','\xbd'},{'\x85','\xbe'},{'\x85','\xbf'},{'\x85','\xc0'}, + {'\x85','\xc1'},{'\x85','\xc2'},{'\x85','\xc3'},{'\x85','\xc4'},{'\x85','\xc5'}, + {'\x85','\xc6'},{'\x85','\xc7'},{'\x85','\xc8'},{'\x85','\xc9'},{'\x85','\xca'}, + {'\x85','\xcb'},{'\x85','\xcc'},{'\x85','\xcd'},{'\x85','\xce'},{'\x85','\xcf'}, + {'\x85','\xd0'},{'\x85','\xd1'},{'\x85','\xd2'},{'\x85','\xd3'},{'\x85','\xd4'}, + {'\x85','\xd5'},{'\x85','\xd6'},{'\x85','\xd7'},{'\x85','\xd8'},{'\x85','\xd9'}, + {'\x85','\xda'},{'\x85','\xdb'},{'\x85','\xdc'},{'\x85','\xdd'},{'\x85','\xde'}, + {'\x85','\xdf'},{'\x85','\xe0'},{'\x85','\xe1'},{'\x85','\xe2'},{'\x85','\xe3'}, + {'\x85','\xe4'},{'\x85','\xe5'},{'\x85','\xe6'},{'\x85','\xe7'},{'\x85','\xe8'}, + {'\x85','\xe9'},{'\x85','\xea'},{'\x85','\xeb'},{'\x85','\xec'},{'\x85','\xed'}, + {'\x85','\xee'},{'\x85','\xef'},{'\x85','\xf0'},{'\x85','\xf1'},{'\x85','\xf2'}, + {'\x85','\xf3'},{'\x85','\xf4'},{'\x85','\xf5'},{'\x85','\xf6'},{'\x85','\xf7'}, + {'\x85','\xf8'},{'\x85','\xf9'},{'\x85','\xfa'},{'\x85','\xfb'},{'\x85','\xfc'}, + {'\x85','\xfd'},{'\x85','\xfe'},{'\x86','\x40'},{'\x86','\x41'},{'\x86','\x42'}, + {'\x86','\x43'},{'\x86','\x44'},{'\x86','\x45'},{'\x86','\x46'},{'\x86','\x47'}, + {'\x86','\x48'},{'\x86','\x49'},{'\x86','\x4a'},{'\x86','\x4b'},{'\x86','\x4c'}, + {'\x86','\x4d'},{'\x86','\x4e'},{'\x86','\x4f'},{'\x86','\x50'},{'\x86','\x51'}, + {'\x86','\x52'},{'\x86','\x53'},{'\x86','\x54'},{'\x86','\x55'},{'\x86','\x56'}, + {'\x86','\x57'},{'\x86','\x58'},{'\x86','\x59'},{'\x86','\x5a'},{'\x86','\x5b'}, + {'\x86','\x5c'},{'\x86','\x5d'},{'\x86','\x5e'},{'\x86','\x5f'},{'\x86','\x60'}, + {'\x86','\x61'},{'\x86','\x62'},{'\x86','\x63'},{'\x86','\x64'},{'\x86','\x65'}, + {'\x86','\x66'},{'\x86','\x67'},{'\x86','\x68'},{'\x86','\x69'},{'\x86','\x6a'}, + {'\x86','\x6b'},{'\x86','\x6c'},{'\x86','\x6d'},{'\x86','\x6e'},{'\x86','\x6f'}, + {'\x86','\x70'},{'\x86','\x71'},{'\x86','\x72'},{'\x86','\x73'},{'\x86','\x74'}, + {'\x86','\x75'},{'\x86','\x76'},{'\x86','\x77'},{'\x86','\x78'},{'\x86','\x79'}, + {'\x86','\x7a'},{'\x86','\x7b'},{'\x86','\x7c'},{'\x86','\x7d'},{'\x86','\x7e'}, + {'\x86','\xa1'},{'\x86','\xa2'},{'\x86','\xa3'},{'\x86','\xa4'},{'\x86','\xa5'}, + {'\x86','\xa6'},{'\x86','\xa7'},{'\x86','\xa8'},{'\x86','\xa9'},{'\x86','\xaa'}, + {'\x86','\xab'},{'\x86','\xac'},{'\x86','\xad'},{'\x86','\xae'},{'\x86','\xaf'}, + {'\x86','\xb0'},{'\x86','\xb1'},{'\x86','\xb2'},{'\x86','\xb3'},{'\x86','\xb4'}, + {'\x86','\xb5'},{'\x86','\xb6'},{'\x86','\xb7'},{'\x86','\xb8'},{'\x86','\xb9'}, + {'\x86','\xba'},{'\x86','\xbb'},{'\x86','\xbc'},{'\x86','\xbd'},{'\x86','\xbe'}, + {'\x86','\xbf'},{'\x86','\xc0'},{'\x86','\xc1'},{'\x86','\xc2'},{'\x86','\xc3'}, + {'\x86','\xc4'},{'\x86','\xc5'},{'\x86','\xc6'},{'\x86','\xc7'},{'\x86','\xc8'}, + {'\x86','\xc9'},{'\x86','\xca'},{'\x86','\xcb'},{'\x86','\xcc'},{'\x86','\xcd'}, + {'\x86','\xce'},{'\x86','\xcf'},{'\x86','\xd0'},{'\x86','\xd1'},{'\x86','\xd2'}, + {'\x86','\xd3'},{'\x86','\xd4'},{'\x86','\xd5'},{'\x86','\xd6'},{'\x86','\xd7'}, + {'\x86','\xd8'},{'\x86','\xd9'},{'\x86','\xda'},{'\x86','\xdb'},{'\x86','\xdc'}, + {'\x86','\xdd'},{'\x86','\xde'},{'\x86','\xdf'},{'\x86','\xe0'},{'\x86','\xe1'}, + {'\x86','\xe2'},{'\x86','\xe3'},{'\x86','\xe4'},{'\x86','\xe5'},{'\x86','\xe6'}, + {'\x86','\xe7'},{'\x86','\xe8'},{'\x86','\xe9'},{'\x86','\xea'},{'\x86','\xeb'}, + {'\x86','\xec'},{'\x86','\xed'},{'\x86','\xee'},{'\x86','\xef'},{'\x86','\xf0'}, + {'\x86','\xf1'},{'\x86','\xf2'},{'\x86','\xf3'},{'\x86','\xf4'},{'\x86','\xf5'}, + {'\x86','\xf6'},{'\x86','\xf7'},{'\x86','\xf8'},{'\x86','\xf9'},{'\x86','\xfa'}, + {'\x86','\xfb'},{'\x86','\xfc'},{'\x86','\xfd'},{'\x86','\xfe'},{'\x87','\x40'}, + {'\x87','\x41'},{'\x87','\x42'},{'\x87','\x43'},{'\x87','\x44'},{'\x87','\x45'}, + {'\x87','\x46'},{'\x87','\x47'},{'\x87','\x48'},{'\x87','\x49'},{'\x87','\x4a'}, + {'\x87','\x4b'},{'\x87','\x4c'},{'\x87','\x4d'},{'\x87','\x4e'},{'\x87','\x4f'}, + {'\x87','\x50'},{'\x87','\x51'},{'\x87','\x52'},{'\x87','\x53'},{'\x87','\x54'}, + {'\x87','\x55'},{'\x87','\x56'},{'\x87','\x57'},{'\x87','\x58'},{'\x87','\x59'}, + {'\x87','\x5a'},{'\x87','\x5b'},{'\x87','\x5c'},{'\x87','\x5d'},{'\x87','\x5e'}, + {'\x87','\x5f'},{'\x87','\x60'},{'\x87','\x61'},{'\x87','\x62'},{'\x87','\x63'}, + {'\x87','\x64'},{'\x87','\x65'},{'\x87','\x66'},{'\x87','\x67'},{'\x87','\x68'}, + {'\x87','\x69'},{'\x87','\x6a'},{'\x87','\x6b'},{'\x87','\x6c'},{'\x87','\x6d'}, + {'\x87','\x6e'},{'\x87','\x6f'},{'\x87','\x70'},{'\x87','\x71'},{'\x87','\x72'}, + {'\x87','\x73'},{'\x87','\x74'},{'\x87','\x75'},{'\x87','\x76'},{'\x87','\x77'}, + {'\x87','\x78'},{'\x87','\x79'},{'\x87','\x7a'},{'\x87','\x7b'},{'\x87','\x7c'}, + {'\x87','\x7d'},{'\x87','\x7e'},{'\x87','\xa1'},{'\x87','\xa2'},{'\x87','\xa3'}, + {'\x87','\xa4'},{'\x87','\xa5'},{'\x87','\xa6'},{'\x87','\xa7'},{'\x87','\xa8'}, + {'\x87','\xa9'},{'\x87','\xaa'},{'\x87','\xab'},{'\x87','\xac'},{'\x87','\xad'}, + {'\x87','\xae'},{'\x87','\xaf'},{'\x87','\xb0'},{'\x87','\xb1'},{'\x87','\xb2'}, + {'\x87','\xb3'},{'\x87','\xb4'},{'\x87','\xb5'},{'\x87','\xb6'},{'\x87','\xb7'}, + {'\x87','\xb8'},{'\x87','\xb9'},{'\x87','\xba'},{'\x87','\xbb'},{'\x87','\xbc'}, + {'\x87','\xbd'},{'\x87','\xbe'},{'\x87','\xbf'},{'\x87','\xc0'},{'\x87','\xc1'}, + {'\x87','\xc2'},{'\x87','\xc3'},{'\x87','\xc4'},{'\x87','\xc5'},{'\x87','\xc6'}, + {'\x87','\xc7'},{'\x87','\xc8'},{'\x87','\xc9'},{'\x87','\xca'},{'\x87','\xcb'}, + {'\x87','\xcc'},{'\x87','\xcd'},{'\x87','\xce'},{'\x87','\xcf'},{'\x87','\xd0'}, + {'\x87','\xd1'},{'\x87','\xd2'},{'\x87','\xd3'},{'\x87','\xd4'},{'\x87','\xd5'}, + {'\x87','\xd6'},{'\x87','\xd7'},{'\x87','\xd8'},{'\x87','\xd9'},{'\x87','\xda'}, + {'\x87','\xdb'},{'\x87','\xdc'},{'\x87','\xdd'},{'\x87','\xde'},{'\x87','\xdf'}, + {'\x87','\xe0'},{'\x87','\xe1'},{'\x87','\xe2'},{'\x87','\xe3'},{'\x87','\xe4'}, + {'\x87','\xe5'},{'\x87','\xe6'},{'\x87','\xe7'},{'\x87','\xe8'},{'\x87','\xe9'}, + {'\x87','\xea'},{'\x87','\xeb'},{'\x87','\xec'},{'\x87','\xed'},{'\x87','\xee'}, + {'\x87','\xef'},{'\x87','\xf0'},{'\x87','\xf1'},{'\x87','\xf2'},{'\x87','\xf3'}, + {'\x87','\xf4'},{'\x87','\xf5'},{'\x87','\xf6'},{'\x87','\xf7'},{'\x87','\xf8'}, + {'\x87','\xf9'},{'\x87','\xfa'},{'\x87','\xfb'},{'\x87','\xfc'},{'\x87','\xfd'}, + {'\x87','\xfe'},{'\x88','\x40'},{'\x88','\x41'},{'\x88','\x42'},{'\x88','\x43'}, + {'\x88','\x44'},{'\x88','\x45'},{'\x88','\x46'},{'\x88','\x47'},{'\x88','\x48'}, + {'\x88','\x49'},{'\x88','\x4a'},{'\x88','\x4b'},{'\x88','\x4c'},{'\x88','\x4d'}, + {'\x88','\x4e'},{'\x88','\x4f'},{'\x88','\x50'},{'\x88','\x51'},{'\x88','\x52'}, + {'\x88','\x53'},{'\x88','\x54'},{'\x88','\x55'},{'\x88','\x56'},{'\x88','\x57'}, + {'\x88','\x58'},{'\x88','\x59'},{'\x88','\x5a'},{'\x88','\x5b'},{'\x88','\x5c'}, + {'\x88','\x5d'},{'\x88','\x5e'},{'\x88','\x5f'},{'\x88','\x60'},{'\x88','\x61'}, + {'\x88','\x62'},{'\x88','\x63'},{'\x88','\x64'},{'\x88','\x65'},{'\x88','\x66'}, + {'\x88','\x67'},{'\x88','\x68'},{'\x88','\x69'},{'\x88','\x6a'},{'\x88','\x6b'}, + {'\x88','\x6c'},{'\x88','\x6d'},{'\x88','\x6e'},{'\x88','\x6f'},{'\x88','\x70'}, + {'\x88','\x71'},{'\x88','\x72'},{'\x88','\x73'},{'\x88','\x74'},{'\x88','\x75'}, + {'\x88','\x76'},{'\x88','\x77'},{'\x88','\x78'},{'\x88','\x79'},{'\x88','\x7a'}, + {'\x88','\x7b'},{'\x88','\x7c'},{'\x88','\x7d'},{'\x88','\x7e'},{'\x88','\xa1'}, + {'\x88','\xa2'},{'\x88','\xa3'},{'\x88','\xa4'},{'\x88','\xa5'},{'\x88','\xa6'}, + {'\x88','\xa7'},{'\x88','\xa8'},{'\x88','\xa9'},{'\x88','\xaa'},{'\x88','\xab'}, + {'\x88','\xac'},{'\x88','\xad'},{'\x88','\xae'},{'\x88','\xaf'},{'\x88','\xb0'}, + {'\x88','\xb1'},{'\x88','\xb2'},{'\x88','\xb3'},{'\x88','\xb4'},{'\x88','\xb5'}, + {'\x88','\xb6'},{'\x88','\xb7'},{'\x88','\xb8'},{'\x88','\xb9'},{'\x88','\xba'}, + {'\x88','\xbb'},{'\x88','\xbc'},{'\x88','\xbd'},{'\x88','\xbe'},{'\x88','\xbf'}, + {'\x88','\xc0'},{'\x88','\xc1'},{'\x88','\xc2'},{'\x88','\xc3'},{'\x88','\xc4'}, + {'\x88','\xc5'},{'\x88','\xc6'},{'\x88','\xc7'},{'\x88','\xc8'},{'\x88','\xc9'}, + {'\x88','\xca'},{'\x88','\xcb'},{'\x88','\xcc'},{'\x88','\xcd'},{'\x88','\xce'}, + {'\x88','\xcf'},{'\x88','\xd0'},{'\x88','\xd1'},{'\x88','\xd2'},{'\x88','\xd3'}, + {'\x88','\xd4'},{'\x88','\xd5'},{'\x88','\xd6'},{'\x88','\xd7'},{'\x88','\xd8'}, + {'\x88','\xd9'},{'\x88','\xda'},{'\x88','\xdb'},{'\x88','\xdc'},{'\x88','\xdd'}, + {'\x88','\xde'},{'\x88','\xdf'},{'\x88','\xe0'},{'\x88','\xe1'},{'\x88','\xe2'}, + {'\x88','\xe3'},{'\x88','\xe4'},{'\x88','\xe5'},{'\x88','\xe6'},{'\x88','\xe7'}, + {'\x88','\xe8'},{'\x88','\xe9'},{'\x88','\xea'},{'\x88','\xeb'},{'\x88','\xec'}, + {'\x88','\xed'},{'\x88','\xee'},{'\x88','\xef'},{'\x88','\xf0'},{'\x88','\xf1'}, + {'\x88','\xf2'},{'\x88','\xf3'},{'\x88','\xf4'},{'\x88','\xf5'},{'\x88','\xf6'}, + {'\x88','\xf7'},{'\x88','\xf8'},{'\x88','\xf9'},{'\x88','\xfa'},{'\x88','\xfb'}, + {'\x88','\xfc'},{'\x88','\xfd'},{'\x88','\xfe'},{'\x89','\x40'},{'\x89','\x41'}, + {'\x89','\x42'},{'\x89','\x43'},{'\x89','\x44'},{'\x89','\x45'},{'\x89','\x46'}, + {'\x89','\x47'},{'\x89','\x48'},{'\x89','\x49'},{'\x89','\x4a'},{'\x89','\x4b'}, + {'\x89','\x4c'},{'\x89','\x4d'},{'\x89','\x4e'},{'\x89','\x4f'},{'\x89','\x50'}, + {'\x89','\x51'},{'\x89','\x52'},{'\x89','\x53'},{'\x89','\x54'},{'\x89','\x55'}, + {'\x89','\x56'},{'\x89','\x57'},{'\x89','\x58'},{'\x89','\x59'},{'\x89','\x5a'}, + {'\x89','\x5b'},{'\x89','\x5c'},{'\x89','\x5d'},{'\x89','\x5e'},{'\x89','\x5f'}, + {'\x89','\x60'},{'\x89','\x61'},{'\x89','\x62'},{'\x89','\x63'},{'\x89','\x64'}, + {'\x89','\x65'},{'\x89','\x66'},{'\x89','\x67'},{'\x89','\x68'},{'\x89','\x69'}, + {'\x89','\x6a'},{'\x89','\x6b'},{'\x89','\x6c'},{'\x89','\x6d'},{'\x89','\x6e'}, + {'\x89','\x6f'},{'\x89','\x70'},{'\x89','\x71'},{'\x89','\x72'},{'\x89','\x73'}, + {'\x89','\x74'},{'\x89','\x75'},{'\x89','\x76'},{'\x89','\x77'},{'\x89','\x78'}, + {'\x89','\x79'},{'\x89','\x7a'},{'\x89','\x7b'},{'\x89','\x7c'},{'\x89','\x7d'}, + {'\x89','\x7e'},{'\x89','\xa1'},{'\x89','\xa2'},{'\x89','\xa3'},{'\x89','\xa4'}, + {'\x89','\xa5'},{'\x89','\xa6'},{'\x89','\xa7'},{'\x89','\xa8'},{'\x89','\xa9'}, + {'\x89','\xaa'},{'\x89','\xab'},{'\x89','\xac'},{'\x89','\xad'},{'\x89','\xae'}, + {'\x89','\xaf'},{'\x89','\xb0'},{'\x89','\xb1'},{'\x89','\xb2'},{'\x89','\xb3'}, + {'\x89','\xb4'},{'\x89','\xb5'},{'\x89','\xb6'},{'\x89','\xb7'},{'\x89','\xb8'}, + {'\x89','\xb9'},{'\x89','\xba'},{'\x89','\xbb'},{'\x89','\xbc'},{'\x89','\xbd'}, + {'\x89','\xbe'},{'\x89','\xbf'},{'\x89','\xc0'},{'\x89','\xc1'},{'\x89','\xc2'}, + {'\x89','\xc3'},{'\x89','\xc4'},{'\x89','\xc5'},{'\x89','\xc6'},{'\x89','\xc7'}, + {'\x89','\xc8'},{'\x89','\xc9'},{'\x89','\xca'},{'\x89','\xcb'},{'\x89','\xcc'}, + {'\x89','\xcd'},{'\x89','\xce'},{'\x89','\xcf'},{'\x89','\xd0'},{'\x89','\xd1'}, + {'\x89','\xd2'},{'\x89','\xd3'},{'\x89','\xd4'},{'\x89','\xd5'},{'\x89','\xd6'}, + {'\x89','\xd7'},{'\x89','\xd8'},{'\x89','\xd9'},{'\x89','\xda'},{'\x89','\xdb'}, + {'\x89','\xdc'},{'\x89','\xdd'},{'\x89','\xde'},{'\x89','\xdf'},{'\x89','\xe0'}, + {'\x89','\xe1'},{'\x89','\xe2'},{'\x89','\xe3'},{'\x89','\xe4'},{'\x89','\xe5'}, + {'\x89','\xe6'},{'\x89','\xe7'},{'\x89','\xe8'},{'\x89','\xe9'},{'\x89','\xea'}, + {'\x89','\xeb'},{'\x89','\xec'},{'\x89','\xed'},{'\x89','\xee'},{'\x89','\xef'}, + {'\x89','\xf0'},{'\x89','\xf1'},{'\x89','\xf2'},{'\x89','\xf3'},{'\x89','\xf4'}, + {'\x89','\xf5'},{'\x89','\xf6'},{'\x89','\xf7'},{'\x89','\xf8'},{'\x89','\xf9'}, + {'\x89','\xfa'},{'\x89','\xfb'},{'\x89','\xfc'},{'\x89','\xfd'},{'\x89','\xfe'}, + {'\x8a','\x40'},{'\x8a','\x41'},{'\x8a','\x42'},{'\x8a','\x43'},{'\x8a','\x44'}, + {'\x8a','\x45'},{'\x8a','\x46'},{'\x8a','\x47'},{'\x8a','\x48'},{'\x8a','\x49'}, + {'\x8a','\x4a'},{'\x8a','\x4b'},{'\x8a','\x4c'},{'\x8a','\x4d'},{'\x8a','\x4e'}, + {'\x8a','\x4f'},{'\x8a','\x50'},{'\x8a','\x51'},{'\x8a','\x52'},{'\x8a','\x53'}, + {'\x8a','\x54'},{'\x8a','\x55'},{'\x8a','\x56'},{'\x8a','\x57'},{'\x8a','\x58'}, + {'\x8a','\x59'},{'\x8a','\x5a'},{'\x8a','\x5b'},{'\x8a','\x5c'},{'\x8a','\x5d'}, + {'\x8a','\x5e'},{'\x8a','\x5f'},{'\x8a','\x60'},{'\x8a','\x61'},{'\x8a','\x62'}, + {'\x8a','\x63'},{'\x8a','\x64'},{'\x8a','\x65'},{'\x8a','\x66'},{'\x8a','\x67'}, + {'\x8a','\x68'},{'\x8a','\x69'},{'\x8a','\x6a'},{'\x8a','\x6b'},{'\x8a','\x6c'}, + {'\x8a','\x6d'},{'\x8a','\x6e'},{'\x8a','\x6f'},{'\x8a','\x70'},{'\x8a','\x71'}, + {'\x8a','\x72'},{'\x8a','\x73'},{'\x8a','\x74'},{'\x8a','\x75'},{'\x8a','\x76'}, + {'\x8a','\x77'},{'\x8a','\x78'},{'\x8a','\x79'},{'\x8a','\x7a'},{'\x8a','\x7b'}, + {'\x8a','\x7c'},{'\x8a','\x7d'},{'\x8a','\x7e'},{'\x8a','\xa1'},{'\x8a','\xa2'}, + {'\x8a','\xa3'},{'\x8a','\xa4'},{'\x8a','\xa5'},{'\x8a','\xa6'},{'\x8a','\xa7'}, + {'\x8a','\xa8'},{'\x8a','\xa9'},{'\x8a','\xaa'},{'\x8a','\xab'},{'\x8a','\xac'}, + {'\x8a','\xad'},{'\x8a','\xae'},{'\x8a','\xaf'},{'\x8a','\xb0'},{'\x8a','\xb1'}, + {'\x8a','\xb2'},{'\x8a','\xb3'},{'\x8a','\xb4'},{'\x8a','\xb5'},{'\x8a','\xb6'}, + {'\x8a','\xb7'},{'\x8a','\xb8'},{'\x8a','\xb9'},{'\x8a','\xba'},{'\x8a','\xbb'}, + {'\x8a','\xbc'},{'\x8a','\xbd'},{'\x8a','\xbe'},{'\x8a','\xbf'},{'\x8a','\xc0'}, + {'\x8a','\xc1'},{'\x8a','\xc2'},{'\x8a','\xc3'},{'\x8a','\xc4'},{'\x8a','\xc5'}, + {'\x8a','\xc6'},{'\x8a','\xc7'},{'\x8a','\xc8'},{'\x8a','\xc9'},{'\x8a','\xca'}, + {'\x8a','\xcb'},{'\x8a','\xcc'},{'\x8a','\xcd'},{'\x8a','\xce'},{'\x8a','\xcf'}, + {'\x8a','\xd0'},{'\x8a','\xd1'},{'\x8a','\xd2'},{'\x8a','\xd3'},{'\x8a','\xd4'}, + {'\x8a','\xd5'},{'\x8a','\xd6'},{'\x8a','\xd7'},{'\x8a','\xd8'},{'\x8a','\xd9'}, + {'\x8a','\xda'},{'\x8a','\xdb'},{'\x8a','\xdc'},{'\x8a','\xdd'},{'\x8a','\xde'}, + {'\x8a','\xdf'},{'\x8a','\xe0'},{'\x8a','\xe1'},{'\x8a','\xe2'},{'\x8a','\xe3'}, + {'\x8a','\xe4'},{'\x8a','\xe5'},{'\x8a','\xe6'},{'\x8a','\xe7'},{'\x8a','\xe8'}, + {'\x8a','\xe9'},{'\x8a','\xea'},{'\x8a','\xeb'},{'\x8a','\xec'},{'\x8a','\xed'}, + {'\x8a','\xee'},{'\x8a','\xef'},{'\x8a','\xf0'},{'\x8a','\xf1'},{'\x8a','\xf2'}, + {'\x8a','\xf3'},{'\x8a','\xf4'},{'\x8a','\xf5'},{'\x8a','\xf6'},{'\x8a','\xf7'}, + {'\x8a','\xf8'},{'\x8a','\xf9'},{'\x8a','\xfa'},{'\x8a','\xfb'},{'\x8a','\xfc'}, + {'\x8a','\xfd'},{'\x8a','\xfe'},{'\x8b','\x40'},{'\x8b','\x41'},{'\x8b','\x42'}, + {'\x8b','\x43'},{'\x8b','\x44'},{'\x8b','\x45'},{'\x8b','\x46'},{'\x8b','\x47'}, + {'\x8b','\x48'},{'\x8b','\x49'},{'\x8b','\x4a'},{'\x8b','\x4b'},{'\x8b','\x4c'}, + {'\x8b','\x4d'},{'\x8b','\x4e'},{'\x8b','\x4f'},{'\x8b','\x50'},{'\x8b','\x51'}, + {'\x8b','\x52'},{'\x8b','\x53'},{'\x8b','\x54'},{'\x8b','\x55'},{'\x8b','\x56'}, + {'\x8b','\x57'},{'\x8b','\x58'},{'\x8b','\x59'},{'\x8b','\x5a'},{'\x8b','\x5b'}, + {'\x8b','\x5c'},{'\x8b','\x5d'},{'\x8b','\x5e'},{'\x8b','\x5f'},{'\x8b','\x60'}, + {'\x8b','\x61'},{'\x8b','\x62'},{'\x8b','\x63'},{'\x8b','\x64'},{'\x8b','\x65'}, + {'\x8b','\x66'},{'\x8b','\x67'},{'\x8b','\x68'},{'\x8b','\x69'},{'\x8b','\x6a'}, + {'\x8b','\x6b'},{'\x8b','\x6c'},{'\x8b','\x6d'},{'\x8b','\x6e'},{'\x8b','\x6f'}, + {'\x8b','\x70'},{'\x8b','\x71'},{'\x8b','\x72'},{'\x8b','\x73'},{'\x8b','\x74'}, + {'\x8b','\x75'},{'\x8b','\x76'},{'\x8b','\x77'},{'\x8b','\x78'},{'\x8b','\x79'}, + {'\x8b','\x7a'},{'\x8b','\x7b'},{'\x8b','\x7c'},{'\x8b','\x7d'},{'\x8b','\x7e'}, + {'\x8b','\xa1'},{'\x8b','\xa2'},{'\x8b','\xa3'},{'\x8b','\xa4'},{'\x8b','\xa5'}, + {'\x8b','\xa6'},{'\x8b','\xa7'},{'\x8b','\xa8'},{'\x8b','\xa9'},{'\x8b','\xaa'}, + {'\x8b','\xab'},{'\x8b','\xac'},{'\x8b','\xad'},{'\x8b','\xae'},{'\x8b','\xaf'}, + {'\x8b','\xb0'},{'\x8b','\xb1'},{'\x8b','\xb2'},{'\x8b','\xb3'},{'\x8b','\xb4'}, + {'\x8b','\xb5'},{'\x8b','\xb6'},{'\x8b','\xb7'},{'\x8b','\xb8'},{'\x8b','\xb9'}, + {'\x8b','\xba'},{'\x8b','\xbb'},{'\x8b','\xbc'},{'\x8b','\xbd'},{'\x8b','\xbe'}, + {'\x8b','\xbf'},{'\x8b','\xc0'},{'\x8b','\xc1'},{'\x8b','\xc2'},{'\x8b','\xc3'}, + {'\x8b','\xc4'},{'\x8b','\xc5'},{'\x8b','\xc6'},{'\x8b','\xc7'},{'\x8b','\xc8'}, + {'\x8b','\xc9'},{'\x8b','\xca'},{'\x8b','\xcb'},{'\x8b','\xcc'},{'\x8b','\xcd'}, + {'\x8b','\xce'},{'\x8b','\xcf'},{'\x8b','\xd0'},{'\x8b','\xd1'},{'\x8b','\xd2'}, + {'\x8b','\xd3'},{'\x8b','\xd4'},{'\x8b','\xd5'},{'\x8b','\xd6'},{'\x8b','\xd7'}, + {'\x8b','\xd8'},{'\x8b','\xd9'},{'\x8b','\xda'},{'\x8b','\xdb'},{'\x8b','\xdc'}, + {'\x8b','\xdd'},{'\x8b','\xde'},{'\x8b','\xdf'},{'\x8b','\xe0'},{'\x8b','\xe1'}, + {'\x8b','\xe2'},{'\x8b','\xe3'},{'\x8b','\xe4'},{'\x8b','\xe5'},{'\x8b','\xe6'}, + {'\x8b','\xe7'},{'\x8b','\xe8'},{'\x8b','\xe9'},{'\x8b','\xea'},{'\x8b','\xeb'}, + {'\x8b','\xec'},{'\x8b','\xed'},{'\x8b','\xee'},{'\x8b','\xef'},{'\x8b','\xf0'}, + {'\x8b','\xf1'},{'\x8b','\xf2'},{'\x8b','\xf3'},{'\x8b','\xf4'},{'\x8b','\xf5'}, + {'\x8b','\xf6'},{'\x8b','\xf7'},{'\x8b','\xf8'},{'\x8b','\xf9'},{'\x8b','\xfa'}, + {'\x8b','\xfb'},{'\x8b','\xfc'},{'\x8b','\xfd'},{'\x8b','\xfe'},{'\x8c','\x40'}, + {'\x8c','\x41'},{'\x8c','\x42'},{'\x8c','\x43'},{'\x8c','\x44'},{'\x8c','\x45'}, + {'\x8c','\x46'},{'\x8c','\x47'},{'\x8c','\x48'},{'\x8c','\x49'},{'\x8c','\x4a'}, + {'\x8c','\x4b'},{'\x8c','\x4c'},{'\x8c','\x4d'},{'\x8c','\x4e'},{'\x8c','\x4f'}, + {'\x8c','\x50'},{'\x8c','\x51'},{'\x8c','\x52'},{'\x8c','\x53'},{'\x8c','\x54'}, + {'\x8c','\x55'},{'\x8c','\x56'},{'\x8c','\x57'},{'\x8c','\x58'},{'\x8c','\x59'}, + {'\x8c','\x5a'},{'\x8c','\x5b'},{'\x8c','\x5c'},{'\x8c','\x5d'},{'\x8c','\x5e'}, + {'\x8c','\x5f'},{'\x8c','\x60'},{'\x8c','\x61'},{'\x8c','\x62'},{'\x8c','\x63'}, + {'\x8c','\x64'},{'\x8c','\x65'},{'\x8c','\x66'},{'\x8c','\x67'},{'\x8c','\x68'}, + {'\x8c','\x69'},{'\x8c','\x6a'},{'\x8c','\x6b'},{'\x8c','\x6c'},{'\x8c','\x6d'}, + {'\x8c','\x6e'},{'\x8c','\x6f'},{'\x8c','\x70'},{'\x8c','\x71'},{'\x8c','\x72'}, + {'\x8c','\x73'},{'\x8c','\x74'},{'\x8c','\x75'},{'\x8c','\x76'},{'\x8c','\x77'}, + {'\x8c','\x78'},{'\x8c','\x79'},{'\x8c','\x7a'},{'\x8c','\x7b'},{'\x8c','\x7c'}, + {'\x8c','\x7d'},{'\x8c','\x7e'},{'\x8c','\xa1'},{'\x8c','\xa2'},{'\x8c','\xa3'}, + {'\x8c','\xa4'},{'\x8c','\xa5'},{'\x8c','\xa6'},{'\x8c','\xa7'},{'\x8c','\xa8'}, + {'\x8c','\xa9'},{'\x8c','\xaa'},{'\x8c','\xab'},{'\x8c','\xac'},{'\x8c','\xad'}, + {'\x8c','\xae'},{'\x8c','\xaf'},{'\x8c','\xb0'},{'\x8c','\xb1'},{'\x8c','\xb2'}, + {'\x8c','\xb3'},{'\x8c','\xb4'},{'\x8c','\xb5'},{'\x8c','\xb6'},{'\x8c','\xb7'}, + {'\x8c','\xb8'},{'\x8c','\xb9'},{'\x8c','\xba'},{'\x8c','\xbb'},{'\x8c','\xbc'}, + {'\x8c','\xbd'},{'\x8c','\xbe'},{'\x8c','\xbf'},{'\x8c','\xc0'},{'\x8c','\xc1'}, + {'\x8c','\xc2'},{'\x8c','\xc3'},{'\x8c','\xc4'},{'\x8c','\xc5'},{'\x8c','\xc6'}, + {'\x8c','\xc7'},{'\x8c','\xc8'},{'\x8c','\xc9'},{'\x8c','\xca'},{'\x8c','\xcb'}, + {'\x8c','\xcc'},{'\x8c','\xcd'},{'\x8c','\xce'},{'\x8c','\xcf'},{'\x8c','\xd0'}, + {'\x8c','\xd1'},{'\x8c','\xd2'},{'\x8c','\xd3'},{'\x8c','\xd4'},{'\x8c','\xd5'}, + {'\x8c','\xd6'},{'\x8c','\xd7'},{'\x8c','\xd8'},{'\x8c','\xd9'},{'\x8c','\xda'}, + {'\x8c','\xdb'},{'\x8c','\xdc'},{'\x8c','\xdd'},{'\x8c','\xde'},{'\x8c','\xdf'}, + {'\x8c','\xe0'},{'\x8c','\xe1'},{'\x8c','\xe2'},{'\x8c','\xe3'},{'\x8c','\xe4'}, + {'\x8c','\xe5'},{'\x8c','\xe6'},{'\x8c','\xe7'},{'\x8c','\xe8'},{'\x8c','\xe9'}, + {'\x8c','\xea'},{'\x8c','\xeb'},{'\x8c','\xec'},{'\x8c','\xed'},{'\x8c','\xee'}, + {'\x8c','\xef'},{'\x8c','\xf0'},{'\x8c','\xf1'},{'\x8c','\xf2'},{'\x8c','\xf3'}, + {'\x8c','\xf4'},{'\x8c','\xf5'},{'\x8c','\xf6'},{'\x8c','\xf7'},{'\x8c','\xf8'}, + {'\x8c','\xf9'},{'\x8c','\xfa'},{'\x8c','\xfb'},{'\x8c','\xfc'},{'\x8c','\xfd'}, + {'\x8c','\xfe'},{'\x8d','\x40'},{'\x8d','\x41'},{'\x8d','\x42'},{'\x8d','\x43'}, + {'\x8d','\x44'},{'\x8d','\x45'},{'\x8d','\x46'},{'\x8d','\x47'},{'\x8d','\x48'}, + {'\x8d','\x49'},{'\x8d','\x4a'},{'\x8d','\x4b'},{'\x8d','\x4c'},{'\x8d','\x4d'}, + {'\x8d','\x4e'},{'\x8d','\x4f'},{'\x8d','\x50'},{'\x8d','\x51'},{'\x8d','\x52'}, + {'\x8d','\x53'},{'\x8d','\x54'},{'\x8d','\x55'},{'\x8d','\x56'},{'\x8d','\x57'}, + {'\x8d','\x58'},{'\x8d','\x59'},{'\x8d','\x5a'},{'\x8d','\x5b'},{'\x8d','\x5c'}, + {'\x8d','\x5d'},{'\x8d','\x5e'},{'\x8d','\x5f'},{'\x8d','\x60'},{'\x8d','\x61'}, + {'\x8d','\x62'},{'\x8d','\x63'},{'\x8d','\x64'},{'\x8d','\x65'},{'\x8d','\x66'}, + {'\x8d','\x67'},{'\x8d','\x68'},{'\x8d','\x69'},{'\x8d','\x6a'},{'\x8d','\x6b'}, + {'\x8d','\x6c'},{'\x8d','\x6d'},{'\x8d','\x6e'},{'\x8d','\x6f'},{'\x8d','\x70'}, + {'\x8d','\x71'},{'\x8d','\x72'},{'\x8d','\x73'},{'\x8d','\x74'},{'\x8d','\x75'}, + {'\x8d','\x76'},{'\x8d','\x77'},{'\x8d','\x78'},{'\x8d','\x79'},{'\x8d','\x7a'}, + {'\x8d','\x7b'},{'\x8d','\x7c'},{'\x8d','\x7d'},{'\x8d','\x7e'},{'\x8d','\xa1'}, + {'\x8d','\xa2'},{'\x8d','\xa3'},{'\x8d','\xa4'},{'\x8d','\xa5'},{'\x8d','\xa6'}, + {'\x8d','\xa7'},{'\x8d','\xa8'},{'\x8d','\xa9'},{'\x8d','\xaa'},{'\x8d','\xab'}, + {'\x8d','\xac'},{'\x8d','\xad'},{'\x8d','\xae'},{'\x8d','\xaf'},{'\x8d','\xb0'}, + {'\x8d','\xb1'},{'\x8d','\xb2'},{'\x8d','\xb3'},{'\x8d','\xb4'},{'\x8d','\xb5'}, + {'\x8d','\xb6'},{'\x8d','\xb7'},{'\x8d','\xb8'},{'\x8d','\xb9'},{'\x8d','\xba'}, + {'\x8d','\xbb'},{'\x8d','\xbc'},{'\x8d','\xbd'},{'\x8d','\xbe'},{'\x8d','\xbf'}, + {'\x8d','\xc0'},{'\x8d','\xc1'},{'\x8d','\xc2'},{'\x8d','\xc3'},{'\x8d','\xc4'}, + {'\x8d','\xc5'},{'\x8d','\xc6'},{'\x8d','\xc7'},{'\x8d','\xc8'},{'\x8d','\xc9'}, + {'\x8d','\xca'},{'\x8d','\xcb'},{'\x8d','\xcc'},{'\x8d','\xcd'},{'\x8d','\xce'}, + {'\x8d','\xcf'},{'\x8d','\xd0'},{'\x8d','\xd1'},{'\x8d','\xd2'},{'\x8d','\xd3'}, + {'\x8d','\xd4'},{'\x8d','\xd5'},{'\x8d','\xd6'},{'\x8d','\xd7'},{'\x8d','\xd8'}, + {'\x8d','\xd9'},{'\x8d','\xda'},{'\x8d','\xdb'},{'\x8d','\xdc'},{'\x8d','\xdd'}, + {'\x8d','\xde'},{'\x8d','\xdf'},{'\x8d','\xe0'},{'\x8d','\xe1'},{'\x8d','\xe2'}, + {'\x8d','\xe3'},{'\x8d','\xe4'},{'\x8d','\xe5'},{'\x8d','\xe6'},{'\x8d','\xe7'}, + {'\x8d','\xe8'},{'\x8d','\xe9'},{'\x8d','\xea'},{'\x8d','\xeb'},{'\x8d','\xec'}, + {'\x8d','\xed'},{'\x8d','\xee'},{'\x8d','\xef'},{'\x8d','\xf0'},{'\x8d','\xf1'}, + {'\x8d','\xf2'},{'\x8d','\xf3'},{'\x8d','\xf4'},{'\x8d','\xf5'},{'\x8d','\xf6'}, + {'\x8d','\xf7'},{'\x8d','\xf8'},{'\x8d','\xf9'},{'\x8d','\xfa'},{'\x8d','\xfb'}, + {'\x8d','\xfc'},{'\x8d','\xfd'},{'\x8d','\xfe'},{'\xc6','\xa1'},{'\xc6','\xa2'}, + {'\xc6','\xa3'},{'\xc6','\xa4'},{'\xc6','\xa5'},{'\xc6','\xa6'},{'\xc6','\xa7'}, + {'\xc6','\xa8'},{'\xc6','\xa9'},{'\xc6','\xaa'},{'\xc6','\xab'},{'\xc6','\xac'}, + {'\xc6','\xad'},{'\xc6','\xae'},{'\xc6','\xaf'},{'\xc6','\xb0'},{'\xc6','\xb1'}, + {'\xc6','\xb2'},{'\xc6','\xb3'},{'\xc6','\xb4'},{'\xc6','\xb5'},{'\xc6','\xb6'}, + {'\xc6','\xb7'},{'\xc6','\xb8'},{'\xc6','\xb9'},{'\xc6','\xba'},{'\xc6','\xbb'}, + {'\xc6','\xbc'},{'\xc6','\xbd'},{'\xc6','\xbe'},{'\xc6','\xbf'},{'\xc6','\xc0'}, + {'\xc6','\xc1'},{'\xc6','\xc2'},{'\xc6','\xc3'},{'\xc6','\xc4'},{'\xc6','\xc5'}, + {'\xc6','\xc6'},{'\xc6','\xc7'},{'\xc6','\xc8'},{'\xc6','\xc9'},{'\xc6','\xca'}, + {'\xc6','\xcb'},{'\xc6','\xcc'},{'\xc6','\xcd'},{'\xc6','\xce'},{'\xc6','\xcf'}, + {'\xc6','\xd0'},{'\xc6','\xd1'},{'\xc6','\xd2'},{'\xc6','\xd3'},{'\xc6','\xd4'}, + {'\xc6','\xd5'},{'\xc6','\xd6'},{'\xc6','\xd7'},{'\xc6','\xd8'},{'\xc6','\xd9'}, + {'\xc6','\xda'},{'\xc6','\xdb'},{'\xc6','\xdc'},{'\xc6','\xdd'},{'\xc6','\xde'}, + {'\xc6','\xdf'},{'\xc6','\xe0'},{'\xc6','\xe1'},{'\xc6','\xe2'},{'\xc6','\xe3'}, + {'\xc6','\xe4'},{'\xc6','\xe5'},{'\xc6','\xe6'},{'\xc6','\xe7'},{'\xc6','\xe8'}, + {'\xc6','\xe9'},{'\xc6','\xea'},{'\xc6','\xeb'},{'\xc6','\xec'},{'\xc6','\xed'}, + {'\xc6','\xee'},{'\xc6','\xef'},{'\xc6','\xf0'},{'\xc6','\xf1'},{'\xc6','\xf2'}, + {'\xc6','\xf3'},{'\xc6','\xf4'},{'\xc6','\xf5'},{'\xc6','\xf6'},{'\xc6','\xf7'}, + {'\xc6','\xf8'},{'\xc6','\xf9'},{'\xc6','\xfa'},{'\xc6','\xfb'},{'\xc6','\xfc'}, + {'\xc6','\xfd'},{'\xc6','\xfe'},{'\xc7','\x40'},{'\xc7','\x41'},{'\xc7','\x42'}, + {'\xc7','\x43'},{'\xc7','\x44'},{'\xc7','\x45'},{'\xc7','\x46'},{'\xc7','\x47'}, + {'\xc7','\x48'},{'\xc7','\x49'},{'\xc7','\x4a'},{'\xc7','\x4b'},{'\xc7','\x4c'}, + {'\xc7','\x4d'},{'\xc7','\x4e'},{'\xc7','\x4f'},{'\xc7','\x50'},{'\xc7','\x51'}, + {'\xc7','\x52'},{'\xc7','\x53'},{'\xc7','\x54'},{'\xc7','\x55'},{'\xc7','\x56'}, + {'\xc7','\x57'},{'\xc7','\x58'},{'\xc7','\x59'},{'\xc7','\x5a'},{'\xc7','\x5b'}, + {'\xc7','\x5c'},{'\xc7','\x5d'},{'\xc7','\x5e'},{'\xc7','\x5f'},{'\xc7','\x60'}, + {'\xc7','\x61'},{'\xc7','\x62'},{'\xc7','\x63'},{'\xc7','\x64'},{'\xc7','\x65'}, + {'\xc7','\x66'},{'\xc7','\x67'},{'\xc7','\x68'},{'\xc7','\x69'},{'\xc7','\x6a'}, + {'\xc7','\x6b'},{'\xc7','\x6c'},{'\xc7','\x6d'},{'\xc7','\x6e'},{'\xc7','\x6f'}, + {'\xc7','\x70'},{'\xc7','\x71'},{'\xc7','\x72'},{'\xc7','\x73'},{'\xc7','\x74'}, + {'\xc7','\x75'},{'\xc7','\x76'},{'\xc7','\x77'},{'\xc7','\x78'},{'\xc7','\x79'}, + {'\xc7','\x7a'},{'\xc7','\x7b'},{'\xc7','\x7c'},{'\xc7','\x7d'},{'\xc7','\x7e'}, + {'\xc7','\xa1'},{'\xc7','\xa2'},{'\xc7','\xa3'},{'\xc7','\xa4'},{'\xc7','\xa5'}, + {'\xc7','\xa6'},{'\xc7','\xa7'},{'\xc7','\xa8'},{'\xc7','\xa9'},{'\xc7','\xaa'}, + {'\xc7','\xab'},{'\xc7','\xac'},{'\xc7','\xad'},{'\xc7','\xae'},{'\xc7','\xaf'}, + {'\xc7','\xb0'},{'\xc7','\xb1'},{'\xc7','\xb2'},{'\xc7','\xb3'},{'\xc7','\xb4'}, + {'\xc7','\xb5'},{'\xc7','\xb6'},{'\xc7','\xb7'},{'\xc7','\xb8'},{'\xc7','\xb9'}, + {'\xc7','\xba'},{'\xc7','\xbb'},{'\xc7','\xbc'},{'\xc7','\xbd'},{'\xc7','\xbe'}, + {'\xc7','\xbf'},{'\xc7','\xc0'},{'\xc7','\xc1'},{'\xc7','\xc2'},{'\xc7','\xc3'}, + {'\xc7','\xc4'},{'\xc7','\xc5'},{'\xc7','\xc6'},{'\xc7','\xc7'},{'\xc7','\xc8'}, + {'\xc7','\xc9'},{'\xc7','\xca'},{'\xc7','\xcb'},{'\xc7','\xcc'},{'\xc7','\xcd'}, + {'\xc7','\xce'},{'\xc7','\xcf'},{'\xc7','\xd0'},{'\xc7','\xd1'},{'\xc7','\xd2'}, + {'\xc7','\xd3'},{'\xc7','\xd4'},{'\xc7','\xd5'},{'\xc7','\xd6'},{'\xc7','\xd7'}, + {'\xc7','\xd8'},{'\xc7','\xd9'},{'\xc7','\xda'},{'\xc7','\xdb'},{'\xc7','\xdc'}, + {'\xc7','\xdd'},{'\xc7','\xde'},{'\xc7','\xdf'},{'\xc7','\xe0'},{'\xc7','\xe1'}, + {'\xc7','\xe2'},{'\xc7','\xe3'},{'\xc7','\xe4'},{'\xc7','\xe5'},{'\xc7','\xe6'}, + {'\xc7','\xe7'},{'\xc7','\xe8'},{'\xc7','\xe9'},{'\xc7','\xea'},{'\xc7','\xeb'}, + {'\xc7','\xec'},{'\xc7','\xed'},{'\xc7','\xee'},{'\xc7','\xef'},{'\xc7','\xf0'}, + {'\xc7','\xf1'},{'\xc7','\xf2'},{'\xc7','\xf3'},{'\xc7','\xf4'},{'\xc7','\xf5'}, + {'\xc7','\xf6'},{'\xc7','\xf7'},{'\xc7','\xf8'},{'\xc7','\xf9'},{'\xc7','\xfa'}, + {'\xc7','\xfb'},{'\xc7','\xfc'},{'\xc7','\xfd'},{'\xc7','\xfe'},{'\xc8','\x40'}, + {'\xc8','\x41'},{'\xc8','\x42'},{'\xc8','\x43'},{'\xc8','\x44'},{'\xc8','\x45'}, + {'\xc8','\x46'},{'\xc8','\x47'},{'\xc8','\x48'},{'\xc8','\x49'},{'\xc8','\x4a'}, + {'\xc8','\x4b'},{'\xc8','\x4c'},{'\xc8','\x4d'},{'\xc8','\x4e'},{'\xc8','\x4f'}, + {'\xc8','\x50'},{'\xc8','\x51'},{'\xc8','\x52'},{'\xc8','\x53'},{'\xc8','\x54'}, + {'\xc8','\x55'},{'\xc8','\x56'},{'\xc8','\x57'},{'\xc8','\x58'},{'\xc8','\x59'}, + {'\xc8','\x5a'},{'\xc8','\x5b'},{'\xc8','\x5c'},{'\xc8','\x5d'},{'\xc8','\x5e'}, + {'\xc8','\x5f'},{'\xc8','\x60'},{'\xc8','\x61'},{'\xc8','\x62'},{'\xc8','\x63'}, + {'\xc8','\x64'},{'\xc8','\x65'},{'\xc8','\x66'},{'\xc8','\x67'},{'\xc8','\x68'}, + {'\xc8','\x69'},{'\xc8','\x6a'},{'\xc8','\x6b'},{'\xc8','\x6c'},{'\xc8','\x6d'}, + {'\xc8','\x6e'},{'\xc8','\x6f'},{'\xc8','\x70'},{'\xc8','\x71'},{'\xc8','\x72'}, + {'\xc8','\x73'},{'\xc8','\x74'},{'\xc8','\x75'},{'\xc8','\x76'},{'\xc8','\x77'}, + {'\xc8','\x78'},{'\xc8','\x79'},{'\xc8','\x7a'},{'\xc8','\x7b'},{'\xc8','\x7c'}, + {'\xc8','\x7d'},{'\xc8','\x7e'},{'\xc8','\xa1'},{'\xc8','\xa2'},{'\xc8','\xa3'}, + {'\xc8','\xa4'},{'\xc8','\xa5'},{'\xc8','\xa6'},{'\xc8','\xa7'},{'\xc8','\xa8'}, + {'\xc8','\xa9'},{'\xc8','\xaa'},{'\xc8','\xab'},{'\xc8','\xac'},{'\xc8','\xad'}, + {'\xc8','\xae'},{'\xc8','\xaf'},{'\xc8','\xb0'},{'\xc8','\xb1'},{'\xc8','\xb2'}, + {'\xc8','\xb3'},{'\xc8','\xb4'},{'\xc8','\xb5'},{'\xc8','\xb6'},{'\xc8','\xb7'}, + {'\xc8','\xb8'},{'\xc8','\xb9'},{'\xc8','\xba'},{'\xc8','\xbb'},{'\xc8','\xbc'}, + {'\xc8','\xbd'},{'\xc8','\xbe'},{'\xc8','\xbf'},{'\xc8','\xc0'},{'\xc8','\xc1'}, + {'\xc8','\xc2'},{'\xc8','\xc3'},{'\xc8','\xc4'},{'\xc8','\xc5'},{'\xc8','\xc6'}, + {'\xc8','\xc7'},{'\xc8','\xc8'},{'\xc8','\xc9'},{'\xc8','\xca'},{'\xc8','\xcb'}, + {'\xc8','\xcc'},{'\xc8','\xcd'},{'\xc8','\xce'},{'\xc8','\xcf'},{'\xc8','\xd0'}, + {'\xc8','\xd1'},{'\xc8','\xd2'},{'\xc8','\xd3'},{'\xc8','\xd4'},{'\xc8','\xd5'}, + {'\xc8','\xd6'},{'\xc8','\xd7'},{'\xc8','\xd8'},{'\xc8','\xd9'},{'\xc8','\xda'}, + {'\xc8','\xdb'},{'\xc8','\xdc'},{'\xc8','\xdd'},{'\xc8','\xde'},{'\xc8','\xdf'}, + {'\xc8','\xe0'},{'\xc8','\xe1'},{'\xc8','\xe2'},{'\xc8','\xe3'},{'\xc8','\xe4'}, + {'\xc8','\xe5'},{'\xc8','\xe6'},{'\xc8','\xe7'},{'\xc8','\xe8'},{'\xc8','\xe9'}, + {'\xc8','\xea'},{'\xc8','\xeb'},{'\xc8','\xec'},{'\xc8','\xed'},{'\xc8','\xee'}, + {'\xc8','\xef'},{'\xc8','\xf0'},{'\xc8','\xf1'},{'\xc8','\xf2'},{'\xc8','\xf3'}, + {'\xc8','\xf4'},{'\xc8','\xf5'},{'\xc8','\xf6'},{'\xc8','\xf7'},{'\xc8','\xf8'}, + {'\xc8','\xf9'},{'\xc8','\xfa'},{'\xc8','\xfb'},{'\xc8','\xfc'},{'\xc8','\xfd'}, + {'\xc8','\xfe'},{'\xa3','\xe2'},{'\xa3','\xe3'},{'\xa3','\xe4'},{'\xa3','\xe5'}, + {'\xa3','\xe6'},{'\xa3','\xe7'},{'\xa3','\xe8'},{'\xa3','\xe9'},{'\xa3','\xea'}, + {'\xa3','\xeb'},{'\xa3','\xec'},{'\xa3','\xed'},{'\xa3','\xee'},{'\xa3','\xef'}, + {'\xa3','\xf0'},{'\xa3','\xf1'},{'\xa3','\xf2'},{'\xa3','\xf3'},{'\xa3','\xf4'}, + {'\xa3','\xf5'},{'\xa3','\xf6'},{'\xa3','\xf7'},{'\xa3','\xf8'},{'\xa3','\xf9'}, + {'\xa3','\xfa'},{'\xa3','\xfb'},{'\xa3','\xfc'},{'\xa3','\xfd'},{'\xa3','\xfe'}, + {'\xc6','\xde'},{'\xc6','\xdf'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\xff'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xb0','\x5a'}, + {'\xa7','\xf3'},{'\xa8','\xae'},{'\xb8','\xeb'},{'\xb7','\xc6'},{'\xa6','\xea'}, + {'\xa5','\x79'},{'\xc0','\x74'},{'\xc0','\x74'},{'\xab','\xb4'},{'\xaa','\xf7'}, + {'\xb3','\xe2'},{'\xa9','\x60'},{'\xc3','\x69'},{'\xc4','\xee'},{'\xc3','\xb9'}, + {'\xc5','\xda'},{'\xc1','\xb3'},{'\xbb','\x72'},{'\xc5','\xde'},{'\xbc','\xd6'}, + {'\xac','\xa5'},{'\xaf','\x4f'},{'\xaf','\x5f'},{'\xb8','\xa8'},{'\xb9','\x54'}, + {'\xc0','\x64'},{'\xb6','\xc3'},{'\xa7','\x5a'},{'\xc4','\xe6'},{'\xc4','\xea'}, + {'\xc4','\xf5'},{'\xc6','\x7d'},{'\xb4','\x50'},{'\xc0','\xdd'},{'\xc2','\xc5'}, + {'\xc4','\xb0'},{'\xa9','\xd4'},{'\xc3','\xbe'},{'\xc4','\xfa'},{'\xb4','\x59'}, + {'\xae','\xd4'},{'\xae','\xf6'},{'\xaf','\x54'},{'\xad','\xa6'},{'\xa8','\xd3'}, + {'\xa7','\x4e'},{'\xb3','\xd2'},{'\xbe','\xdb'},{'\xc3','\x72'},{'\xc4','\x6c'}, + {'\xbf','\x63'},{'\xa6','\xd1'},{'\xc4','\xaa'},{'\xb8','\xb8'},{'\xb8','\xf4'}, + {'\xc5','\x53'},{'\xbe','\x7c'},{'\xc6','\x4f'},{'\xb8','\x4c'},{'\xb8','\x53'}, + {'\xba','\xf1'},{'\xdb','\x77'},{'\xbf','\xfd'},{'\xb3','\xc0'},{'\xbd','\xd7'}, + {'\xc3','\x62'},{'\xa7','\xcb'},{'\xc5','\xa2'},{'\xc5','\xa4'},{'\xa8','\x63'}, + {'\xbd','\x55'},{'\xb8','\xef'},{'\xb9','\x70'},{'\xc2','\x53'},{'\xb9','\xf0'}, + {'\xbc','\xd3'},{'\xb2','\x5c'},{'\xba','\x7c'},{'\xb2','\xd6'},{'\xc1','\x5c'}, + {'\xad','\xae'},{'\xb0','\xc7'},{'\xa6','\xd8'},{'\xbb','\xfe'},{'\xad','\xe2'}, + {'\xb8','\x57'},{'\xba','\xf0'},{'\xb5','\xd9'},{'\xb3','\xae'},{'\xc5','\xaa'}, + {'\xce','\xd4'},{'\xbc','\xd6'},{'\xbf','\xd5'},{'\xa4','\xa6'},{'\xb9','\xe7'}, + {'\xab','\xe3'},{'\xb2','\x76'},{'\xb2','\xa7'},{'\xa5','\x5f'},{'\xed','\xa8'}, + {'\xab','\x4b'},{'\xb4','\x5f'},{'\xa4','\xa3'},{'\xaa','\x63'},{'\xbc','\xc6'}, + {'\xaf','\xc1'},{'\xb0','\xd1'},{'\xb6','\xeb'},{'\xac','\xd9'},{'\xb8','\xad'}, + {'\xbb','\xa1'},{'\xb1','\xfe'},{'\xa8','\xb0'},{'\xa8','\x48'},{'\xac','\x42'}, + {'\xad','\x59'},{'\xb1','\xb0'},{'\xb2','\xa4'},{'\xab','\x47'},{'\xa8','\xe2'}, + {'\x84','\x5b'},{'\xb1','\xe7'},{'\xc2','\xb3'},{'\xa8','\x7d'},{'\xbd','\xcc'}, + {'\xb6','\x71'},{'\xc0','\x79'},{'\xa7','\x66'},{'\xa4','\x6b'},{'\xc3','\x66'}, + {'\xae','\xc8'},{'\xc2','\x6f'},{'\xc4','\x72'},{'\xbe','\x5b'},{'\xc6','\x7a'}, + {'\xc4','\x52'},{'\xbe','\xa4'},{'\xa4','\x4f'},{'\xbe','\xe4'},{'\xbe','\xfa'}, + {'\xf7','\x65'},{'\xa6','\x7e'},{'\xbc','\xa6'},{'\xc5','\xca'},{'\xbc','\xbf'}, + {'\xba','\xa7'},{'\xb7','\xd2'},{'\xe6','\xa3'},{'\x9d','\xce'},{'\xbd','\x6d'}, + {'\xc1','\x70'},{'\xbd','\xfb'},{'\xbd','\xac'},{'\xb3','\x73'},{'\xc1','\xe5'}, + {'\xa6','\x43'},{'\xa6','\x48'},{'\xab','\x7c'},{'\xaf','\x50'},{'\xb5','\xf5'}, + {'\xbb','\xa1'},{'\xb7','\x47'},{'\xa9','\xc0'},{'\xb1','\xc9'},{'\xc0','\xd4'}, + {'\xc3','\xae'},{'\xc2','\x79'},{'\xa5','\x4f'},{'\xcb','\xf1'},{'\xb9','\xe7'}, + {'\xc0','\xad'},{'\xcc','\xb0'},{'\xac','\xc2'},{'\xbc','\xfc'},{'\xb2','\xdc'}, + {'\xb2','\xe2'},{'\xb9','\x61'},{'\xb9','\x73'},{'\xc6','\x46'},{'\xbb','\xe2'}, + {'\xa8','\xd2'},{'\xc2','\xa7'},{'\xc4','\xbf'},{'\xc1','\xf5'},{'\xb4','\x63'}, + {'\xa4','\x46'},{'\xb9','\xb1'},{'\xbc','\x64'},{'\xa7','\xbf'},{'\xae','\xc6'}, + {'\xbc','\xd6'},{'\xbf','\x52'},{'\xc0','\xf8'},{'\xe7','\x64'},{'\xbf','\xf1'}, + {'\xc0','\x73'},{'\xb7','\x77'},{'\xa8','\xbf'},{'\xbc','\x42'},{'\xcc','\xd8'}, + {'\xac','\x68'},{'\xac','\x79'},{'\xb7','\xc8'},{'\xaf','\x5b'},{'\xaf','\x64'}, + {'\xb2','\xb8'},{'\xaf','\xc3'},{'\xc3','\xfe'},{'\xa4','\xbb'},{'\xbc','\xae'}, + {'\xb3','\xb0'},{'\xad','\xdb'},{'\xb1','\x5b'},{'\xb2','\x5f'},{'\xbd','\xfc'}, + {'\xab','\xdf'},{'\xb7','\x58'},{'\xae','\xdf'},{'\xb2','\x76'},{'\xb6','\xa9'}, + {'\xa7','\x51'},{'\xa6','\x4f'},{'\xbc','\x69'},{'\xa9','\xf6'},{'\xa7','\xf5'}, + {'\xb1','\xf9'},{'\xaa','\x64'},{'\xb2','\x7a'},{'\xb5','\x67'},{'\xbf','\xa9'}, + {'\xf9','\xd8'},{'\xb8','\xcc'},{'\xa8','\xbd'},{'\xc2','\xf7'},{'\xb0','\xce'}, + {'\xb7','\xc4'},{'\xa7','\x5b'},{'\xbf','\x4d'},{'\xbf','\x5a'},{'\xc4','\xa9'}, + {'\x95','\xf9'},{'\xc5','\xec'},{'\xc5','\xef'},{'\xaa','\x4c'},{'\xb2','\x4f'}, + {'\xc1','\x7b'},{'\xa5','\xdf'},{'\xb2','\xc1'},{'\xb2','\xc9'},{'\xaa','\xac'}, + {'\xaa','\xa5'},{'\xc3','\xd1'},{'\xa4','\xb0'},{'\xaf','\xf9'},{'\xa8','\xeb'}, + {'\xa4','\xc1'},{'\xab','\xd7'},{'\xa9','\xdd'},{'\xbf','\x7d'},{'\xa6','\x76'}, + {'\xac','\x7d'},{'\xbc','\xc9'},{'\xbf','\xe7'},{'\xa6','\xe6'},{'\xad','\xb0'}, + {'\xa8','\xa3'},{'\xb9','\xf8'},{'\xc9','\x4a'},{'\xdd','\xfc'},{'\x98','\x77'}, + {'\x98','\x78'},{'\xb6','\xef'},{'\x98','\x79'},{'\xb4','\xb8'},{'\x98','\x7a'}, + {'\x98','\x7b'},{'\xe8','\xf9'},{'\x95','\xbd'},{'\xaf','\x71'},{'\x98','\x7c'}, + {'\xaf','\xab'},{'\xb2','\xbb'},{'\xba','\xd6'},{'\xb9','\x74'},{'\xba','\xeb'}, + {'\xa6','\xd0'},{'\x98','\x7d'},{'\x98','\x7e'},{'\x98','\xa1'},{'\xbd','\xd1'}, + {'\x98','\xa2'},{'\x98','\xa3'},{'\xb6','\x68'},{'\xb3','\xa3'},{'\x98','\xa4'}, + {'\x98','\xa5'},{'\x98','\xa6'},{'\xb6','\xba'},{'\xb9','\x7d'},{'\xc0','\x5d'}, + {'\xc5','\x62'},{'\x00','\x00'},{'\x00','\x00'},{'\xab','\x56'},{'\xb9','\xac'}, + {'\xa7','\x4b'},{'\xab','\x6a'},{'\xb6','\xd4'},{'\xa8','\xf5'},{'\xb3','\xdc'}, + {'\xb9','\xc4'},{'\xbe','\xb9'},{'\x94','\x59'},{'\xbe','\xa5'},{'\xbc','\x68'}, + {'\xc9','\x4b'},{'\xae','\xac'},{'\xb4','\x6e'},{'\xbc','\xa8'},{'\xc3','\x67'}, + {'\xb1','\xd3'},{'\xac','\x4a'},{'\xb4','\xbb'},{'\xb1','\xf6'},{'\xae','\xfc'}, + {'\xb2','\x5a'},{'\xba','\x7e'},{'\xb5','\x4e'},{'\x9c','\x70'},{'\xb5','\x5a'}, + {'\xb8','\x4f'},{'\xaa','\xc0'},{'\xac','\xe7'},{'\xac','\xe8'},{'\xaf','\xa7'}, + {'\xaf','\xaa'},{'\xaf','\xac'},{'\xba','\xd7'},{'\xba','\xd5'},{'\xbd','\x5c'}, + {'\xac','\xf0'},{'\xb8','\x60'},{'\xbd','\x6d'},{'\xbf','\xa7'},{'\xc1','\x63'}, + {'\xb8','\x70'},{'\xaa','\xcc'},{'\xaf','\xe4'},{'\x9c','\xd2'},{'\x9c','\xd2'}, + {'\xb5','\xdb'},{'\xbd','\xc5'},{'\xb5','\xf8'},{'\xbf','\xd6'},{'\xc2','\xd4'}, + {'\xbb','\xab'},{'\xc3','\xd8'},{'\x9c','\xe0'},{'\xb6','\x68'},{'\xc3','\xf8'}, + {'\xc5','\x54'},{'\xc0','\x57'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa1','\x4a'},{'\xa1','\x57'},{'\x00','\x00'}, + {'\xa1','\x59'},{'\xa1','\x5b'},{'\xa1','\x5f'},{'\xa1','\x60'},{'\xa1','\x63'}, + {'\xa1','\x64'},{'\xa1','\x67'},{'\xa1','\x68'},{'\xa1','\x6b'},{'\xa1','\x6c'}, + {'\xa1','\x6f'},{'\xa1','\x70'},{'\xa1','\x73'},{'\xa1','\x74'},{'\xa1','\x77'}, + {'\xa1','\x78'},{'\xa1','\x7b'},{'\xa1','\x7c'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa1','\xc6'},{'\xa1','\xc7'},{'\xa1','\xca'}, + {'\xa1','\xcb'},{'\xa1','\xc8'},{'\xa1','\xc9'},{'\xa1','\x5c'},{'\xa1','\x4d'}, + {'\xa1','\x4e'},{'\xa1','\x4f'},{'\x00','\x00'},{'\xa1','\x51'},{'\xa1','\x52'}, + {'\xa1','\x53'},{'\xa1','\x54'},{'\x00','\x00'},{'\xa1','\x7d'},{'\xa1','\x7e'}, + {'\xa1','\xa1'},{'\xa1','\xa2'},{'\xa1','\xa3'},{'\xa1','\xa4'},{'\xa1','\xcc'}, + {'\xa1','\xcd'},{'\xa1','\xce'},{'\xa1','\xde'},{'\xa1','\xdf'},{'\xa1','\xe0'}, + {'\xa1','\xe1'},{'\xa1','\xe2'},{'\x00','\x00'},{'\xa2','\x42'},{'\xa2','\x4c'}, + {'\xa2','\x4d'},{'\xa2','\x4e'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\xa1','\x49'},{'\xc8','\xd0'},{'\xa1','\xad'},{'\xa2','\x43'}, + {'\xa2','\x48'},{'\xa1','\xae'},{'\x91','\xc2'},{'\xa1','\x5d'},{'\xa1','\x5e'}, + {'\xa1','\xaf'},{'\xa1','\xcf'},{'\xa1','\x41'},{'\xa1','\xd0'},{'\xa1','\x44'}, + {'\xa1','\xfe'},{'\xa2','\xaf'},{'\xa2','\xb0'},{'\xa2','\xb1'},{'\xa2','\xb2'}, + {'\xa2','\xb3'},{'\xa2','\xb4'},{'\xa2','\xb5'},{'\xa2','\xb6'},{'\xa2','\xb7'}, + {'\xa2','\xb8'},{'\xa1','\x47'},{'\xa1','\x46'},{'\xa1','\xd5'},{'\xa1','\xd7'}, + {'\xa1','\xd6'},{'\xa1','\x48'},{'\xa2','\x49'},{'\xa2','\xcf'},{'\xa2','\xd0'}, + {'\xa2','\xd1'},{'\xa2','\xd2'},{'\xa2','\xd3'},{'\xa2','\xd4'},{'\xa2','\xd5'}, + {'\xa2','\xd6'},{'\xa2','\xd7'},{'\xa2','\xd8'},{'\xa2','\xd9'},{'\xa2','\xda'}, + {'\xa2','\xdb'},{'\xa2','\xdc'},{'\xa2','\xdd'},{'\xa2','\xde'},{'\xa2','\xdf'}, + {'\xa2','\xe0'},{'\xa2','\xe1'},{'\xa2','\xe2'},{'\xa2','\xe3'},{'\xa2','\xe4'}, + {'\xa2','\xe5'},{'\xa2','\xe6'},{'\xa2','\xe7'},{'\xa2','\xe8'},{'\xc6','\xe4'}, + {'\xa2','\x40'},{'\xc6','\xe5'},{'\x5e','\x20'},{'\xa1','\xc4'},{'\xa1','\xab'}, + {'\xa2','\xe9'},{'\xa2','\xea'},{'\xa2','\xeb'},{'\xa2','\xec'},{'\xa2','\xed'}, + {'\xa2','\xee'},{'\xa2','\xef'},{'\xa2','\xf0'},{'\xa2','\xf1'},{'\xa2','\xf2'}, + {'\xa2','\xf3'},{'\xa2','\xf4'},{'\xa2','\xf5'},{'\xa2','\xf6'},{'\xa2','\xf7'}, + {'\xa2','\xf8'},{'\xa2','\xf9'},{'\xa2','\xfa'},{'\xa2','\xfb'},{'\xa2','\xfc'}, + {'\xa2','\xfd'},{'\xa2','\xfe'},{'\xa3','\x40'},{'\xa3','\x41'},{'\xa3','\x42'}, + {'\xa3','\x43'},{'\xa1','\x61'},{'\xa1','\x55'},{'\xa1','\x62'},{'\xa1','\xe3'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xc8','\xb9'},{'\xc8','\xba'},{'\xc8','\xbb'}, + {'\xc8','\xbc'},{'\xc8','\xbd'},{'\xc8','\xbe'},{'\xc8','\xbf'},{'\xc8','\xc0'}, + {'\xc8','\xc1'},{'\xc8','\xc2'},{'\xc8','\xc3'},{'\xc8','\xc4'},{'\xc8','\xc5'}, + {'\xc8','\xc6'},{'\xc8','\xc7'},{'\xc8','\xc8'},{'\xc8','\xc9'},{'\xc8','\xca'}, + {'\xc8','\xcb'},{'\xc8','\xcc'},{'\xc8','\xd4'},{'\xc8','\xd5'},{'\xc8','\xd6'}, + {'\xc8','\xd7'},{'\xc8','\xd8'},{'\xc8','\xd9'},{'\xc8','\xda'},{'\xc8','\xdb'}, + {'\xc8','\xdc'},{'\xc8','\xdd'},{'\xc8','\xde'},{'\xc8','\xdf'},{'\xc8','\xe0'}, + {'\xc8','\xe1'},{'\xc8','\xe2'},{'\xc8','\xe3'},{'\xc8','\xe4'},{'\xc8','\xe5'}, + {'\xc8','\xe6'},{'\xc8','\xe7'},{'\xc8','\xe8'},{'\xc8','\xe9'},{'\xc8','\xea'}, + {'\xc8','\xeb'},{'\xc8','\xec'},{'\xc8','\xed'},{'\xc8','\xee'},{'\xc8','\xef'}, + {'\xc8','\xf0'},{'\xc8','\xf1'},{'\xc8','\xf2'},{'\xc8','\xf3'},{'\xc8','\xf4'}, + {'\xc8','\xf5'},{'\xc8','\xf6'},{'\xc8','\xf7'},{'\xc8','\xf8'},{'\xc8','\xf9'}, + {'\xc8','\xfa'},{'\xc8','\xfb'},{'\xc8','\xfc'},{'\xc8','\xfd'},{'\xc8','\xfe'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\xa2','\x46'}, + {'\xa2','\x47'},{'\xc8','\xcd'},{'\xa1','\xc3'},{'\xc8','\xce'},{'\xa2','\x44'}, + {'\x00','\x00'},{'\x00','\x00'},{'\xa2','\x78'},{'\xa1','\xf6'},{'\xa1','\xf4'}, + {'\xa1','\xf7'},{'\xa1','\xf5'},{'\xa1','\xbd'},{'\xa1','\xb3'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'},{'\x00','\x00'}, + {'\x00','\x00'} +}; + +static int qt_Big5ToUnicode(const uchar *s, uint *pwc) +{ + uchar c1 = s[0]; + int idx; + ushort wc = 0xfffd; + + if ((c1 >= 0x81 && c1 <= 0xfe)) { + uchar c2 = s[1]; + + if (c2 < 0x40 || c2 > 0xfe + || (idx = ((c1 - 0x81) * 191) + (c2 - 0x40), + (wc = big5_to_ucs[idx]) == 0)) + return 0; + else { + *pwc = (uint) wc; + return 2; + } + + } else if (c1 < 0x80) { + *pwc = (uint) c1; + return 1; + } + return 0; +} + +static int qt_UnicodeToBig5(uint wc, uchar *r) +{ + const Summary16 *summary = NULL; + const uchar * c; + if (wc < 0x80) { + r[0] = (uchar) wc; + return 1; + } + else { + if (wc >= 0 && wc <= 65535){ + c = ucs_to_big5[wc]; + if (c [0] == '\0') + return 0; + if (c [1] != 0) { + r[0] = c[0]; + r[1] = c[1]; + return 2; + } else { // (c [1] == 0) + r[0] = c[0]; + return 1; + } + } + } + return 0; +} + +QString UAOCodec::convertToUnicode(const char* chars, int len, ConverterState *state) const +{ + QChar replacement = QChar::ReplacementCharacter; + uchar buf[2] = {0}; + int nbuf = 0; + if (state) { + if (state->flags & ConvertInvalidToNull) + replacement = QChar::Null; + nbuf = state->remainingChars; + buf[0] = state->state_data[0]; + buf[1] = state->state_data[1]; + } + int invalid = 0; + + //qDebug("UAOCodec::toUnicode(const char* chars = \"%s\", int len = %d)", chars, len); + QString result; + for (int i=0; iremainingChars = nbuf; + state->state_data[0] = buf[0]; + state->state_data[1] = buf[1]; + state->invalidChars += invalid; + } + return result; +} + +QByteArray UAOCodec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + char replacement = '?'; + if (state) { + if (state->flags & ConvertInvalidToNull) + replacement = 0; + } + + int invalid = 0; + + int rlen = 2*len + 1; + QByteArray rstr; + rstr.resize(rlen); + + uchar* cursor = (uchar*)rstr.data(); + for (int i=0; i= 0xa1 && c[0] <= 0xf9) { + *cursor++ = c[0]; + *cursor++ = c[1]; + } else { + *cursor++ = replacement; + ++invalid; + } + } + rstr.resize(cursor - (uchar*)rstr.constData()); + + if (state) { + state->invalidChars += invalid; + } + return rstr; +} + +QList UAOCodec::_aliases() +{ + QList aliases; + aliases += "Unicode-at-on"; + return aliases; +} + +/* ====================================================================== */ +#endif // QT_NO_TEXTCODEC + +QT_END_NAMESPACE diff --git a/src/fqterm/3rdparty/uaocodec.h b/src/fqterm/3rdparty/uaocodec.h new file mode 100644 index 0000000..9984250 --- /dev/null +++ b/src/fqterm/3rdparty/uaocodec.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Most of the code here was originally written by UAO project (http://uao.cpatch.org/) +// Ported to Qt by hooey (from uao-051123-src.tar.gz) + +#ifndef UAOCODEC_H +#define UAOCODEC_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class UAOCodec : public QTextCodec { +public: + static QByteArray _name(); + static QList _aliases(); + static int _mibEnum(); + + QByteArray name() const { return _name(); } + QList aliases() const { return _aliases(); } + int mibEnum() const { return _mibEnum(); } + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; +}; + +QT_END_NAMESPACE + +#endif // UAOCODEC_H diff --git a/src/fqterm/CMakeLists.txt b/src/fqterm/CMakeLists.txt new file mode 100644 index 0000000..a93cdaf --- /dev/null +++ b/src/fqterm/CMakeLists.txt @@ -0,0 +1,83 @@ +set(fqterm_SRCS + fqterm_app.h + fqterm_autoupdate.h + fqterm_frame.h + fqterm_screen.h + fqterm_window.h + fqterm_wndmgr.h + fqterm_autoupdate.cpp + fqterm_app.cpp + fqterm_frame.cpp + fqterm_screen.cpp + fqterm_window.cpp + fqterm_wndmgr.cpp + fqterm_python.h + fqterm_python.cpp + fqterm_scriptengine.h + fqterm_scriptengine.cpp +) + + +IF(WIN32) + set(global_shortcut_impl_SRCS 3rdparty/qxtglobalshortcut_win.cpp) +ELSE(WIN32) + IF(APPLE) + set(global_shortcut_impl_SRCS 3rdparty/qxtglobalshortcut_mac.cpp) + ELSE(APPLE) + set(global_shortcut_impl_SRCS 3rdparty/qxtglobalshortcut_x11.cpp) + ENDIF(APPLE) +ENDIF(WIN32) + + + +set(3rdparty_SRCS + 3rdparty/dotnetstyle.cpp + 3rdparty/dotnetstyle.h + 3rdparty/qxtglobalshortcut.cpp + 3rdparty/qxtglobalshortcut.h + 3rdparty/qxtglobalshortcut_p.h + 3rdparty/qxtglobal.h + 3rdparty/uaocodec.h + 3rdparty/uaocodec.cpp + ${global_shortcut_impl_SRCS} +) + +qt4_automoc(${fqterm_SRCS} + ${3rdparty_SRCS} +) + +qt4_create_translation(fqterm_qm_file + ${fqterm_SRCS} + ${CMAKE_SOURCE_DIR}/res/dict/fqterm_zh_CN.ts +) + +include_directories( + ${QT_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} + ${QT_QTGUI_INCLUDE_DIR} + ${QT_QTNETWORK_INCLUDE_DIR} + ${QT_QTSCRIPT_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../common + ${CMAKE_CURRENT_SOURCE_DIR}/../protocol + ${CMAKE_CURRENT_SOURCE_DIR}/../terminal + ${CMAKE_CURRENT_SOURCE_DIR}/../utilities + ${CMAKE_CURRENT_SOURCE_DIR}/../unite + ${CMAKE_CURRENT_SOURCE_DIR}/../ui + ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty + ${CMAKE_CURRENT_BINARY_DIR}/../ui + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_library(fqterm_main + ${fqterm_SRCS} + ${3rdparty_SRCS} +) + +add_dependencies(fqterm_main + fqterm_common + fqterm_terminal + fqterm_protocol + fqterm_ui + fqterm_utilities + fqterm_unite +) diff --git a/src/fqterm/fqterm.rc b/src/fqterm/fqterm.rc new file mode 100644 index 0000000..88394ab Binary files /dev/null and b/src/fqterm/fqterm.rc differ diff --git a/src/fqterm/fqterm_app.cpp b/src/fqterm/fqterm_app.cpp new file mode 100644 index 0000000..393355a --- /dev/null +++ b/src/fqterm/fqterm_app.cpp @@ -0,0 +1,38 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_app.h" + +namespace FQTerm { + +FQTermApplication::FQTermApplication( int & argc, char ** argv ) : QApplication(argc, argv) +{ + +} + +void FQTermApplication::commitData( QSessionManager & manager ) +{ + emit saveData(); +} + + +} //namespace FQTerm + +#include "fqterm_app.moc" \ No newline at end of file diff --git a/src/fqterm/fqterm_app.h b/src/fqterm/fqterm_app.h new file mode 100644 index 0000000..ee0778a --- /dev/null +++ b/src/fqterm/fqterm_app.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_APP +#define FQTERM_APP +#include +#include +namespace FQTerm { + +class FQTermApplication : public QApplication { + Q_OBJECT; +public: + FQTermApplication(int & argc, char ** argv); +protected: + virtual void commitData(QSessionManager & manager); +signals: + void saveData(); +protected slots: + void mainWindowDestroyed(QObject* obj) {quit();} +}; + +} //namespace FQTerm + +#endif \ No newline at end of file diff --git a/src/fqterm/fqterm_autoupdate.cpp b/src/fqterm/fqterm_autoupdate.cpp new file mode 100644 index 0000000..0f49c38 --- /dev/null +++ b/src/fqterm/fqterm_autoupdate.cpp @@ -0,0 +1,178 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_autoupdate.h" +#include "fqterm_config.h" +#include "fqterm_trace.h" +#include "fqterm_param.h" + +#include +#include +#include +#include +#include +#include + +namespace FQTerm { + +//////////////////////////////////////////////// +static int versionCompare(QString lhs, QString rhs) { + //0 -- lhs == rhs, -1 -- lhs > rhs, 1 -- lhs < rhs + + int versionEnd = lhs.indexOf('-'); + if (versionEnd != -1) { + lhs = lhs.mid(0, versionEnd); + } + versionEnd = rhs.indexOf('-'); + if (versionEnd != -1) { + rhs = rhs.mid(0, versionEnd); + } + QStringList lhsList = lhs.split("."); + QStringList rhsList = rhs.split("."); + if (lhsList.size() != 3 || rhsList.size() != 3) { + return 0; //something is wrong + } + for (int i = 0; i < 3; ++i) { + if (lhsList[i].toInt() < rhsList[i].toInt()) { + return 1; + } + else if (lhsList[i].toInt() > rhsList[i].toInt()) { + return -1; + } + } + return 0; +} +/////////////////////////////////////////////// + +void FQTermAutoUpdater::checkUpdate() { + QString fileName = FQTermPref::getInstance()->poolDir_ + "VersionInfo"; + if (QFile::exists(fileName)) { + QFile::remove(fileName); + } + versionInfoFile_ = new QFile(fileName, this); + if (!versionInfoFile_->open(QIODevice::WriteOnly)) { + delete versionInfoFile_; + return; + } + FQ_VERIFY(connect(updateChecker_, SIGNAL(requestFinished(int, bool)), + this, SLOT(checkRequestFinished(int, bool)))); + FQ_VERIFY(connect(updateChecker_, SIGNAL(done(bool)), + this, SLOT(httpDone(bool)))); + + const QString versionInfoURL = "http://fqterm.googlecode.com/svn/trunk/VersionInfo"; + QUrl url(versionInfoURL); + QHttp::ConnectionMode mode = url.scheme().toLower() == "https" ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp; + updateChecker_->setHost(url.host(), mode, url.port() == -1 ? 0 : url.port()); + if (!url.userName().isEmpty()) + updateChecker_->setUser(url.userName(), url.password()); + checkRequestId_ = updateChecker_->get(url.path(), versionInfoFile_); +} + +QString FQTermAutoUpdater::getNewestVersion() { +#if defined(WIN32) + const QString platform = "FQWin"; +#elif defined(__unix__) && !defined(__APPLE__) + const QString platform = "FQLinux"; +#else + const QString platform = "FQMac"; +#endif + FQTermConfig versionInfo(FQTermPref::getInstance()->poolDir_ + "VersionInfo"); + QString ver = versionInfo.getItemValue(platform, "version"); + if (ver.isEmpty()) { + return FQTERM_VERSION_STRING; + } + return ver; +} + +void FQTermAutoUpdater::promptUpdate() { + const QString updateURL = "http://code.google.com/p/fqterm/downloads/list"; + QMessageBox msgBox(QMessageBox::Information, tr("FQTerm Update Notifier"), + tr("FQTerm update available.\nPress OK to visit our download list,\nDiscard for a future prompt,\nIgnore for no more notification."), + QMessageBox::Ok | QMessageBox::Discard | QMessageBox::Ignore); + switch (msgBox.exec()) { + case QMessageBox::Ok: + QDesktopServices::openUrl(updateURL); + break; + case QMessageBox::Discard: + break; + case QMessageBox::Ignore: + config_->setItemValue("global", "newestversion", getNewestVersion()); + config_->setItemValue("global", "updateprompt", "0"); + break; + } +} + +void FQTermAutoUpdater::checkRequestFinished(int requestId, bool error){ + + if (checkDone_ || requestId != checkRequestId_) { + return; + } + if (!error) { + checkDone_ = true; + } +} + +void FQTermAutoUpdater::httpDone(bool err) { + if (!err) { + versionInfoFile_->flush(); + if (checkDone_) { + QString newestVersionRecorded = config_->getItemValue("global", "newestversion"); + if (newestVersionRecorded.isEmpty()) { + newestVersionRecorded = FQTERM_VERSION_STRING; + config_->setItemValue("global", "newestversion", newestVersionRecorded); + } + QString newestVersionReleased = getNewestVersion(); + + QString updatePrompt = config_->getItemValue("global", "updateprompt"); + if (updatePrompt == "0") { + //if newest version > recorded version, still prompt. + if (versionCompare(newestVersionRecorded, newestVersionReleased) > 0) { + config_->setItemValue("global", "updateprompt", "1"); + promptUpdate(); + } + } + else { + config_->setItemValue("global", "updateprompt", "1"); + //if newest version > version in use, prompt. + if (versionCompare(FQTERM_VERSION_STRING, newestVersionReleased) > 0) { + promptUpdate(); + } + } + } + } + deleteLater(); +} + +FQTermAutoUpdater::FQTermAutoUpdater(QObject* parent, FQTermConfig* config) +: QObject(parent), + config_(config), + versionInfoFile_(0), + checkDone_(false) { + updateChecker_ = new QHttp(this); +} + +FQTermAutoUpdater::~FQTermAutoUpdater() +{ + +} + +} //FQTerm namespace + +#include "fqterm_autoupdate.moc" diff --git a/src/fqterm/fqterm_autoupdate.h b/src/fqterm/fqterm_autoupdate.h new file mode 100644 index 0000000..0ad8aaf --- /dev/null +++ b/src/fqterm/fqterm_autoupdate.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_AUTO_UPDATE_H +#define FQTERM_AUTO_UPDATE_H + +#include + +class QHttp; +class QFile; +class QString; + +namespace FQTerm { + +class FQTermConfig; + +class FQTermAutoUpdater : public QObject{ + + Q_OBJECT; + +public: + FQTermAutoUpdater(QObject* parent, FQTermConfig* config); + ~FQTermAutoUpdater(); + + void checkUpdate(); + +protected slots: + void checkRequestFinished(int requestId, bool error); + void httpDone(bool err); + +private: + QString getNewestVersion(); + void promptUpdate(); + + FQTermConfig* config_; + QHttp * updateChecker_; + QFile * versionInfoFile_; + int checkRequestId_; + bool checkDone_; +}; + +} //namespace FQTerm + +#endif diff --git a/src/fqterm/fqterm_frame.cpp b/src/fqterm/fqterm_frame.cpp new file mode 100644 index 0000000..b50eff9 --- /dev/null +++ b/src/fqterm/fqterm_frame.cpp @@ -0,0 +1,2162 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#if !defined(WIN32) +#include +#endif + +#if defined(__linux__) || defined(__GLIBC__) +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aboutdialog.h" +#include "addrdialog.h" +#include "common.h" +#include "keydialog.h" +#include "prefdialog.h" +#include "fqterm.h" + +#include "fqterm_path.h" +#include "fqterm_autoupdate.h" +#include "fqterm_config.h" +#include "fqterm_frame.h" +#include "fqterm_param.h" +#include "fqterm_session.h" +#include "fqterm_screen.h" +#include "fqterm_time_label.h" +#include "fqterm_tool_button.h" +#include "fqterm_window.h" +#include "fqterm_wndmgr.h" +#include "imageviewer.h" +#include "quickdialog.h" +#include "statusBar.h" +#include "sitemanager.h" +#include "fqterm_shortcuthelper.h" +#include "fqterm_mini_server.h" +#include "shortcutdialog.h" +#include "schemadialog.h" +#include "fqterm_ip_location.h" +#include "iplookup.h" +#include "defineescape.h" +#include "uaocodec.h" + +#ifdef USE_DOTNET_STYLE +#include "dotnetstyle.h" +#endif //USE_DOTNET_STYLE + +#ifdef USE_GLOBAL_HOTKEY +#include "qxtglobalshortcut.h" +#endif //USE_GLOBAL_HOTKEY + +#ifdef HAVE_PYTHON +#include +#include "fqterm_python.h" +#endif //HAVE_PYTHON + +namespace FQTerm { + + +const QString FQTermFrame::qmPrefix[FQTermFrame::translatedModule] = +{"fqterm_", "ui_", "protocol_", "common_"}; +const QString FQTermFrame::qmPostfix = ".qm"; + +//constructor +FQTermFrame::FQTermFrame() + : QMainWindow(0), + tray_(0), + trayMenu_(0), +#ifdef HAVE_PYTHON + pythonHelper_(0), +#endif +#ifdef USE_GLOBAL_HOTKEY + globalHotkey_(0), +#endif //USE_GLOBAL_HOTKEY + shortcutHelper_(0) +{ + setAttribute(Qt::WA_DeleteOnClose); + +/*#ifndef __APPLE__ + setWindowFlags(Qt::CustomizeWindowHint); +#endif*/ + uaoCodec_ = new UAOCodec; + + config_ = new FQTermConfig(getPath(USER_CONFIG) + "fqterm.cfg"); + + initTranslator(); + shortcutHelper_ = new FQTermShortcutHelper(config_, this); + +#ifdef IMAGE_USE_PICFLOW + imageViewer_ = new FQTermImageFlow(config_, NULL, Qt::Window); +#else + imageViewer_ = new FQTermImageOrigin(config_, NULL, Qt::Window); +#endif + + + //create the window manager to deal with the window-tab-icon pairs + windowManager_ = new FQTermWndMgr(this); + setCentralWidget(windowManager_); + + //set menubar + addMainMenu(); + FQ_VERIFY(connect(this, SIGNAL(changeLanguage()), + this, SLOT(recreateMenu()))); + + //initialize all settings + //This should be done before add main tool, since some status of tool will depend on setting + iniSetting(); + FQTermConfig* conf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg"); + checkHelpExists(conf); + delete conf; + //setup toolbar + addMainTool(); + + // add the custom defined key + // and load toolbar position + updateKeyToolBar(); + loadToolBarPosition(); + enableMenuToolBar(false); + + // FIXME: !!!create a horizonal layout to hold the tabbar,the reason + //of why not put the tabbar directly on the status bar is when no + //tab in the tabbar,the statusbar display a horizonal line,ugly. + //perhaps there is some function in statusbar to solve this. + QWidget *hb = new QWidget(statusBar()); + hb->setObjectName("taskbar"); + QHBoxLayout *hbLayout = new QHBoxLayout(hb); + hbLayout->setMargin(0); + hbLayout->setObjectName("tasklayout"); + statusBar()->addWidget(hb); + //create a tabbar in the hbox + hbLayout->addWidget(windowManager_->tabBar()); + + windowMapper_ = new QSignalMapper(this); + FQ_VERIFY(connect(windowMapper_, SIGNAL(mapped(int)), + windowManager_, SLOT(activateTheWindow(int)))); + initAdditionalActions(); + + //create a progress bar to notify the download process + statusBar_ = new FQTerm::StatusBar(statusBar(), "mainStatusBar"); + statusBar()->addWidget(statusBar_, 0); + + installEventFilter(this); + + QDate lastCheckDate = QDate::fromString(config_->getItemValue("global", "lastcheckupdate")); + QDate currentDate = QDate::currentDate(); + if (!lastCheckDate.isValid() || lastCheckDate.daysTo(currentDate) >= 31) { + FQTermAutoUpdater* autoUpdater = + new FQTermAutoUpdater(this, config_); + autoUpdater->checkUpdate(); + config_->setItemValue("global", "lastcheckupdate", currentDate.toString()); + } + + serverThread_ = new FQTermMiniServerThread(); + if (FQTermPref::getInstance()->runServer_) + serverThread_->start(); +#ifdef HAVE_PYTHON + pythonHelper_ = new FQTermPythonHelper; +#endif +#ifdef USE_GLOBAL_HOTKEY + globalHotkey_ = new QxtGlobalShortcut(shortcutHelper_->getAction(FQTermShortcutHelper::GLOBAL_SHOW_FQTERM)->shortcut(), this); + FQ_VERIFY(connect(shortcutHelper_->getAction(FQTermShortcutHelper::GLOBAL_SHOW_FQTERM), SIGNAL(changed()), + this, SLOT(globalHotkeyChanged()))); + FQ_VERIFY(connect(globalHotkey_, SIGNAL(activated()), + this, SLOT(globalHotkeyTriggered()))); +#endif //USE_GLOBAL_HOTKEY +} + +//destructor +FQTermFrame::~FQTermFrame() { +#ifdef USE_GLOBAL_HOTKEY + delete globalHotkey_; +#endif //USE_GLOBAL_HOTKEY +#ifdef HAVE_PYTHON + delete pythonHelper_; +#endif //HAVE_PYTHON + clearTranslator(); + delete imageViewer_; + delete shortcutHelper_; + delete config_; + delete uaoCodec_; + delete windowManager_; + FQTermIPLocation::Destroy(); + serverThread_->quit(); + serverThread_->wait(1000); + delete serverThread_; + +} + +//initialize setting from fqterm.cfg +void FQTermFrame::iniSetting() { + QString strTmp; + + strTmp = config_->getItemValue("global", "fullscreen"); + if (strTmp == "1") { + getAction(FQTermShortcutHelper::FULLSCREEN)->setChecked(true); + showFullScreen(); + } else { + //window size + strTmp = config_->getItemValue("global", "max"); + if (strTmp == "1") { + showMaximized(); + } else { + QString size = config_->getItemValue("global", "size"); + if (size != "") { + int x, y, cx, cy; + sscanf(size.toLatin1(), "%d %d %d %d", &x, &y, &cx, &cy); + resize(QSize(cx, cy)); + move(QPoint(x, y)); + } + } + } + + theme_ = config_->getItemValue("global", "theme"); + QStyle *style; +#ifdef USE_DOTNET_STYLE + //javaboy@newsmth.org + if (theme_ == "Office") + style = new DotNetStyle(DotNetStyle::Office); + else +#endif //USE_DOTNET_STYLE + style = QStyleFactory::create(theme_); + if (style) { + qApp->setStyle(style); + } + + //language + updateLanguageMenu(); + + //TODO: + getAction(FQTermShortcutHelper::COLORCTL_NO)->setChecked(true); + FQTermPref::getInstance()->escapeString_ = config_->getItemValue("global", "escstr"); + if (FQTermPref::getInstance()->escapeString_ == "") { + getAction(FQTermShortcutHelper::COLORCTL_NO)->setChecked(true); + getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false); + } else if (FQTermPref::getInstance()->escapeString_ == "^[^[[") { + getAction(FQTermShortcutHelper::COLORCTL_SMTH)->setChecked(true); + getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false); + } else if (FQTermPref::getInstance()->escapeString_ == "^u[") { + getAction(FQTermShortcutHelper::COLORCTL_PTT)->setChecked(true); + getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false); + } else { + QAction *pAction = getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM); + QString transStrEsc; + transEscapeStr(transStrEsc, FQTermPref::getInstance()->escapeString_); + pAction->setText(transStrEsc); + pAction->setVisible(true); + pAction->setChecked(true); + } + + strTmp = config_->getItemValue("global", "vscrollpos"); + if (strTmp == "0") { + FQTermPref::getInstance()->termScrollBarPosition_ = 0; + getAction(FQTermShortcutHelper::SCROLLBAR_HIDDEN)->setChecked(true); + } else if (strTmp == "1") { + FQTermPref::getInstance()->termScrollBarPosition_ = 1; + getAction(FQTermShortcutHelper::SCROLLBAR_LEFT)->setChecked(true); + } else { + FQTermPref::getInstance()->termScrollBarPosition_ = 2; + getAction(FQTermShortcutHelper::SCROLLBAR_RIGHT)->setChecked(true); + } + strTmp = config_->getItemValue("global", "switchbar"); + isTabBarShown_ = (strTmp != "0"); + getAction(FQTermShortcutHelper::SWITCHBAR)->setChecked(isTabBarShown_); + if (isTabBarShown_) { + statusBar()->show(); + } else { + statusBar()->hide(); + } + + //read sub-window setting. + strTmp = config_->getItemValue("global", "subwindowmax"); + windowManager_->setSubWindowMax((strTmp != "0")); + + + strTmp = config_->getItemValue("global", "subwindowsize"); + if (strTmp != "") { + //FIXME: In case of sub window size not saved properly. + int w, h; + sscanf(strTmp.toLatin1(), "%d %d", &w, &h); + windowManager_->setSubWindowSize(QSize(w, h)); + } else { + //Magic Number. Initialize Window Size to Avoid Errors. + windowManager_->setSubWindowSize(QSize(640, 480)); + } + + FQTermPref::getInstance()->isBossColor_ = false; + + loadPref(); + + setUseDock(FQTermPref::getInstance()->openMinimizeToTray_); + + if (FQTermPref::getInstance()->useStyleSheet_) { + loadStyleSheetFromFile(FQTermPref::getInstance()->styleSheetFile_); + } + + strTmp = config_->getItemValue("global", "runserver"); + FQTermPref::getInstance()->runServer_ = (strTmp != "0"); +} + +void FQTermFrame::loadPref() { + QString strTmp; + + strTmp = config_->getItemValue("preference", "displayoffset"); + FQTermPref::getInstance()->displayOffset_ = strTmp.toInt(); + strTmp = config_->getItemValue("preference", "vsetting"); + FQTermPref::getInstance()->vsetting_ = strTmp.toInt(); + strTmp = config_->getItemValue("preference", "xim"); + FQTermPref::getInstance()->imeEncodingID_ = strTmp.toInt(); + strTmp = config_->getItemValue("preference", "wordwrap"); + FQTermPref::getInstance()->widthToWrapWord_ = strTmp.toInt(); + // strTmp = conf->getItemValue("preference", "smartww"); + // m_pref.bSmartWW = (strTmp != "0"); + strTmp = config_->getItemValue("preference", "wheel"); + FQTermPref::getInstance()->isWheelSupported_ = (strTmp != "0"); + strTmp = config_->getItemValue("preference", "url"); + FQTermPref::getInstance()->openUrlCheck_ = (strTmp != "0"); + // strTmp = conf->getItemValue("preference", "logmsg"); + // m_pref.bLogMsg = (strTmp != "0"); + strTmp = config_->getItemValue("preference", "blinktab"); + FQTermPref::getInstance()->openTabBlinking_ = (strTmp != "0"); + strTmp = config_->getItemValue("preference", "warn"); + FQTermPref::getInstance()->openWarnOnClose_ = (strTmp != "0"); + strTmp = config_->getItemValue("preference", "beep"); + FQTermPref::getInstance()->openBeep_ = strTmp.toInt(); + FQTermPref::getInstance()->beepSoundFileName_ = config_->getItemValue("preference", "wavefile"); + strTmp = config_->getItemValue("preference", "http"); + FQTermPref::getInstance()->httpBrowser_ = strTmp; + // m_pref.strHttp = strTmp; + strTmp = config_->getItemValue("preference", "antialias"); + FQTermPref::getInstance()->openAntiAlias_ = (strTmp != "0"); + strTmp = config_->getItemValue("preference", "enq"); + FQTermPref::getInstance()->replyENQ_ = (strTmp != "0"); + strTmp = config_->getItemValue("preference", "tray"); + if (strTmp.isEmpty()) { +#if defined(__APPLE__) || defined(__linux__) || defined(__GLIBC__) + FQTermPref::getInstance()->openMinimizeToTray_ = false; +#else + FQTermPref::getInstance()->openMinimizeToTray_ = true; +#endif + } else { + FQTermPref::getInstance()->openMinimizeToTray_ = (strTmp != "0"); + } + strTmp = config_->getItemValue("preference", "playmethod"); + FQTermPref::getInstance()->beepMethodID_ = strTmp.toInt(); + strTmp = config_->getItemValue("preference", "externalplayer"); + FQTermPref::getInstance()->beepPlayerName_ = strTmp; + + strTmp = config_->getItemValue("preference", "clearpool"); + FQTermPref::getInstance()->needClearZmodemPoolOnClose_ = (strTmp == "1"); + strTmp = config_->getItemValue("preference", "pool"); + FQTermPref::getInstance()->poolDir_ = strTmp.isEmpty() ? + getPath(USER_CONFIG) + "pool/": strTmp; + if (FQTermPref::getInstance()->poolDir_.right(1) != "/") { + FQTermPref::getInstance()->poolDir_.append('/'); + } + strTmp = config_->getItemValue("preference", "zmodem"); + FQTermPref::getInstance()->zmodemDir_ = strTmp.isEmpty() ? + getPath(USER_CONFIG) + "zmodem/": strTmp; + if (FQTermPref::getInstance()->zmodemDir_.right(1) != "/") { + FQTermPref::getInstance()->zmodemDir_.append('/'); + } + strTmp = config_->getItemValue("preference", "image"); + FQTermPref::getInstance()->imageViewerName_ = strTmp; + strTmp = config_->getItemValue("preference", "qssfile"); + FQTermPref::getInstance()->styleSheetFile_ = strTmp; + FQTermPref::getInstance()->useStyleSheet_ = !strTmp.isEmpty(); + + strTmp = config_->getItemValue("preference", "editor"); + FQTermPref::getInstance()->externalEditor_ = strTmp; + + //FIXME: duplicated strings. + strTmp = config_->getItemValue("preference", "searchengine"); + if (strTmp == "google") { + getAction(FQTermShortcutHelper::SEARCH_GOOGLE)->setChecked(true); + } else if (strTmp == "baidu") { + getAction(FQTermShortcutHelper::SEARCH_BAIDU)->setChecked(true); + } else if (strTmp == "bing") { + getAction(FQTermShortcutHelper::SEARCH_BING)->setChecked(true); + } else if (strTmp == "yahoo") { + getAction(FQTermShortcutHelper::SEARCH_YAHOO)->setChecked(true); + } else if (strTmp == "custom") { + getAction(FQTermShortcutHelper::SEARCH_CUSTOM)->setChecked(true); + } else { + getAction(FQTermShortcutHelper::SEARCH_GOOGLE)->setChecked(true); + strTmp = "google"; + } + FQTermPref::getInstance()->searchEngine_ = strTmp; + + strTmp = config_->getItemValue("preference", "editorarg"); + FQTermPref::getInstance()->externalEditorArg_ = strTmp; + + strTmp = config_->getItemValue("preference", "asciienhance"); + FQTermPref::getInstance()->isAnsciiEnhance_ = (strTmp == "1"); +} + +//save current setting to fqterm.cfg +void FQTermFrame::saveSetting() { + QString strTmp; + //save font + config_->setItemValue("global", "font", qApp->font().family()); + strTmp.setNum(QFontInfo(qApp->font()).pointSize()); + config_->setItemValue("global", "pointsize", strTmp); + strTmp.setNum(QFontInfo(qApp->font()).pixelSize()); + config_->setItemValue("global", "pixelsize", strTmp); + + //save window position and size + if (isMaximized()) { + config_->setItemValue("global", "max", "1"); + } else { + strTmp = QString("%1 %2 %3 %4").arg(x()).arg(y()).arg(width()).arg(height()); + // cstrTmp.sprintf("%d %d %d %d",x(),y(),width(),height()); + config_->setItemValue("global", "size", strTmp); + config_->setItemValue("global", "max", "0"); + } + + if (windowState() & Qt::WindowFullScreen) { + config_->setItemValue("global", "fullscreen", "1"); + } else { + config_->setItemValue("global", "fullscreen", "0"); + } + + // cstrTmp.setNum(theme); + config_->setItemValue("global", "theme", theme_); + + config_->setItemValue("global", "escstr", FQTermPref::getInstance()->escapeString_); + + strTmp.setNum(FQTermPref::getInstance()->termScrollBarPosition_); + config_->setItemValue("global", "vscrollpos", strTmp); + + config_->setItemValue("global", "switchbar", isTabBarShown_ ? "1" : "0"); + + //save subwindow setting + config_->setItemValue("global", "subwindowmax", windowManager_->getSubWindowMax() ? "1" : "0"); + int w = windowManager_->getSubWindowSize().width(); + int h = windowManager_->getSubWindowSize().height(); + + strTmp = QString("%1 %2").arg(w).arg(h); + config_->setItemValue("global", "subwindowsize", strTmp); + + //Save toolbarstate. + QByteArray state = saveState().toHex(); + strTmp = QString(state); + config_->setItemValue("global", "toolbarstate", strTmp); + + config_->setItemValue("global", "runserver", FQTermPref::getInstance()->runServer_ ? "1" : "0"); + + config_->save(getPath(USER_CONFIG) + "fqterm.cfg"); +} + +void FQTermFrame::initAdditionalActions() +{ + +#if defined(__APPLE__) + QString opt(tr("Ctrl")); +#else + QString opt(tr("Alt")); +#endif + + for (int i = 1; i <= 10; ++i) { + QAction *idAction = new QAction(this); + QString shortcut(opt); + shortcut += "+" + QString("").setNum(i % 10); + idAction->setShortcut(shortcut); + connect(idAction, SIGNAL(triggered()), windowMapper_, SLOT(map())); + windowMapper_->setMapping(idAction, i - 1); + addAction(idAction); + } + + FQTERM_ADDACTION(windowManager_, NEXTWINDOW, windowManager_, activateNextWindow); + FQTERM_ADDACTION(windowManager_, PREVWINDOW, windowManager_, activatePrevWindow); + +} + +//addressbook +void FQTermFrame::addressBook() { + siteDialog siteManager(this, false); + if (siteManager.exec() == 1) { + newWindow(siteManager.currentParameter(), siteManager.currentSiteIndex()); + } +} + +//quicklogin +void FQTermFrame::quickLogin() { + quickDialog quick(config_, this); + FQTermConfig *pConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg"); + + loadAddress(pConf, -1, quick.param_); + delete pConf; + + if (quick.exec() == 1) { + newWindow(quick.param_); + } +} + +void FQTermFrame::exitFQTerm() { + if (!clearUp()) return; + deleteLater(); +} + +void FQTermFrame::newWindow(const FQTermParam ¶m, int index) { + QIcon *icon = new QIcon(QPixmap(getPath(RESOURCE) + "pic/tabpad.png")); + FQTermWindow* window = windowManager_->newWindow(param, config_, icon, index); + + updateFontCombo(); + FQ_VERIFY(connect(window->getScreen(), SIGNAL(termFontChange(bool,QFont)), this, SLOT(termFontChange(bool,QFont)))); + + window->connectHost(); +} + + +void FQTermFrame::aboutFQTerm() { + aboutDialog about(this); + about.exec(); +} + +//slot Help->Homepage +void FQTermFrame::homepage() { + const QString &httpBrowser = FQTermPref::getInstance()->httpBrowser_; + const QString homeUrl = "http://code.google.com/p/fqterm"; + + if (httpBrowser.isNull() || httpBrowser.isEmpty()) { + QDesktopServices::openUrl(homeUrl); + } else { + runProgram(httpBrowser, homeUrl); + } +} + +//slot Windows menu aboutToShow +void FQTermFrame::windowsMenuAboutToShow() { + menuWindows_->clear(); + FQTERM_ADDACTION(menuWindows_, CASCADEWINDOWS, windowManager_, cascade); + FQTERM_ADDACTION(menuWindows_, TILEWINDOWS, windowManager_, tile); + if (windowManager_->count() == 0) { + getAction(FQTermShortcutHelper::CASCADEWINDOWS)->setEnabled(false); + getAction(FQTermShortcutHelper::TILEWINDOWS)->setEnabled(false); + } + menuWindows_->addSeparator(); + +#ifdef Q_OS_MACX + // used to dock the program + if (isHidden()) { + menuWindows_->addAction(tr("Main Window"), this, SLOT(trayShow())); + } +#endif + + for (int i = 0; i < int(windowManager_->count()); ++i) { + QAction *idAction = menuWindows_->addAction(windowManager_->subWindowList().at(i)->windowTitle()); + idAction->setCheckable(true); + idAction->setChecked(windowManager_->activeWindow() == windowManager_->nthWindow(i)); + connect(idAction, SIGNAL(triggered()), windowMapper_, SLOT(map())); + windowMapper_->setMapping(idAction, i); + } +} + +void FQTermFrame::reloadConfig() { + config_->load(getPath(USER_CONFIG) + "fqterm.cfg"); +} + +void FQTermFrame::popupConnectMenu() { + menuConnect_->clear(); + menuConnect_->addAction(tr("Quick Login"), this, SLOT(quickLogin())); + menuConnect_->addSeparator(); + + FQTermConfig conf(getPath(USER_CONFIG) + "address.cfg"); + + QStringList listName; + loadNameList(&conf, listName); + + for (int i = 0; i < listName.count(); i++) { + QAction *idAction = menuConnect_->addAction(listName[i], this, SLOT + (connectMenuActivated())); + idAction->setData(i); + if (i < 10) { +#ifdef __APPLE__ + QString shortCut(tr("Ctrl+Meta")); +#else + QString shortCut(tr("Ctrl+Alt")); +#endif + shortCut += "+" + QString("").setNum((i + 1)% 10); + idAction->setShortcut(shortCut); + } + } + + int lastIndex = config_->getItemValue("global", "lastaddrindex").toInt(); + if (lastIndex < 0 || lastIndex >= listName.count()) + lastIndex = 0; + if (listName.count() > 0) + { + menuConnect_->addSeparator(); + QAction *idAction = menuConnect_->addAction(listName[lastIndex], this, SLOT + (connectMenuActivated())); + idAction->setData(LAST_ADDRESS_INDEX); +#ifdef __APPLE__ + QString shortCut(tr("Ctrl+Meta")); +#else + QString shortCut(tr("Ctrl+Alt")); +#endif + shortCut += "+" + QString("-"); + idAction->setShortcut(shortCut); + + } +} + +void FQTermFrame::connectMenuActivated() { + FQTermConfig *pConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg"); + int id = static_cast < QAction * > (sender())->data().toInt(); + if (id == LAST_ADDRESS_INDEX) + { + id = config_->getItemValue("global", "lastaddrindex").toInt(); + } + + FQTermParam param; + + // FIXME: don't know the relation with id and param setted by setItemParameter + if (loadAddress(pConf, id, param)) { + newWindow(param, id); + } + delete pConf; +} + + +bool FQTermFrame::eventFilter(QObject *o, QEvent *e) { + return false; +} + +void FQTermFrame::closeEvent(QCloseEvent *clse) { + if (FQTermPref::getInstance()->openMinimizeToTray_ && + windowManager_->count() > 0) { + trayHide(); + clse->ignore(); + return ; + } + if (!clearUp()) + { + clse->ignore(); + return; + } + + clse->accept(); + + deleteLater(); +} + +void FQTermFrame::langEnglish() { + installTranslator("en_US"); +} + +void FQTermFrame::connectIt() { + if (windowManager_->activeWindow() == NULL) { + FQTermParam param; + FQTermConfig *pConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg"); + + loadAddress(pConf, -1, param); + delete pConf; + newWindow(param); + } else if (!windowManager_->activeWindow()->isConnected()) { + windowManager_->activeWindow()->getSession()->reconnect(); + } +} + +void FQTermFrame::disconnect() { + FQTermWindow* aw = windowManager_->activeWindow(); + if (aw) { + aw->disconnect(); + } +} + +void FQTermFrame::copy() { + windowManager_->activeWindow()->copy(); +} + +void FQTermFrame::paste() { + windowManager_->activeWindow()->paste(); +} + +void FQTermFrame::searchIt() +{ + windowManager_->activeWindow()->searchIt(); +} + +void FQTermFrame::shareIt() +{ + windowManager_->activeWindow()->shareIt(); +} + +void FQTermFrame::externalEditor() { + windowManager_->activeWindow()->externalEditor(); +} + +void FQTermFrame::fastPost() { + windowManager_->activeWindow()->fastPost(); +} + +void FQTermFrame::copyRect() { + windowManager_->activeWindow()->getSession()->param().isRectSelect_ + = !windowManager_->activeWindow()->getSession()->param().isRectSelect_; + + getAction(FQTermShortcutHelper::RECTANGLESELECTION)->setChecked( + windowManager_->activeWindow()->getSession()->param().isRectSelect_); +} + +void FQTermFrame::copyColor() { + windowManager_->activeWindow()->getSession()->param().isColorCopy_ + = !windowManager_->activeWindow()->getSession()->param().isColorCopy_; + + getAction(FQTermShortcutHelper::COPYWITHCOLOR)->setChecked( + windowManager_->activeWindow()->getSession()->param().isColorCopy_); +} + +void FQTermFrame::copyArticle() { + windowManager_->activeWindow()->copyArticle(); +} + +void FQTermFrame::autoCopy() { + windowManager_->activeWindow()->getSession()->param().isAutoCopy_ + = !windowManager_->activeWindow()->getSession()->param().isAutoCopy_; + + getAction(FQTermShortcutHelper::AUTOCOPYSELECTION)->setChecked( + windowManager_->activeWindow()->getSession()->param().isAutoCopy_); +} + +void FQTermFrame::wordWrap() { + windowManager_->activeWindow()->getSession()->param().isAutoWrap_ + = !windowManager_->activeWindow()->getSession()->param().isAutoWrap_; + + getAction(FQTermShortcutHelper::PASTEWORDWRAP)->setChecked( + windowManager_->activeWindow()->getSession()->param().isAutoWrap_); +} + +void FQTermFrame::noEsc() { + FQTermPref::getInstance()->escapeString_ = ""; + getAction(FQTermShortcutHelper::COLORCTL_NO)->setChecked(true); + getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false); +} + +void FQTermFrame::escEsc() { + FQTermPref::getInstance()->escapeString_ = "^[^[["; + getAction(FQTermShortcutHelper::COLORCTL_SMTH)->setChecked(true); + getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false); +} + +void FQTermFrame::uEsc() { + FQTermPref::getInstance()->escapeString_ = "^u["; + getAction(FQTermShortcutHelper::COLORCTL_PTT)->setChecked(true); + getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false); +} + +void FQTermFrame::oldCustomEsc() { +} + +void FQTermFrame::customEsc() { + QString strEsc(FQTermPref::getInstance()->escapeString_); + DefineEscapeDialog defineEscapeDialog_(strEsc, this); + if (defineEscapeDialog_.exec() == 1) + { + FQTermPref::getInstance()->escapeString_ = strEsc; + QAction *pAction = getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM); + if (strEsc != QString("") && strEsc != QString("^[^[[") && strEsc != QString("^u[")) + { + QString transStrEsc; + transEscapeStr(transStrEsc, strEsc); + pAction->setText(transStrEsc); + pAction->setVisible(true); + pAction->setChecked(true); + } + else + { + pAction->setVisible(false); + } + } +} + +bool FQTermFrame::isDelimiterExistedBefore(const QString& str, + const std::vector& existingDelimiters) { + for (std::vector::const_iterator cit = existingDelimiters.begin(); + cit != existingDelimiters.end(); + ++cit) + { + if (str.right(cit->length()) == *cit) + { + return true; + } + } + return false; +} + +int FQTermFrame::isDelimiterExistedAfter(const QString& str, + const std::vector& existingDelimiters) { + for (std::vector::const_iterator cit = existingDelimiters.begin(); + cit != existingDelimiters.end(); + ++cit) + { + if (str.left(cit->length()) == *cit) + { + return cit->length(); + } + } + return 0; +} + +bool FQTermFrame::uppercaseCharFollowingCtrl(QString& str, + int& i, + const QString& after) { + if (after == QString("Ctrl") && + str[i] > 'a' - 1 && + str[i] < 'z' - 1) + { + str[i] = str[i].toUpper(); + ++i; + return true; + } + else + { + return false; + } +} + +void FQTermFrame::replaceEscapeString(QString& str, + const QString& before, + const QString& after, + const QString& delimiter, + const std::vector *existingDelimiters /* = NULL */) { + bool preMatched = false; + int i = 0; + while (i < str.length()) + { + bool matched = true; + for (int j = 0; j < before.length(); ++j) + { + if (str[i + j] != before[j]) + { + matched = false; + break; + } + }// end of for + if (matched) + { + if (i == 0) + { + // the matched string is the head of the string + str = after + delimiter + str.right(str.length() - before.length()); + i = after.length() + delimiter.length(); + bool changed = uppercaseCharFollowingCtrl(str, i, after); + preMatched = !changed; + } + else if (i == str.length() - before.length()) + { + // the matched string is the tail of the string + if (existingDelimiters != NULL && + isDelimiterExistedBefore(str.left(i), *existingDelimiters)) + { + preMatched = true; + } + + if (preMatched) + { + str = str.left(i) + after; + } + else + { + str = str.left(i) + delimiter + after; + } + break; + } + else + { + // the matched string is at the middle of the string + if (existingDelimiters != NULL && + isDelimiterExistedBefore(str.left(i), *existingDelimiters)) + { + preMatched = true; + } + + if (preMatched) + { + str = str.left(i) + after + delimiter + str.right(str.length() - i - before.length()); + i += after.length() + delimiter.length(); + } + else + { + str = str.left(i) + delimiter + after + delimiter + str.right(str.length() - i - before.length()); + i += after.length() + 2 * delimiter.length(); + } + bool changed = uppercaseCharFollowingCtrl(str, i, after); + preMatched = !changed; + } + if (preMatched) + { + int len; + if (existingDelimiters != NULL && + (len = isDelimiterExistedAfter(str.right(str.length() - i), *existingDelimiters)) != 0) + { + str = str.left(i) + str.right(str.length() - i - len); + } + } + } + else + { + preMatched = false; + ++i; + } + }// end of while +} + +void FQTermFrame::transEscapeStr(QString& target, const QString& source) { + const QChar cSpecial(17); + target = source; + replaceEscapeString(target, QString("^["), QString("ESC"), QString(cSpecial)); + std::vector existingDelimiters; + existingDelimiters.push_back(QString(cSpecial)); + replaceEscapeString(target, QString("^"), QString("Ctrl"), QString("+"), &existingDelimiters); + target.replace(cSpecial, QChar(' ')); +} + +void FQTermFrame::setColor() { + windowManager_->activeWindow()->setColor(); +} + +void FQTermFrame::refreshScreen() { + windowManager_->activeWindow()->forcedRepaintScreen(); +} + +void FQTermFrame::uiFont() { + bool ok; + QFont font = QFontDialog::getFont(&ok, qApp->font()); + + if (FQTermPref::getInstance()->openAntiAlias_) { + font.setStyleStrategy(QFont::PreferAntialias); + } + + if (ok == true) { + qApp->setFont(font); + //refresh style sheet + if (FQTermPref::getInstance()->useStyleSheet_) { + refreshStyleSheet(); + } + imageViewer_->adjustItemSize(); + } +} + +void FQTermFrame::fullscreen() { + + + if (!(windowState() & Qt::WindowFullScreen)) { + menuBar()->hide(); + toolBarMdiTools_->hide(); + toolBarMdiConnectTools_->hide(); + toolBarSetupKeys_->hide(); + toolBarFonts_->hide(); + hideScroll(); + showSwitchBar(); + showFullScreen(); + } else { + menuBar()->show(); + toolBarMdiTools_->show(); + toolBarMdiConnectTools_->show(); + toolBarSetupKeys_->show(); + toolBarFonts_->show(); + emit updateScroll(); + showSwitchBar(); + showNormal(); + } + +} + +void FQTermFrame::bosscolor() { + FQTermPref::getInstance()->isBossColor_ = !FQTermPref::getInstance()->isBossColor_; + emit bossColor(); + getAction(FQTermShortcutHelper::BOSSCOLOR)->setChecked(FQTermPref::getInstance()->isBossColor_); +} + + +void FQTermFrame::toggleServer(bool on) { + FQTermPref::getInstance()->runServer_ = on; + if (on) { + serverThread_->start(); + } else { + serverThread_->quit(); + serverThread_->wait(1000); + } +} + +void FQTermFrame::themesMenuAboutToShow() { + QVector vectorShortcutKeys; + menuThemes_->clear(); + QStringList styles = QStyleFactory::keys(); + for (QStringList::ConstIterator it = styles.begin(); + it != styles.end(); it++) { + QString strTheme = *it; + for (int i = 0; i < strTheme.length(); ++i) + { + if (vectorShortcutKeys.indexOf(strTheme.at(i)) == -1) + { + vectorShortcutKeys.append(strTheme.at(i)); + strTheme.insert(i, QChar('&')); + break; + } + } + insertThemeItem(strTheme); + } +#ifdef USE_DOTNET_STYLE + insertThemeItem("Office"); //javaboy@newsmth.org +#endif //USE_DOTNET_STYLE +} + +void FQTermFrame::themesMenuActivated() { + theme_ = ((QAction*)QObject::sender())->text().remove(QChar('&')); + QStyle *style; +#ifdef USE_DOTNET_STYLE + //javaboy@newsmth.org + if (theme_ == "Office") + style = new DotNetStyle(DotNetStyle::Office); + else +#endif //USE_DOTNET_STYLE + style = QStyleFactory::create(theme_); + if (style) { + qApp->setStyle(style); + } +} + + + +void FQTermFrame::hideScroll() { + FQTermPref::getInstance()->termScrollBarPosition_ = 0; + emit updateScroll(); +} + +void FQTermFrame::leftScroll() { + FQTermPref::getInstance()->termScrollBarPosition_ = 1; + emit updateScroll(); +} + +void FQTermFrame::rightScroll() { + FQTermPref::getInstance()->termScrollBarPosition_ = 2; + emit updateScroll(); +} + +void FQTermFrame::setSE(const QString& se) { + FQTermPref::getInstance()->searchEngine_ = se; + config_->setItemValue("preference", "searchengine", se); +} + +void FQTermFrame::setSEGoogle() { + setSE("google"); +} +void FQTermFrame::setSEBaidu(){ + setSE("baidu"); +} +void FQTermFrame::setSEYahoo() { + setSE("yahoo"); +} +void FQTermFrame::setSEBing() { + setSE("bing"); +} +void FQTermFrame::setSECustom(){ + setSE("custom"); +} + +void FQTermFrame::showSwitchBar() { + isTabBarShown_ = !isTabBarShown_; + getAction(FQTermShortcutHelper::SWITCHBAR)->setChecked(isTabBarShown_); + + if (isTabBarShown_) { + statusBar()->show(); + } else { + statusBar()->hide(); + } +} + +void FQTermFrame::setting() { + windowManager_->activeWindow()->setting(); + updateMenuToolBar(); +} + +void FQTermFrame::saveSessionSetting() { + windowManager_->activeWindow()->saveSetting(false); +} + +void FQTermFrame::defaultSetting() { + FQTermConfig *pConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg"); + FQTermParam tmpParam; + + if (pConf->hasSection("default")) { + loadAddress(pConf, -1, tmpParam); + } + + addrDialog set(this, tmpParam, addrDialog::SAVE); + + if (set.exec() == 2) { + saveAddress(pConf, -1, set.param()); + pConf->save(getPath(USER_CONFIG) + "address.cfg"); + } + + delete pConf; +} + +void FQTermFrame::preference() { + prefDialog pref(config_, this); + bool styleSheetUsed = FQTermPref::getInstance()->useStyleSheet_; + + if (pref.exec() == 1) { + //TODO: refactor + loadPref(); + setUseDock(FQTermPref::getInstance()->openMinimizeToTray_); + if (FQTermPref::getInstance()->useStyleSheet_) { + loadStyleSheetFromFile(FQTermPref::getInstance()->styleSheetFile_); + } + else if (styleSheetUsed) { + clearStyleSheet(); + } + } + emit fontAntiAliasing(FQTermPref::getInstance()->openAntiAlias_); +} + +void FQTermFrame::shortcutSetting() { + int act = windowManager_->activeWindowIndex(); + FQTermShortcutDialog fsd(shortcutHelper_, this); + fsd.exec(); + windowManager_->activateTheWindow(act); +} + +void FQTermFrame::keySetup() { + keyDialog keyDlg(config_, this); + if (keyDlg.exec() == 1) { + updateKeyToolBar(); + } +} + + +void FQTermFrame::ipLookup() { + IPLookupDialog ipLookupDialog_(this); + ipLookupDialog_.exec(); +} + +void FQTermFrame::antiIdle() { + windowManager_->activeWindow()->toggleAntiIdle(); + getAction(FQTermShortcutHelper::ANTIIDLE)->setChecked( + windowManager_->activeWindow()->getSession()->isAntiIdle()); +} + +void FQTermFrame::autoReply() { + windowManager_->activeWindow()->toggleAutoReply(); + getAction(FQTermShortcutHelper::AUTOREPLY)->setChecked( + windowManager_->activeWindow()->getSession()->isAutoReply()); +} + +void FQTermFrame::viewMessages() { + windowManager_->activeWindow()->viewMessages(); +} + +void FQTermFrame::enableMouse() { + windowManager_->activeWindow()->getSession()->param().isSupportMouse_ + = !windowManager_->activeWindow()->getSession()->param().isSupportMouse_; + getAction(FQTermShortcutHelper::MOUSESUPPORT)->setChecked( + windowManager_->activeWindow()->getSession()->param().isSupportMouse_); +} + +void FQTermFrame::viewImages(QString filename, bool raiseViewer) { + if (filename.isEmpty()) { + filename = FQTermPref::getInstance()->poolDir_; + } + + if (raiseViewer) { + imageViewer_->scrollTo(filename); + if (imageViewer_->isHidden()) { + imageViewer_->resize(size() * 3 / 4 + QSize(1,1)); + imageViewer_->show(); + } + clearFocus(); + imageViewer_->raise(); + imageViewer_->activateWindow(); + } else { + imageViewer_->updateImage(filename); + } +} + +void FQTermFrame::viewImages() { + viewImages(FQTermPref::getInstance()->poolDir_, true); +} + +void FQTermFrame::beep() { + windowManager_->activeWindow()->getSession()->param().isBeep_ = + !windowManager_->activeWindow()->getSession()->param().isBeep_; + getAction(FQTermShortcutHelper::BEEP)->setChecked(windowManager_->activeWindow()->getSession()->param().isBeep_); +} + +void FQTermFrame::reconnect() { + FQTermWindow * qtw = windowManager_->activeWindow(); + if (qtw){ + qtw->toggleAutoReconnect(); + } +} + + +void FQTermFrame::delayedRunScript() { + windowManager_->activeWindow()->runScript(); +} + + +void FQTermFrame::runScript() { + QTimer::singleShot(1, this, SLOT(delayedRunScript())); +} + +void FQTermFrame::stopScript() { + windowManager_->activeWindow()->stopScript(); +} + + +void FQTermFrame::runPyScript() { +#ifdef HAVE_PYTHON + windowManager_->activeWindow()->runPythonScript(); +#endif //HAVE_PYTHON +} + +bool FQTermFrame::event(QEvent *e) { + + static bool shown = false; + if (e->type() == QEvent::WindowStateChange) { + if ((((QWindowStateChangeEvent*)(e))->oldState() & Qt::WindowMinimized) + && !(windowState() & Qt::WindowMinimized)) { + shown = true; + } + if (!(windowState() & Qt::WindowMinimized)) + { + config_->setItemValue("global", "max", (windowState() & Qt::WindowMaximized) ? "1" : "0"); + config_->setItemValue("global", "fullscreen", (windowState() & Qt::WindowFullScreen) ? "1" : "0"); + } + } + if (e->type() == QEvent::Paint && shown) { + shown = false; + qApp->setActiveWindow(NULL); + qApp->setActiveWindow(this); + } + + bool res = this->QMainWindow::event(e); + + if (e->type() == QEvent::HoverMove + || e->type() == QEvent::MouseMove + || e->type() == QEvent::Move) { + if (res) { + FQ_TRACE("frameEvent", 10) << "Accept event: " << e->type() + << " " << getEventName(e->type()) << "."; + } else { + FQ_TRACE("frameEvent", 10) << "Ignore event: " << e->type() + << " " << getEventName(e->type()) << "."; + } + } else { + if (res) { + FQ_TRACE("frameEvent", 9) << "Accept event: " << e->type() + << " " << getEventName(e->type()) << "."; + } else { + FQ_TRACE("frameEvent", 9) << "Ignore event: " << e->type() + << " " << getEventName(e->type()) << "."; + } + } + + return res; +} + +void FQTermFrame::keyClicked(int id) { + if (windowManager_->activeWindow() == NULL) { + return ; + } + + QString strItem = QString("key%1").arg(id); + QString strTmp = config_->getItemValue("key", strItem); + + if (strTmp[0] == '0') { // key + windowManager_->activeWindow()->externInput(strTmp.mid(1)); + } else if (strTmp[0] == '1') { // script + QString scriptFile = strTmp.mid(1).trimmed(); +#ifdef HAVE_PYTHON + if (scriptFile.endsWith(".py", Qt::CaseInsensitive)) + windowManager_->activeWindow()->runPythonScriptFile(scriptFile); + else +#endif + windowManager_->activeWindow()->runScript(scriptFile.toAscii()); + } else if (strTmp[0] == '2') { // program + runProgram(strTmp.mid(1)); + } +} + +void FQTermFrame::addMainTool() { + // the main toolbar + toolBarMdiTools_ = addToolBar("Main ToolBar"); + toolBarMdiTools_->setObjectName("Main ToolBar"); + + connectButton_ = new QToolButton(toolBarMdiTools_); + connectButton_->setIcon(QPixmap(getPath(RESOURCE) + "pic/connect.png")); + + toolBarMdiTools_->addWidget(connectButton_); + menuConnect_ = new QMenu(this); + //FIXME: autoupdate menu + FQ_VERIFY(connect(menuConnect_, SIGNAL(aboutToShow()), + this, SLOT(popupConnectMenu()))); + connectButton_->setMenu(menuConnect_); + connectButton_->setPopupMode(QToolButton::InstantPopup); + + toolBarMdiTools_->addAction(getAction(FQTermShortcutHelper::QUICKLOGIN)); + + serverButton_ = new QToolButton(toolBarMdiTools_); + serverButton_->setCheckable(true); + serverButton_->setIcon(QPixmap(getPath(RESOURCE) + "pic/fqterm_32x32.png")); + serverButton_->setChecked(FQTermPref::getInstance()->runServer_); + FQ_VERIFY(connect(serverButton_, SIGNAL(toggled(bool)), this, SLOT(toggleServer(bool)))); + toolBarMdiTools_->addWidget(serverButton_); + // custom define + toolBarSetupKeys_ = addToolBar("Custom Key"); + toolBarSetupKeys_->setObjectName("Custom Key"); + + // the toolbar + toolBarMdiConnectTools_ = addToolBar("BBS operations"); + toolBarMdiConnectTools_->setObjectName("BBS operations"); + FQTERM_ADDACTION(toolBarMdiConnectTools_, DISCONNECT, this, disconnect); + getAction(FQTermShortcutHelper::DISCONNECT)->setEnabled(false); + toolBarMdiConnectTools_->addSeparator(); + + //Font Tool Bar + toolBarFonts_ = addToolBar("Font ToolBar"); + toolBarFonts_->setObjectName("Font ToolBar"); + + + + // Edit (5) + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::COPY)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::PASTE)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::COPYWITHCOLOR)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::RECTANGLESELECTION)); + toolBarMdiConnectTools_->addSeparator(); + + //Font + fontButton_ = new QToolButton(toolBarFonts_); + QAction* dummyAction = new QAction(QPixmap(getPath(RESOURCE) + "pic/change_fonts.png"), + tr("Set Terminal Fonts"), fontButton_); + fontButton_->setDefaultAction(dummyAction); + toolBarFonts_->addWidget(fontButton_); + fontButton_->setMenu(menuFont_); + fontButton_->setPopupMode(QToolButton::InstantPopup); + + toolBarFonts_->addSeparator(); + englishFontCombo_ = new QFontComboBox(toolBarFonts_); + otherFontCombo_ = new QFontComboBox(toolBarFonts_); + QLabel *englishFontLabel = new QLabel(toolBarFonts_); + englishFontLabel->setPixmap(QPixmap(getPath(RESOURCE) + "pic/english_font.png")); + toolBarFonts_->addWidget(englishFontLabel); + toolBarFonts_->addWidget(englishFontCombo_); + toolBarFonts_->addSeparator(); + QLabel *otherFontLabel = new QLabel(toolBarFonts_); + otherFontLabel->setPixmap(QPixmap(getPath(RESOURCE) + "pic/other_font.png")); + toolBarFonts_->addWidget(otherFontLabel); + toolBarFonts_->addWidget(otherFontCombo_); + FQ_VERIFY(connect(englishFontCombo_, SIGNAL(currentFontChanged(const QFont&)), + this, SLOT(comboFontChanged(const QFont&)))); + FQ_VERIFY(connect(otherFontCombo_, SIGNAL(currentFontChanged(const QFont&)), + this, SLOT(comboFontChanged(const QFont&)))); + + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::COLORSETTING)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::ANSICOLOR)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::REFRESHSCREEN)); + toolBarMdiConnectTools_->addSeparator(); + + // Option + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::CURRENTSETTING)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::SAVESETTING)); + toolBarMdiConnectTools_->addSeparator(); + + // Spec (5) + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::COPYARTICLE)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::ANTIIDLE)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::AUTOREPLY)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::VIEWMESSAGE)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::IMAGEVIEWER)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::MOUSESUPPORT)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::BEEP)); + toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::AUTORECONNECT)); + + //call popupConnectMenu() to enable the shortcuts + popupConnectMenu(); + + +} + + +QAction* FQTermFrame::getAction(int shortcut) { + if (!shortcutHelper_) + return NULL; + return shortcutHelper_->getAction(shortcut); +} + + + +void FQTermFrame::addMainMenu() { + menuMain_ = menuBar(); + + //File Menu + menuFile_ = menuMain_->addMenu(tr("&File")); + + FQTERM_ADDACTION(menuFile_, CONNECT, this, connectIt); + FQTERM_ADDACTION(menuFile_, DISCONNECT, this, disconnect); + menuFile_->addSeparator(); + FQTERM_ADDACTION(menuFile_, ADDRESSBOOK, this, addressBook); + FQTERM_ADDACTION(menuFile_, QUICKLOGIN, this, quickLogin); + menuFile_->addSeparator(); + FQTERM_ADDACTION(menuFile_, EXIT, this, exitFQTerm); + getAction(FQTermShortcutHelper::EXIT)->setMenuRole(QAction::QuitRole); + + //Edit Menu + QMenu *edit = menuMain_->addMenu(tr("&Edit")); + + FQTERM_ADDACTION(edit, COPY, this, copy); + FQTERM_ADDACTION(edit, PASTE, this, paste); + edit->addSeparator(); + FQTERM_ADDACTION(edit, COPYWITHCOLOR, this, copyColor); + FQTERM_ADDACTION(edit, RECTANGLESELECTION, this, copyRect); + FQTERM_ADDACTION(edit, AUTOCOPYSELECTION, this, autoCopy); + FQTERM_ADDACTION(edit, PASTEWORDWRAP, this, wordWrap); + edit->addSeparator(); + FQTERM_ADDACTION(edit, SEARCHIT, this, searchIt); + FQTERM_ADDACTION(edit, WEIBOSHARE, this, shareIt); + edit->addSeparator(); + FQTERM_ADDACTION(edit, EXTERNALEDITOR, this, externalEditor); + edit->addSeparator(); + FQTERM_ADDACTION(edit, FASTPOST, this, fastPost); + edit->addSeparator(); + + QMenu *escapeMenu = edit->addMenu(tr("Control sequence in clipboar&d")); + escapeGroup = new QActionGroup(this); + FQTERM_ADDACTION(escapeMenu, COLORCTL_NO,this, noEsc); + escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_NO)); + FQTERM_ADDACTION(escapeMenu, COLORCTL_SMTH,this, escEsc); + escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_SMTH)); + FQTERM_ADDACTION(escapeMenu, COLORCTL_PTT,this, uEsc); + escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_PTT)); + FQTERM_ADDACTION(escapeMenu, COLORCTL_OLD_CUSTOM,this, oldCustomEsc); + escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)); + FQTERM_ADDACTION(escapeMenu, COLORCTL_CUSTOM,this, customEsc); + escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_CUSTOM)); + + //View menu + QMenu *view = menuMain_->addMenu(tr("&View")); + + menuFont_ = view->addMenu(tr("&Font")); + menuFont_->setIcon(QPixmap(getPath(RESOURCE) + "pic/change_fonts.png")); + view->addMenu(menuFont_); + FQTERM_ADDACTION(menuFont_, OTHERFONT, this, setFont); + getAction(FQTermShortcutHelper::OTHERFONT)->setData(0); + FQTERM_ADDACTION(menuFont_, ENGLISHFONT, this, setFont); + getAction(FQTermShortcutHelper::ENGLISHFONT)->setData(1); + FQTERM_ADDACTION(view, COLORSETTING, this, setColor); + FQTERM_ADDACTION(view, ANSICOLOR, this, toggleAnsiColor); + FQTERM_ADDACTION(view, REFRESHSCREEN, this, refreshScreen); + view->addSeparator(); + + //language menu + languageGroup = new QActionGroup(view); + languageGroup->setExclusive(true); + if (installerList_.isEmpty()) { + FQ_TRACE("frame", 0) + << "No language menu because of lack of translation files"; + } else { + menuLanguage_ = view->addMenu(tr("&Language")); + FQTERM_ADDACTION(menuLanguage_, LANGUAGE_ENGLISH, this, langEnglish); + languageGroup->addAction(getAction(FQTermShortcutHelper::LANGUAGE_ENGLISH)); + + foreach(TranslatorInstaller* installer, installerList_) { + QAction* action = menuLanguage_->addAction( + installer->languageName(), installer, SLOT(installTranslator())); + action->setCheckable(true); + languageGroup->addAction(action); + } + + } + + FQTERM_ADDACTION(view, UIFONT, this, uiFont); + + menuThemes_ = view->addMenu(tr("&Themes")); + FQ_VERIFY(connect(menuThemes_, SIGNAL(aboutToShow()), this, SLOT(themesMenuAboutToShow()))); + + FQTERM_ADDACTION(view, FULLSCREEN, this, fullscreen); + FQTERM_ADDACTION(view, BOSSCOLOR, this, bosscolor); + + view->addSeparator(); + + QMenu *scrollMenu = view->addMenu(tr("&ScrollBar")); + scrollGroup = new QActionGroup(this); + FQTERM_ADDACTION(scrollMenu, SCROLLBAR_HIDDEN,this, hideScroll); + scrollGroup->addAction(getAction(FQTermShortcutHelper::SCROLLBAR_HIDDEN)); + FQTERM_ADDACTION(scrollMenu, SCROLLBAR_RIGHT,this, rightScroll); + scrollGroup->addAction(getAction(FQTermShortcutHelper::SCROLLBAR_RIGHT)); + FQTERM_ADDACTION(scrollMenu, SCROLLBAR_LEFT,this, leftScroll); + scrollGroup->addAction(getAction(FQTermShortcutHelper::SCROLLBAR_LEFT)); + + FQTERM_ADDACTION(view, SWITCHBAR, this, showSwitchBar); + // Option Menu + QMenu *option = menuMain_->addMenu(tr("&Option")); + + FQTERM_ADDACTION(option, CURRENTSETTING, this, setting); + FQTERM_ADDACTION(option, SAVESETTING, this, saveSessionSetting); + option->addSeparator(); + FQTERM_ADDACTION(option, DEFAULTSETTING, this, defaultSetting); +#ifdef Q_OS_MAC + FQTERM_ADDACTION(menuFile_, PREFERENCE, this, preference); +#else + FQTERM_ADDACTION(option, PREFERENCE, this, preference); +#endif + getAction(FQTermShortcutHelper::PREFERENCE)->setMenuRole(QAction::PreferencesRole); + FQTERM_ADDACTION(option, SHORTCUTSETTING, this, shortcutSetting); + option->addSeparator(); + FQTERM_ADDACTION(option, EDITSCHEMA, this, editSchema); + option->addSeparator(); + + QMenu *searchEngineMenu = option->addMenu(tr("Searc&h Engine")); + searchEngineGroup = new QActionGroup(this); + FQTERM_ADDACTION(searchEngineMenu, SEARCH_GOOGLE,this, setSEGoogle); + searchEngineGroup->addAction(getAction(FQTermShortcutHelper::SEARCH_GOOGLE)); + FQTERM_ADDACTION(searchEngineMenu, SEARCH_BAIDU,this, setSEBaidu); + searchEngineGroup->addAction(getAction(FQTermShortcutHelper::SEARCH_BAIDU)); + FQTERM_ADDACTION(searchEngineMenu, SEARCH_BING,this, setSEBing); + searchEngineGroup->addAction(getAction(FQTermShortcutHelper::SEARCH_BING)); + FQTERM_ADDACTION(searchEngineMenu, SEARCH_YAHOO,this, setSEYahoo); + searchEngineGroup->addAction(getAction(FQTermShortcutHelper::SEARCH_YAHOO)); + FQTERM_ADDACTION(searchEngineMenu, SEARCH_CUSTOM,this, setSECustom); + searchEngineGroup->addAction(getAction(FQTermShortcutHelper::SEARCH_CUSTOM)); + + // Special + QMenu *spec = menuMain_->addMenu(tr("&Special")); + FQTERM_ADDACTION(spec, COPYARTICLE, this, copyArticle); + FQTERM_ADDACTION(spec, ANTIIDLE, this, antiIdle); + FQTERM_ADDACTION(spec, AUTOREPLY, this, autoReply); + FQTERM_ADDACTION(spec, VIEWMESSAGE, this, viewMessages); + FQTERM_ADDACTION(spec, BEEP, this, beep); + FQTERM_ADDACTION(spec, MOUSESUPPORT, this, enableMouse); + FQTERM_ADDACTION(spec, IMAGEVIEWER, this, viewImages); + FQTERM_ADDACTION(spec, IPLOOKUP, this, ipLookup); + + //Script + QMenu *script = menuMain_->addMenu(tr("Scrip&t")); + FQTERM_ADDACTION(script, RUNSCRIPT, this, runScript); + FQTERM_ADDACTION(script, STOPSCRIPT, this, stopScript); +#ifdef HAVE_PYTHON + script->addSeparator(); + FQTERM_ADDACTION(script, RUNPYTHONSCRIPT, this, runPyScript); +#endif //HAVE_PYTHON + + //Window menu + menuWindows_ = menuMain_->addMenu(tr("&Windows")); + FQ_VERIFY(connect(menuWindows_, SIGNAL(aboutToShow()),this, SLOT(windowsMenuAboutToShow()))); + menuMain_->addSeparator(); + + //Help menu + QMenu *help = menuMain_->addMenu(tr("&Help")); + FQTERM_ADDACTION(help, ABOUT, this, aboutFQTerm); + getAction(FQTermShortcutHelper::ABOUT)->setMenuRole(QAction::AboutRole); + FQTERM_ADDACTION(help, HOMEPAGE, this, homepage); +} + +void FQTermFrame::updateMenuToolBar() { + FQTermWindow *window = windowManager_->activeWindow(); + + if (window == NULL) { + return ; + } + + // update menu + getAction(FQTermShortcutHelper::DISCONNECT)->setEnabled(window->isConnected()); + getAction(FQTermShortcutHelper::COPYWITHCOLOR)->setChecked(window->getSession()->param().isColorCopy_); + getAction(FQTermShortcutHelper::RECTANGLESELECTION)->setChecked(window->getSession()->param().isRectSelect_); + getAction(FQTermShortcutHelper::AUTOCOPYSELECTION)->setChecked(window->getSession()->param().isAutoCopy_); + getAction(FQTermShortcutHelper::PASTEWORDWRAP)->setChecked(window->getSession()->param().isAutoWrap_); + getAction(FQTermShortcutHelper::FULLSCREEN)->setChecked(windowState() & Qt::WindowFullScreen); + getAction(FQTermShortcutHelper::ANSICOLOR)->setChecked(window->getSession()->param().isAnsiColor_); + getAction(FQTermShortcutHelper::ANTIIDLE)->setChecked(window->getSession()->isAntiIdle()); + getAction(FQTermShortcutHelper::AUTOREPLY)->setChecked(window->getSession()->isAutoReply()); + getAction(FQTermShortcutHelper::BEEP)->setChecked(window->getSession()->param().isBeep_); + getAction(FQTermShortcutHelper::MOUSESUPPORT)->setChecked(window->getSession()->param().isSupportMouse_); + getAction(FQTermShortcutHelper::AUTORECONNECT)->setChecked(window->getSession()->param().isAutoReconnect_); + + updateFontCombo(); +} + +void FQTermFrame::updateFontCombo() { + FQTermWindow *window = windowManager_->activeWindow(); + + if (window == NULL) { + return ; + } + englishFontCombo_->blockSignals(true); + otherFontCombo_->blockSignals(true); + englishFontCombo_->setCurrentFont(window->getScreen()->termFont(true)); + otherFontCombo_->setCurrentFont(window->getScreen()->termFont(false)); + englishFontCombo_->blockSignals(false); + otherFontCombo_->blockSignals(false); +} + +void FQTermFrame::termFontChange(bool isEnglish, QFont font) { + updateFontCombo(); +} + +void FQTermFrame::comboFontChanged(const QFont & font) { + + FQTermWindow *window = windowManager_->activeWindow(); + + if (window == NULL) { + return ; + } + + window->getScreen()->blockSignals(true); + + bool isEnglish = (sender() == (QObject*)englishFontCombo_); + + QString& fontName = isEnglish? + window->getSession()->param().englishFontName_:window->getSession()->param().otherFontName_; + int& fontSize = isEnglish? + window->getSession()->param().englishFontSize_:window->getSession()->param().otherFontSize_; + QFontComboBox* combo = isEnglish ? englishFontCombo_ : otherFontCombo_; + + QFont f(combo->currentFont().family(), window->getScreen()->termFont(true).pointSize()); + + window->getScreen()->setTermFont(isEnglish, f); + + fontName = f.family(); + fontSize = f.pointSize(); + + window->getScreen()->blockSignals(false); + + window->forcedRepaintScreen(); +} + +void FQTermFrame::enableMenuToolBar(bool enable) { + getAction(FQTermShortcutHelper::DISCONNECT)->setEnabled(enable); + getAction(FQTermShortcutHelper::COPY)->setEnabled(enable); + getAction(FQTermShortcutHelper::PASTE)->setEnabled(enable); + getAction(FQTermShortcutHelper::COPYWITHCOLOR)->setEnabled(enable); + getAction(FQTermShortcutHelper::RECTANGLESELECTION)->setEnabled(enable); + getAction(FQTermShortcutHelper::AUTOCOPYSELECTION)->setEnabled(enable); + getAction(FQTermShortcutHelper::PASTEWORDWRAP)->setEnabled(enable); + getAction(FQTermShortcutHelper::ANSICOLOR)->setEnabled(enable); + + fontButton_->setEnabled(enable); + englishFontCombo_->setEnabled(enable); + otherFontCombo_->setEnabled(enable); + menuFont_->setEnabled(enable); + + getAction(FQTermShortcutHelper::COLORSETTING)->setEnabled(enable); + getAction(FQTermShortcutHelper::REFRESHSCREEN)->setEnabled(enable); + getAction(FQTermShortcutHelper::CURRENTSETTING)->setEnabled(enable); + getAction(FQTermShortcutHelper::SAVESETTING)->setEnabled(enable); + getAction(FQTermShortcutHelper::COPYARTICLE)->setEnabled(enable); + getAction(FQTermShortcutHelper::ANTIIDLE)->setEnabled(enable); + getAction(FQTermShortcutHelper::AUTOREPLY)->setEnabled(enable); + getAction(FQTermShortcutHelper::VIEWMESSAGE)->setEnabled(enable); + getAction(FQTermShortcutHelper::BEEP)->setEnabled(enable); + getAction(FQTermShortcutHelper::MOUSESUPPORT)->setEnabled(enable); + getAction(FQTermShortcutHelper::RUNSCRIPT)->setEnabled(enable); + getAction(FQTermShortcutHelper::STOPSCRIPT)->setEnabled(enable); +#ifdef HAVE_PYTHON + getAction(FQTermShortcutHelper::RUNPYTHONSCRIPT)->setEnabled(enable); +#endif + getAction(FQTermShortcutHelper::SEARCHIT)->setEnabled(enable); + getAction(FQTermShortcutHelper::WEIBOSHARE)->setEnabled(enable); + getAction(FQTermShortcutHelper::EXTERNALEDITOR)->setEnabled(enable); + getAction(FQTermShortcutHelper::FASTPOST)->setEnabled(enable); +} + +void FQTermFrame::updateKeyToolBar() { + toolBarSetupKeys_->clear(); + toolBarSetupKeys_->addAction(QPixmap(getPath(RESOURCE) + "pic/setup_shortcuts.png"), + tr("Key Setup"), this, SLOT(keySetup())); + + QString strItem, strTmp; + strTmp = config_->getItemValue("key", "num"); + int num = strTmp.toInt(); + + for (int i = 0; i < num; i++) { + strItem = QString("name%1").arg(i); + strTmp = config_->getItemValue("key", strItem); + FQTermToolButton *button = + new FQTermToolButton(toolBarSetupKeys_, i, strTmp); + button->setText(strTmp); + strItem = QString("key%1").arg(i); + strTmp = (config_->getItemValue("key", strItem)); + //TODO: add tool tip here + // QToolTip::add( button, strTmp.mid(1) ); + // button->addToolTip(strTmp.mid(1)); + + strTmp = config_->getItemValue("key", QString("shortcut%1").arg(i)); + if (!strTmp.isEmpty()) { + QAction *act = new QAction(button); + act->setShortcut(strTmp); + button->addAction(act); + FQ_VERIFY(connect(act, SIGNAL(triggered()), button, SLOT(slotClicked()))); + } + + FQ_VERIFY(connect(button, SIGNAL(buttonClicked(int)), + this, SLOT(keyClicked(int)))); + toolBarSetupKeys_->addWidget(button); + } + + + +} + + +void FQTermFrame::popupFocusIn(FQTermWindow*) { + // bring to font + if (isHidden()) { + show(); + } + if (isMinimized()) { + if (isMaximized()) { + showMaximized(); + } else { + showNormal(); + } + } + raise(); + activateWindow(); +} + +void FQTermFrame::insertThemeItem(const QString& themeitem) { + QAction *idAction; + + idAction = menuThemes_->addAction(themeitem, + this, SLOT(themesMenuActivated())); + idAction->setCheckable(true); + idAction->setChecked(themeitem == theme_); +} + +void FQTermFrame::setUseDock(bool use) { + if (use == false) { + if (tray_) { + tray_->hide(); + delete tray_; + tray_ = 0; + //delete menuTray_; + //menuTray_ = 0; + } + return ; + } + + if (tray_ || !QSystemTrayIcon::isSystemTrayAvailable()) { + return ; + } + + trayMenu_ = new QMenu; + FQ_VERIFY(connect(trayMenu_, SIGNAL(aboutToShow()), SLOT(buildTrayMenu()))); + + tray_ = new QSystemTrayIcon(this); + tray_->setIcon(QPixmap(getPath(RESOURCE) + "pic/fqterm_tray.png")); + tray_->setContextMenu(trayMenu_); + FQ_VERIFY(connect(tray_, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + SLOT(trayActived(QSystemTrayIcon::ActivationReason)))); + tray_->show(); +} + +void FQTermFrame::buildTrayMenu() { + if (!trayMenu_) { + return ; + } + trayMenu_->clear(); + + if (isHidden()) { + trayMenu_->addAction(tr("Show"), this, SLOT(trayShow())); + } else { + trayMenu_->addAction(tr("Hide"), this, SLOT(trayHide())); + } + trayMenu_->addSeparator(); + trayMenu_->addAction(tr("About"), this, SLOT(aboutFQTerm())); + trayMenu_->addAction(tr("Exit"), this, SLOT(exitFQTerm())); +} + +void FQTermFrame::trayActived(QSystemTrayIcon::ActivationReason reason) { + if (reason == QSystemTrayIcon::Context) { + return ; + } + if (!isVisible()) { + trayShow(); + } else { + trayHide(); + } +} + +void FQTermFrame::trayShow() { + show(); + // bring to font + if (isHidden()) { + show(); + } + if (isMinimized()) { + if (isMaximized()) { + showMaximized(); + } else { +#ifdef Q_OS_MACX + showMaximized(); +#else + showNormal(); +#endif + } + } + raise(); + activateWindow(); + FQTermWindow* window = windowManager_->activeWindow(); + if (window) { + window->forcedRepaintScreen(); + if (!window->isMaximized()) { + windowManager_->refreshAllExcept(window); + } + } +} + +void FQTermFrame::trayHide() { + static bool showTip = true; + QString str = config_->getItemValue("global", "traytipshown"); + if (str == "1") { + showTip = false; + } + hide(); + if (showTip && tray_) { + tray_->showMessage(tr("FQTerm"), + tr("FQTerm will keep running in the system tray.\n" + "To terminate the program, " + "choose exit in the tray menu.")); + showTip = false; + config_->setItemValue("global", "traytipshown", "1"); + } +} + +void FQTermFrame::buzz(FQTermWindow* window) { + if (windowManager_->activeWindow() == window) + return; + int xp = x(); + int yp = y(); + QTime t; + + t.start(); + for (int i = 32; i > 0;) { + if (t.elapsed() >= 1) { + int delta = i >> 2; + int dir = i &3; + int dx = ((dir == 1) || (dir == 2)) ? delta : -delta; + int dy = (dir < 2) ? delta : -delta; + move(xp + dx, yp + dy); + t.restart(); + i--; + } + } + move(xp, yp); +} + + +//-------------------------- +//recreate the main menu +//-------------------------- +void +FQTermFrame::recreateMenu() { + + if (shortcutHelper_) { + shortcutHelper_->retranslateActions(); + } + menuBar()->clear(); + delete escapeGroup; + delete languageGroup; + addMainMenu(); + updateLanguageMenu(); + + QString strTmp = QString(saveState().toHex()); + config_->setItemValue("global", "toolbarstate", strTmp); + config_->save(getPath(USER_CONFIG) + "fqterm.cfg"); + + delete toolBarMdiTools_; + delete toolBarSetupKeys_; + delete toolBarMdiConnectTools_; + delete toolBarFonts_; + delete menuConnect_; + addMainTool(); + updateKeyToolBar(); + loadToolBarPosition(); + if (!windowManager_->activeWindow()) { + enableMenuToolBar(false); + } else { + enableMenuToolBar(true); + updateMenuToolBar(); + } + if (FQTermPref::getInstance()->useStyleSheet_) { + refreshStyleSheet(); + } +} + +void FQTermFrame::installTranslator(const QString& lang) { + config_->setItemValue("global", "language", lang); + config_->save(getPath(USER_CONFIG) + "fqterm.cfg"); + + for (int i = 0; i < translatedModule; ++i) { + if (translator[i] != 0) { + qApp->removeTranslator(translator[i]); + delete translator[i]; + translator[i] = 0; + } + } + + if (lang != "en_US" && !lang.isEmpty()) { + for (int i = 0; i < translatedModule; ++i) { + QString dict = + getPath(RESOURCE) + "dict/" + qmPrefix[i] + lang + qmPostfix; + translator[i] = new QTranslator(0); + translator[i]->load(dict); + qApp->installTranslator(translator[i]); + } + } + + emit changeLanguage(); +} + +void FQTermFrame::initTranslator() { + QString dict_path = getPath(RESOURCE) + "dict/"; + QDir dictDir(dict_path); + QStringList langList; + + for (int i = 0; i < translatedModule; ++i) { + translator[i] = 0; + QStringList filter; + filter << qmPrefix[i] + "*" + qmPostfix; + dictDir.setNameFilters(filter); + QFileInfoList list = dictDir.entryInfoList(); + + FQ_TRACE("translator", 3) << "Found " << list.size() + << " " << qmPostfix + << " file(s) under path " + << dict_path; + + foreach(QFileInfo info, list){ + QString language = info.fileName(); + language = language.mid( + qmPrefix[i].length(), + language.length() - qmPrefix[i].length() - qmPostfix.length()); + + FQ_TRACE("translator", 3) << "Check file " << info.fileName(); + + if (!langList.contains(language)) { + langList << language; + installerList_.append(new TranslatorInstaller(language, this)); + FQ_TRACE("translator", 3) << "Found translations for " << language; + } else { + FQ_TRACE("translator", 3) << "Language " << language + << " is already registered."; + } + } + } + + if (installerList_.empty()) { + FQ_TRACE("translator", 0) << "No translations found."; + } + + QString lang = config_->getItemValue("global", "language"); + if (!langList.contains(lang)) { + lang = QLocale::system().name(); + } +#if defined(__linux__) || defined(__GLIBC__) + if (QLocale::system().language() == QLocale::English) + lang = QLocale::system().name(); +#endif + installTranslator(lang); +} + + +void FQTermFrame::clearTranslator() { + foreach(TranslatorInstaller* installer, installerList_){ + delete installer; + } +} + +void FQTermFrame::updateLanguageMenu() { + QString strTmp = config_->getItemValue("global", "language"); + int i = 0; + foreach(TranslatorInstaller* installer, installerList_){ + if (installer->languageFormalName() == strTmp) { + languageGroup->actions().at(i + 1)->setChecked(true); + break; + } + ++i; + } + if (!installerList_.isEmpty() && + (strTmp == "en_US" || i == installerList_.size())) { + languageGroup->actions().at(0)->setChecked(true); + } +} + +void FQTermFrame::setFont() { + bool isEnglish = (QAction*)(sender()) == getAction(FQTermShortcutHelper::ENGLISHFONT); + windowManager_->activeWindow()->setFont(isEnglish); +} + +void FQTermFrame::refreshStyleSheet() +{ + qApp->setStyleSheet(qApp->styleSheet()); +} +void FQTermFrame::loadStyleSheetFromFile( const QString qssFile ) +{ + QFile file(qssFile); + file.open(QIODevice::ReadOnly); + QString qss = file.readAll(); + qApp->setStyleSheet(qss); + file.close(); +} + +void FQTermFrame::clearStyleSheet() { + qApp->setStyleSheet(""); +} + +void FQTermFrame::loadToolBarPosition() +{ + //load toolbar setting + QString strTmp = config_->getItemValue("global", "toolbarstate"); + if (!strTmp.isEmpty()) + { + restoreState(QByteArray::fromHex(strTmp.toAscii())); + } else { + addToolBar(Qt::TopToolBarArea, toolBarMdiConnectTools_); + insertToolBar(toolBarMdiConnectTools_,toolBarSetupKeys_); + insertToolBar(toolBarSetupKeys_, toolBarMdiTools_); + insertToolBar(toolBarMdiTools_, toolBarFonts_); + } +} + +void FQTermFrame::toggleAnsiColor() { + windowManager_->activeWindow()->getSession()->param().isAnsiColor_ + = !windowManager_->activeWindow()->getSession()->param().isAnsiColor_; + getAction(FQTermShortcutHelper::ANSICOLOR)->setChecked( + windowManager_->activeWindow()->getSession()->param().isAnsiColor_); + refreshScreen(); +} + +bool FQTermFrame::clearUp() { + if (!windowManager_->closeAllWindow()) + return false; + + saveSetting(); + // clear zmodem and pool if needed + if (FQTermPref::getInstance()->needClearZmodemPoolOnClose_) { + clearDir(FQTermPref::getInstance()->zmodemDir_); + clearDir(FQTermPref::getInstance()->poolDir_); + clearDir(FQTermPref::getInstance()->poolDir_ + "shadow-cache/"); + } + + setUseDock(false); + + return true; +} + +void FQTermFrame::editSchema() { + + schemaDialog schema(this); + FQ_VERIFY(connect(&schema, SIGNAL(schemaEdited()), + this, SLOT(schemaUpdated()))); + schema.exec(); +} + +void FQTermFrame::schemaUpdated() { + for (int i = 0; i < windowManager_->count(); ++i) { + windowManager_->nthWindow(i)->getScreen()->setSchema(); + windowManager_->nthWindow(i)->forcedRepaintScreen(); + } +} + + +void FQTermFrame::globalHotkeyTriggered() { + if (isActiveWindow() && !isMinimized() && isVisible()) + { + showMinimized(); + return; + } + show(); + if (config_->getItemValue("global", "fullscreen") == "1") + showFullScreen(); + else if (config_->getItemValue("global", "max") == "1") + showMaximized(); + else + showNormal(); + raise(); + activateWindow(); +} + +void FQTermFrame::globalHotkeyChanged() +{ +#ifdef USE_GLOBAL_HOTKEY + globalHotkey_->setShortcut(shortcutHelper_->getAction(FQTermShortcutHelper::GLOBAL_SHOW_FQTERM)->shortcut()); +#endif //USE_GLOBAL_HOTKEY +} + + + +TranslatorInstaller::TranslatorInstaller(const QString& language, + FQTermFrame* frame) + : language_(language), + frame_(frame) { + FQTermConfig conf(getPath(USER_CONFIG) + "language.cfg"); + + languageName_ = conf.getItemValue("Name", language_); + if (languageName_.isEmpty()){ + languageName_ = QLocale::languageToString(QLocale(language_).language()); + if (languageName_ == "C") { + languageName_ = "Unknown Language"; + } + } +} + +QString TranslatorInstaller::languageName() { + return languageName_; +} + +void TranslatorInstaller::installTranslator() { + frame_->installTranslator(language_); +} + +QString TranslatorInstaller::languageFormalName() { + return language_; +} + +} // namespace FQTerm + +#include "fqterm_frame.moc" diff --git a/src/fqterm/fqterm_frame.h b/src/fqterm/fqterm_frame.h new file mode 100644 index 0000000..8adaf49 --- /dev/null +++ b/src/fqterm/fqterm_frame.h @@ -0,0 +1,326 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_FRAME_H +#define FQTERM_FRAME_H + +#include +#include +#include + +#include + +class QWidget; +class QLineEdit; +class QToolButton; +class QMdiArea; +class QSignalMapper; +class QTabBar; +class QFontDialog; +class QActionGroup; +class QString; +class QFontComboBox; +class UAOCodec; + +#ifdef USE_GLOBAL_HOTKEY +class QxtGlobalShortcut; +#endif //USE_GLOBAL_HOTKEY + +namespace FQTerm { + +class IPLookupDialog; +class DefineEscapeDialog; +class FQTermImage; +class FQTermParam; +class FQTermConfig; +class FQTermWndMgr; +class FQTermWindow; +class StatusBar; +class FQTermTimeLabel; +class TranslatorInstaller; +class FQTermMiniServerThread; +class FQTermShortcutHelper; + +#ifdef HAVE_PYTHON +class FQTermPythonHelper; +#endif //HAVE_PYTHON + +class FQTermFrame: public QMainWindow { + Q_OBJECT; + public: + FQTermFrame(); + ~FQTermFrame(); + + void updateMenuToolBar(); + void enableMenuToolBar(bool); + + void popupFocusIn(FQTermWindow*); + + void viewImages(QString filename, bool raiseViewer); + void buzz(FQTermWindow* window = NULL); + void installTranslator(const QString& lang); + FQTermConfig * config() const { return config_; } + + static const int translatedModule = 4; + static const QString qmPrefix[translatedModule]; + static const QString qmPostfix; + + signals: + void bossColor(); + void updateScroll(); + void changeLanguage(); + void fontAntiAliasing(bool); + + protected slots: + + bool event(QEvent *event); + + void viewImages(); + bool clearUp(); + + // Menu + void recreateMenu(); + void addressBook(); + void quickLogin(); + void exitFQTerm(); + + void aboutFQTerm(); + void langEnglish(); + void defaultSetting(); + void preference(); + void shortcutSetting(); + void runScript(); + void delayedRunScript(); // to avoid activate recursion guard + void stopScript(); + void runPyScript(); + void homepage(); + + void toggleAnsiColor(); + + // Toolbar + void keyClicked(int); + + void connectIt(); + void disconnect(); + void copy(); + void paste(); + void searchIt(); + void shareIt(); + void externalEditor(); + void fastPost(); + void copyRect(); + void copyColor(); + void copyArticle(); + void autoCopy(); + void wordWrap(); + void noEsc(); + void escEsc(); + void uEsc(); + void oldCustomEsc(); + void customEsc(); + void hideScroll(); + void leftScroll(); + void rightScroll(); + void setSEGoogle(); + void setSEBaidu(); + void setSEYahoo(); + void setSEBing(); + void setSECustom(); + void showSwitchBar(); + void setFont(); + void setColor(); + void refreshScreen(); + void fullscreen(); + void bosscolor(); + void toggleServer(bool on); + void uiFont(); + void antiIdle(); + void autoReply(); + void setting(); + void saveSessionSetting(); + void viewMessages(); + void enableMouse(); + void beep(); + void reconnect(); + void keySetup(); + void ipLookup(); + void termFontChange(bool isEnglish, QFont font); + void comboFontChanged(const QFont & font); + + void themesMenuAboutToShow(); + void themesMenuActivated(); + void windowsMenuAboutToShow(); + void connectMenuActivated(); + void popupConnectMenu(); + void trayActived(QSystemTrayIcon::ActivationReason); + + //void trayClicked(const QPoint &, int); + //void trayDoubleClicked(); + void trayHide(); + void trayShow(); + void buildTrayMenu(); + + void reloadConfig(); + + void saveSetting(); + void schemaUpdated(); + void editSchema(); + private: + + FQTermWndMgr *windowManager_; + // image viewer + FQTermImage *imageViewer_; + + FQTermTimeLabel *labelTime_; + + QString theme_; + + QActionGroup *escapeGroup; + QActionGroup *languageGroup; + QActionGroup *scrollGroup; + QActionGroup *searchEngineGroup; + QMenu *menuWindows_; + QMenu *menuThemes_; + QMenu *menuFont_; + QMenu *menuFile_; + QMenu *menuLanguage_; + QMenu *menuConnect_; + QSignalMapper* windowMapper_; + + FQTerm::StatusBar *statusBar_; + + QToolButton *serverButton_; + QToolButton *connectButton_; + QToolButton *fontButton_; + QFontComboBox *englishFontCombo_; + QFontComboBox *otherFontCombo_; + + QMenuBar *menuMain_; + QToolBar *toolBarMdiConnectTools_; + QToolBar *toolBarMdiTools_; + QToolBar *toolBarSetupKeys_; + QToolBar *toolBarFonts_; + + bool isTabBarShown_; + + QSystemTrayIcon *tray_; + + QMenu *trayMenu_; + + QTranslator * translator[translatedModule]; + QList installerList_; + + FQTermConfig * config_; + FQTermShortcutHelper * shortcutHelper_; + QAction* getAction(int shortcut); + FQTermMiniServerThread* serverThread_; + + UAOCodec* uaoCodec_; + +private: + void newWindow(const FQTermParam ¶m, int index = -1); + + void closeEvent(QCloseEvent*); + void selectStyleMenu(int, int); + void iniSetting(); + void loadPref(); + + void addMainMenu(); + void addMainTool(); + + void setSE(const QString& se); + + void updateKeyToolBar(); + void updateFontCombo(); + + void loadToolBarPosition(); + + bool eventFilter(QObject *, QEvent*); + + void insertThemeItem(const QString&); + void setUseDock(bool); + + void initAdditionalActions(); + + void initTranslator(); + void clearTranslator(); + void connector(); + void updateLanguageMenu(); + + void loadStyleSheetFromFile(const QString qssFile); + void refreshStyleSheet(); + void clearStyleSheet(); + + bool isDelimiterExistedBefore(const QString& str, + const std::vector& existingDelimiters); + int isDelimiterExistedAfter(const QString& str, + const std::vector& existingDelimiters); + bool uppercaseCharFollowingCtrl(QString& str, + int& i, + const QString& after); + void replaceEscapeString(QString& str, + const QString& before, + const QString& after, + const QString& delimiter, + const std::vector *existingDelimiters = NULL); + void transEscapeStr(QString& target, const QString& source); + +#ifdef HAVE_PYTHON +public: + FQTermPythonHelper* getPythonHelper() { + return pythonHelper_; + } + + //protected slots: +private: + FQTermPythonHelper* pythonHelper_; +#endif //HAVE_PYTHON + +#ifdef USE_GLOBAL_HOTKEY + QxtGlobalShortcut* globalHotkey_; +#endif //USE_GLOBAL_HOTKEY +private slots: + void globalHotkeyTriggered(); + void globalHotkeyChanged(); +}; + +class TranslatorInstaller : public QObject +{ + Q_OBJECT; + +public: + TranslatorInstaller(const QString& language, FQTermFrame* frame); + + QString languageName(); + QString languageFormalName(); +public slots: + void installTranslator(); + +protected: + QString language_; + FQTermFrame* frame_; + + QString languageName_; +}; + + +} // namespace FQTerm + +#endif // FQTERM_FRAME_H diff --git a/src/fqterm/fqterm_python.cpp b/src/fqterm/fqterm_python.cpp new file mode 100644 index 0000000..68b9385 --- /dev/null +++ b/src/fqterm/fqterm_python.cpp @@ -0,0 +1,826 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include "fqterm.h" +#ifdef HAVE_PYTHON +#include +#endif +class SleeperThread : public QThread +{ +public: + static void msleep(unsigned long msecs) + { + QThread::msleep(msecs); + } +}; + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_PYTHON + +#include "fqterm_window.h" +#include "fqterm_buffer.h" +#include "fqterm_text_line.h" +#include "fqterm_param.h" +#include "fqterm_session.h" +#include "fqterm_python.h" +#include "fqterm_path.h" +#include "common.h" +namespace FQTerm { + +/* ************************************************************************** + * + * Pythons Embedding + * + * ***************************************************************************/ + +QString getException() { + PyObject *pType = NULL, *pValue = NULL, *pTb = NULL, *pName, *pTraceback; + + PyErr_Fetch(&pType, &pValue, &pTb); + + pName = PyString_FromString("traceback"); + pTraceback = PyImport_Import(pName); + Py_DECREF(pName); + + if (pTraceback == NULL) { + return "General Error in Python Callback"; + } + + pName = PyString_FromString("format_exception"); + PyObject *pRes = PyObject_CallMethodObjArgs(pTraceback, pName, pType, pValue, + pTb, NULL); + Py_DECREF(pName); + + Py_DECREF(pTraceback); + + Py_XDECREF(pType); + Py_XDECREF(pValue); + Py_XDECREF(pTb); + + if (pRes == NULL) { + return "General Error in Python Callback"; + } + + pName = PyString_FromString("string"); + PyObject *pString = PyImport_Import(pName); + Py_DECREF(pName); + + if (pString == NULL) { + return "General Error in Python Callback"; + } + + pName = PyString_FromString("join"); + PyObject *pErr = PyObject_CallMethodObjArgs(pString, pName, pRes, NULL); + Py_DECREF(pName); + + Py_DECREF(pString); + Py_DECREF(pRes); + + if (pErr == NULL) { + return "General Error in Python Callback"; + } + + QString str(PyString_AsString(pErr)); + Py_DECREF(pErr); + + return str; +} + +QString getErrOutputFile(FQTermWindow *lp) { + // file name + QString str2; + str2.setNum(long(lp)); + str2 += ".err"; + // path + return getPath(USER_CONFIG) + str2; +} + +// copy current artcle for back compatible use only +// for new coder please use getArticle +static PyObject *fqterm_copyArticle(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + FQTermWindow *termWindow_ = (FQTermWindow*)lp; + + QStringList strList; + QString strArticle; + QReadWriteLock& bufferLock = termWindow_->getSession()->getBufferLock(); + QReadLocker locker(&bufferLock); + while (1) { + // check it there is duplicated string + // it starts from the end in the range of one screen height + // so this is a non-greedy match + QString strTemp; + termWindow_->getSession()->getBuffer()->getTextLineInTerm(0)->getAllPlainText(strTemp); + strTemp = strTemp.trimmed(); + int i = 0; + int start = 0; + for (QStringList::Iterator it = strList.end(); + it != strList.begin() && i < termWindow_->getSession()->getBuffer()->getNumRows() - 1; // not exceeeding the last screen + --it, i++) { + if (*it != strTemp) { + continue; + } + QStringList::Iterator it2 = it; + bool dup = true; + // match more to see if its duplicated + for (int j = 0; j <= i; j++, it2++) { + QString str1; + termWindow_->getSession()->getBuffer()->getTextLineInTerm(j)->getAllPlainText(str1); + if (*it2 != str1.trimmed()) { + dup = false; + break; + } + } + if (dup) { + // set the start point + start = i + 1; + break; + } + } + // add new lines + for (i = start; i < termWindow_->getSession()->getBuffer()->getNumRows() - 1; i++) { + QString tmp; + termWindow_->getSession()->getBuffer()->getTextLineInTerm(i)->getAllPlainText(tmp); + strList += tmp.trimmed(); + } + + // the end of article + QString testEnd; + termWindow_->getSession()->getBuffer()->getTextLineInTerm(termWindow_->getSession()->getBuffer()->getNumRows() - 1)->getAllPlainText(testEnd); + if (testEnd.indexOf("%") == -1) { + break; + } + // continue + termWindow_->writeString_ts(" "); + + // TODO: fixme + if (!termWindow_->getSession()->getWaitCondition().wait(&bufferLock, 10000)) { + // // timeout + break; + } + } +#if defined(_OS_WIN32_) || defined(Q_OS_WIN32) + strArticle = strList.join("\r\n"); +#else + strArticle = strList.join("\n"); +#endif + + PyObject *py_text = PyString_FromString(strArticle.toUtf8()); + + Py_INCREF(py_text); + return py_text; +} + +static PyObject *fqterm_getArticle(PyObject *, PyObject *args) { + long lp; + int timeout; + int succeed = 1; + + if (!PyArg_ParseTuple(args, "li", &lp, &timeout)) { + return NULL; + } + FQTermWindow *termWindow_ = (FQTermWindow*)lp; + + QStringList strList; + QString strArticle; + QReadWriteLock& bufferLock = termWindow_->getSession()->getBufferLock(); + while (!bufferLock.tryLockForRead()) {} + while (1) { + // check it there is duplicated string + // it starts from the end in the range of one screen height + // so this is a non-greedy match + QString strTemp; + termWindow_->getSession()->getBuffer()->getTextLineInTerm(0)->getAllPlainText(strTemp); + strTemp = strTemp.trimmed(); + + int i = 0; + int start = 0; + for (QStringList::Iterator it = strList.end(); + it != strList.begin() && i < termWindow_->getSession()->getBuffer()->getNumRows() - 1; // not exceeeding the last screen + --it, i++) { + if (it == strList.end() || *it != strTemp) { + continue; + } + QStringList::Iterator it2 = it; + bool dup = true; + // match more to see if its duplicated + for (int j = 0; j <= i && it2 != strList.end(); j++, it2++) { + QString str1; + termWindow_->getSession()->getBuffer()->getTextLineInTerm(j)->getAllPlainText(str1); + if (*it2 != str1.trimmed()) { + dup = false; + break; + } + } + if (dup) { + // set the start point + start = i + 1; + break; + } + } + // add new lines + for (i = start; i < termWindow_->getSession()->getBuffer()->getNumRows() - 1; i++) { + QString tmp; + termWindow_->getSession()->getBuffer()->getTextLineInTerm(i)->getAllPlainText(tmp); + strList += tmp.trimmed(); + } + + // the end of article + QString testEnd; + termWindow_->getSession()->getBuffer()->getTextLineInTerm(termWindow_->getSession()->getBuffer()->getNumRows() - 1)->getAllPlainText(testEnd); + if (testEnd.indexOf("%") == -1) { + break; + } + // continue + termWindow_->writeString_ts(" "); + + // TODO: fixme + if (!termWindow_->getSession()->getWaitCondition().wait(&bufferLock, timeout)) { // timeout + succeed = 0; + break; + } + } + bufferLock.unlock(); + if (succeed) + strArticle = strList.join(OS_NEW_LINE); + + PyObject *py_res = Py_BuildValue("si", (const char*)strArticle.toUtf8().data(), + succeed); + + Py_INCREF(py_res); + + return py_res; + +} + +static PyObject *fqterm_formatError(PyObject *, PyObject *args) { + long lp; + + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + QString strErr; + QString filename = getErrOutputFile((FQTermWindow*)lp); + + QDir d; + if (d.exists(filename)) { + QFile file(filename); + file.open(QIODevice::ReadOnly); + QTextStream is(&file); + while (!is.atEnd()) { + strErr += is.readLine(); // line of text excluding '\n' + strErr += '\n'; + } + file.close(); + d.remove(filename); + } + + if (!strErr.isEmpty()) { + ((FQTermWindow*)lp)->getPythonErrorMessage() = strErr; + // TODO: fixme + //qApp->postEvent((FQTermWindow*)lp, new QCustomEvent(PYE_ERROR)); + } else { + // TODO: fixme + //qApp->postEvent((FQTermWindow*)lp, new QCustomEvent(PYE_FINISH)); + } + + + Py_INCREF(Py_None); + return Py_None; +} + +// caret x +static PyObject *fqterm_caretX(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + int x = ((FQTermWindow*)lp)->getSession()->getBuffer()->getCaretColumn(); + PyObject *py_x = Py_BuildValue("i", x); + Py_INCREF(py_x); + return py_x; +} + +// caret y +static PyObject *fqterm_caretY(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + int y = ((FQTermWindow*)lp)->getSession()->getBuffer()->getCaretRow(); + PyObject *py_y = Py_BuildValue("i", y); + Py_INCREF(py_y); + return py_y; + +} + +// columns +static PyObject *fqterm_columns(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + int numColumns = ((FQTermWindow*)lp)->getSession()->getBuffer()->getNumColumns(); + PyObject *py_columns = Py_BuildValue("i", numColumns); + + Py_INCREF(py_columns); + return py_columns; + +} + +// rows +static PyObject *fqterm_rows(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + int rows = ((FQTermWindow*)lp)->getSession()->getBuffer()->getNumRows(); + PyObject *py_rows = Py_BuildValue("i", rows); + + Py_INCREF(py_rows); + return py_rows; +} + +// sned string to server +static PyObject *fqterm_sendString(PyObject *, PyObject *args) { + char *pstr; + long lp; + + if (!PyArg_ParseTuple(args, "ls", &lp, &pstr)) { + return NULL; + } + + ((FQTermWindow*)lp)->writeRawString_ts(U82U(pstr)); + + Py_INCREF(Py_None); + return Py_None; +} + +// input should be utf8. +// same as above except parsing string first "\n" "^p" etc +static PyObject *fqterm_sendParsedString(PyObject *, PyObject *args) { + char *pstr; + long lp; + int len; + + if (!PyArg_ParseTuple(args, "ls", &lp, &pstr)) { + return NULL; + } + len = strlen(pstr); + + ((FQTermWindow*)lp)->writeString_ts(U82U(pstr)); + + Py_INCREF(Py_None); + return Py_None; +} + +// get text at line +static PyObject *fqterm_getText(PyObject *, PyObject *args) { + long lp; + int numRows; + if (!PyArg_ParseTuple(args, "li", &lp, &numRows)) { + return NULL; + } + QString str; + if (numRows < ((FQTermWindow*)lp)->getSession()->getBuffer()->getNumRows()) + ((FQTermWindow*)lp)->getSession()->getBuffer()->getTextLineInTerm(numRows)->getAllPlainText(str); + + PyObject *py_text = PyString_FromString(U2U8(str)); + + Py_INCREF(py_text); + return py_text; +} + +// get text with attributes +static PyObject *fqterm_getAttrText(PyObject *, PyObject *args) { + long lp; + int numRows; + if (!PyArg_ParseTuple(args, "li", &lp, &numRows)) { + return NULL; + } + + QString str; + if (numRows < ((FQTermWindow*)lp)->getSession()->getBuffer()->getNumRows()) + ((FQTermWindow*)lp)->getSession()->getBuffer()->getTextLineInTerm(numRows)->getAllAnsiText(str); + + PyObject *py_text = PyString_FromString(U2U8(str)); + + Py_INCREF(py_text); + return py_text; +} + +// is host connected +static PyObject *fqterm_isConnected(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + bool connected = ((FQTermWindow*)lp)->isConnected(); + PyObject *py_connected = Py_BuildValue("i", connected ? 1 : 0); + + Py_INCREF(py_connected); + return py_connected; +} + +// disconnect from host +static PyObject *fqterm_disconnect(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + ((FQTermWindow*)lp)->disconnect(); + + Py_INCREF(Py_None); + return Py_None; +} + +// reconnect to host +static PyObject *fqterm_reconnect(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + ((FQTermWindow*)lp)->getSession()->reconnect(); + + Py_INCREF(Py_None); + return Py_None; +} + +// bbs encoding 0-GBK 1-BIG5 +//FIXME: UTF8 and HKSCS +static PyObject *fqterm_getBBSCodec(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + PyObject *py_codec = PyString_FromString(((FQTermWindow*)lp) + ->getSession()->param().serverEncodingID_ == 0 ? "GBK" : "Big5"); + Py_INCREF(py_codec); + + return py_codec; +} + +// host address +static PyObject *fqterm_getAddress(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + PyObject *py_addr = PyString_FromString(((FQTermWindow*)lp) + ->getSession()->param().hostAddress_.toLocal8Bit()); + Py_INCREF(py_addr); + return py_addr; +} + +// host port number +static PyObject *fqterm_getPort(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + PyObject *py_port = Py_BuildValue("i", ((FQTermWindow*)lp)->getSession()->param().port_); + Py_INCREF(py_port); + return py_port; +} + +// connection protocol 0-telnet 1-SSH1 2-SSH2 +static PyObject *fqterm_getProtocol(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + PyObject *py_port = Py_BuildValue("i", ((FQTermWindow*)lp) + ->getSession()->param().protocolType_); + Py_INCREF(py_port); + return py_port; +} + +// key to reply msg +static PyObject *fqterm_getReplyKey(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + PyObject *py_key = PyString_FromString(((FQTermWindow*)lp) + ->getSession()->param().replyKeyCombination_.toLocal8Bit()); + Py_INCREF(py_key); + return py_key; +} + +// url under mouse +static PyObject *fqterm_getURL(PyObject *, PyObject *args) { + long lp; + if (!PyArg_ParseTuple(args, "l", &lp)) { + return NULL; + } + + PyObject *py_url = PyString_FromString(((FQTermWindow*)lp)->getSession()->getUrl().toUtf8().constData()); + Py_INCREF(py_url); + return py_url; +} + +// preview image link +static PyObject *fqterm_previewImage(PyObject *, PyObject *args) { + long lp; + char *url; + if (!PyArg_ParseTuple(args, "ls", &lp, &url)) { + return NULL; + } + + ((FQTermWindow*)lp)->getHttpHelper(url, true); + + Py_INCREF(Py_None); + return Py_None; + +} + +// convert string from UTF8 to specified encoding +static PyObject *fqterm_fromUTF8(PyObject *, PyObject *args) { + char *str, *enc; + if (!PyArg_ParseTuple(args, "ss", &str, &enc)) { + return NULL; + } + QTextCodec *encodec = QTextCodec::codecForName(enc); + QTextCodec *utf8 = QTextCodec::codecForName("utf8"); + + PyObject *py_str = PyString_FromString(encodec->fromUnicode(utf8->toUnicode + (str))); + Py_INCREF(py_str); + return py_str; +} + +// convert string from specified encoding to UTF8 +static PyObject *fqterm_toUTF8(PyObject *, PyObject *args) { + char *str, *enc; + if (!PyArg_ParseTuple(args, "ss", &str, &enc)) { + return NULL; + } + QTextCodec *encodec = QTextCodec::codecForName(enc); + QTextCodec *utf8 = QTextCodec::codecForName("utf8"); + + PyObject *py_str = PyString_FromString(utf8->fromUnicode(encodec->toUnicode + (str))); + Py_INCREF(py_str); + return py_str; +} + +static PyObject *fqterm_wait(PyObject *, PyObject *args) { + long t; + if (!PyArg_ParseTuple(args, "l", &t)) { + return NULL; + } + SleeperThread::msleep(t); + + Py_INCREF(Py_None); + return Py_None; +} + +PyMethodDef fqterm_methods[] = { + { + "formatError", (PyCFunction)fqterm_formatError, METH_VARARGS, + "get the traceback info" + } + + , + + { + "getArticle", (PyCFunction)fqterm_getArticle, METH_VARARGS, + "copy current article" + } + + , + + { + "copyArticle", (PyCFunction)fqterm_copyArticle, METH_VARARGS, + "copy current article (obsolete)" + } + + , + + { + "getText", (PyCFunction)fqterm_getText, METH_VARARGS, "get text at line#" + } + + , + + { + "getAttrText", (PyCFunction)fqterm_getAttrText, METH_VARARGS, + "get attr text at line#" + } + + , + + { + "sendString", (PyCFunction)fqterm_sendString, METH_VARARGS, + "send string to server" + } + + , + + { + "sendParsedString", (PyCFunction)fqterm_sendParsedString, METH_VARARGS, + "send string with escape" + } + + , + + { + "caretX", (PyCFunction)fqterm_caretX, METH_VARARGS, "caret x" + } + + , + + { + "caretY", (PyCFunction)fqterm_caretY, METH_VARARGS, "caret y" + } + + , + + { + "columns", (PyCFunction)fqterm_columns, METH_VARARGS, "screen width" + } + + , + + { + "rows", (PyCFunction)fqterm_rows, METH_VARARGS, "screen height" + } + + , + + { + "isConnected", (PyCFunction)fqterm_isConnected, METH_VARARGS, + "connected to server or not" + } + + , + + { + "disconnect", (PyCFunction)fqterm_disconnect, METH_VARARGS, + "disconnect from server" + } + + , + + { + "reconnect", (PyCFunction)fqterm_reconnect, METH_VARARGS, "reconnect" + } + + , + + { + "getBBSCodec", (PyCFunction)fqterm_getBBSCodec, METH_VARARGS, + "get the bbs encoding, GBK or Big5" + } + + , + + { + "getAddress", (PyCFunction)fqterm_getAddress, METH_VARARGS, + "get the bbs address" + } + + , + + { + "getPort", (PyCFunction)fqterm_getPort, METH_VARARGS, "get the bbs port number" + } + + , + + { + "getProtocol", (PyCFunction)fqterm_getProtocol, METH_VARARGS, + "get the bbs protocol, 0/1/2 TELNET/SSH1/SSH2" + } + + , + + { + "getReplyKey", (PyCFunction)fqterm_getReplyKey, METH_VARARGS, + "get the key to reply messages" + } + + , + + { + "getURL", (PyCFunction)fqterm_getURL, METH_VARARGS, + "get the url string under mouse" + } + + , + + { + "previewImage", (PyCFunction)fqterm_previewImage, METH_VARARGS, + "preview the image link" + } + + , + + { + "fromUTF8", (PyCFunction)fqterm_fromUTF8, METH_VARARGS, + "decode from utf8 to string in specified codec" + } + + , + + { + "toUTF8", (PyCFunction)fqterm_toUTF8, METH_VARARGS, + "decode from string in specified codec to utf8" + } + + , + + { + "wait", (PyCFunction)fqterm_wait, METH_VARARGS, + "wait for x ms" + } + + , + + { + NULL, (PyCFunction)NULL, 0, NULL + } +}; + + + +FQTermPythonHelper::FQTermPythonHelper() + : mainThreadState_(NULL) { + + // initialize Python + Py_Initialize(); + // initialize thread support + PyEval_InitThreads(); + // save a pointer to the main PyThreadState object + mainThreadState_ = PyThreadState_Get(); + // add path + PyRun_SimpleString("import sys\n"); + QString pathCmd; + pathCmd = "sys.path.insert(0,'"; + pathCmd += getPath(RESOURCE)+"script')"; + PyRun_SimpleString(fq_strdup(pathCmd.toUtf8().data())); + + Py_InitModule4("fqterm", fqterm_methods, + NULL,(PyObject*)NULL,PYTHON_API_VERSION); + // release the lock + PyEval_ReleaseLock(); +} + +FQTermPythonHelper::~FQTermPythonHelper() { + // shut down the interpreter + PyInterpreterState * mainInterpreterState = mainThreadState_->interp; + // create a thread state object for this thread + PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState); + PyThreadState_Swap(myThreadState); + PyEval_AcquireLock(); + Py_Finalize(); +} + +} // namespace FQTerm + +#endif //HAVE_PYTHON \ No newline at end of file diff --git a/src/fqterm/fqterm_python.h b/src/fqterm/fqterm_python.h new file mode 100644 index 0000000..bad6b04 --- /dev/null +++ b/src/fqterm/fqterm_python.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_PYTHON_H +#define FQTERM_PYTHON_H + +#ifdef HAVE_PYTHON +#include "fqterm.h" + +namespace FQTerm { + +class FQTermWindow; +extern QString getException(); +extern QString getErrOutputFile(FQTermWindow*); +extern PyMethodDef fqterm_methods[]; + +class FQTermPythonHelper +{ +public: + FQTermPythonHelper(); + ~FQTermPythonHelper(); + PyThreadState* getPyThreadState() { + return mainThreadState_; + } +private: + PyThreadState * mainThreadState_; +}; + +} // namespace FQTerm + +#endif // HAVE_PYTHON + +#endif // FQTERM_PYTHON_H + diff --git a/src/fqterm/fqterm_screen.cpp b/src/fqterm/fqterm_screen.cpp new file mode 100644 index 0000000..339e666 --- /dev/null +++ b/src/fqterm/fqterm_screen.cpp @@ -0,0 +1,1868 @@ +/**************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fqterm_buffer.h" +#include "fqterm_config.h" +#include "fqterm_convert.h" +#include "fqterm_frame.h" +#include "fqterm_param.h" +#include "fqterm_screen.h" +#include "fqterm_session.h" +#include "fqterm_text_line.h" +#include "fqterm_window.h" +#include "fqterm_wndmgr.h" +#ifdef HAVE_PYTHON +#include +#endif //HAVE_PYTHON +namespace FQTerm { +/* ------------------------------------------------------------------------ */ +/* */ +/* Constructor/Destructor */ +/* */ +/* ------------------------------------------------------------------------ */ + +FQTermScreen::FQTermScreen(QWidget *parent, FQTermSession *session) + : QWidget(parent), + scrollBarWidth_(15), + termBuffer_(session->getBuffer()), + cnLetterSpacing_(0.0), + spLetterSpacing_(0.0), + enLetterSpacing_(0.0), + cnFixedPitch_(false), + enFixedPitch_(false), + hasBackground_(false), + backgroundRenderOption_(0), + backgroundCoverage_(0), + backgroundAlpha_(0), + backgroundUseAlpha_(false) { + termWindow_ = (FQTermWindow*)parent; + session_ = session; + param_ = &session->param(); + paintState_ = System; + isCursorShown_ = true; + is_light_background_mode_ = false; + + setFocusPolicy(Qt::ClickFocus); + setAttribute(Qt::WA_InputMethodEnabled, true); + setMouseTracking(true); + + setSchema(); + + initFontMetrics(); + + FQ_VERIFY(connect(termBuffer_, SIGNAL(bufferSizeChanged()), + this, SLOT(bufferSizeChanged()))); + + FQ_VERIFY(connect(termBuffer_, SIGNAL(termSizeChanged(int, int)), + this, SLOT(termSizeChanged(int, int)))); + + blinkTimer_ = new QTimer(this); + FQ_VERIFY(connect(blinkTimer_, SIGNAL(timeout()), this, SLOT(blinkEvent()))); + + cursorTimer_ = new QTimer(this); + FQ_VERIFY(connect(cursorTimer_, SIGNAL(timeout()), + this, SLOT(cursorEvent()))); + + // the scrollbar + scrollBar_ = new QScrollBar(this); + scrollBar_->setCursor(Qt::ArrowCursor); + bufferStart_ = 0; + bufferEnd_ = termBuffer_->getNumRows() - 1; + areLinesBlink_ = new bool[bufferEnd_ - bufferStart_ + 1]; + scrollBar_->setRange(0, 0); + scrollBar_->setSingleStep(1); + scrollBar_->setPageStep(termBuffer_->getNumRows()); + scrollBar_->setValue(0); + updateScrollBar(); + FQ_VERIFY(connect(scrollBar_, SIGNAL(valueChanged(int)), + this, SLOT(scrollChanged(int)))); + + gotoPrevPage_ = new QShortcut(QKeySequence(tr("Shift+PageUp")), + this, SLOT(prevPage())); + gotoNextPage_ = new QShortcut(QKeySequence(tr("Shift+PageDown")), + this, SLOT(nextPage())); + gotoPrevLine_ = new QShortcut(QKeySequence(tr("Shift+Up")), + this, SLOT(prevLine())); + gotoNextLine_ = new QShortcut(QKeySequence(tr("Shift+Down")), + this, SLOT(nextLine())); + + setAttribute(Qt::WA_OpaquePaintEvent, true); + + // init variable + isBlinkScreen_ = false; + isBlinkCursor_ = true; + + + preedit_line_ = new PreeditLine(this, colors_); + + tmp_im_query_ = new QString(); +} + +FQTermScreen::~FQTermScreen() { + delete [] areLinesBlink_; + delete blinkTimer_; + delete cursorTimer_; + //delete m_pCanvas; + //delete m_inputContent; + + delete preedit_line_; + + delete tmp_im_query_; +} + +bool FQTermScreen::event(QEvent *e) { + switch(e->type()) { + case QEvent::KeyPress: + { + // forward all key press events to parant (FQTermWindow). + return false; + } + } + return this->QWidget::event(e); +} + +// focus event received +void FQTermScreen::focusInEvent(QFocusEvent*) { + + gotoPrevPage_->setEnabled(true); + gotoNextPage_->setEnabled(true); + gotoPrevLine_->setEnabled(true); + gotoNextLine_->setEnabled(true); + +} + +// focus out +void FQTermScreen::focusOutEvent(QFocusEvent*) { + gotoPrevPage_->setEnabled(false); + gotoNextPage_->setEnabled(false); + gotoPrevLine_->setEnabled(false); + gotoNextLine_->setEnabled(false); +} + +void FQTermScreen::resizeEvent(QResizeEvent*) { + syncBufferAndScreen(); +} + +void FQTermScreen::syncBufferAndScreen() { + updateScrollBar(); + updateBackgroundPixmap(); + + if (param_->isFontAutoFit_ == 1) { + updateFont(); + } else if (param_->isFontAutoFit_ == 0) { //adjust column/row + int cx = clientRectangle_.width() / charWidth_; + int cy = clientRectangle_.height() / charHeight_; + if (param_->hostType_ == 0) { + if (cx < 80) cx = 80; + if (cy < 24) cy = 24; + } else { + if (cx < 10) cx = 10; + if (cy < 10) cy = 10; + } + session_->setTermSize(cx, cy); + //session_->writeStr("\0x5f"); + } else { + session_->setTermSize(param_->numColumns_, param_->numRows_); + } +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* Mouse */ +/* */ +/* ------------------------------------------------------------------------ */ +void FQTermScreen::enterEvent(QEvent *e) { + QApplication::sendEvent(termWindow_, e); +} + +void FQTermScreen::leaveEvent(QEvent *e) { + QApplication::sendEvent(termWindow_, e); +} + +void FQTermScreen::mousePressEvent(QMouseEvent *me) { + + termWindow_->mousePressEvent(me); + setFocus(); +} + +void FQTermScreen::mouseMoveEvent(QMouseEvent *me) { +#ifdef Q_OS_MACX + termWindow_->mouseMoveEvent(me); +#else + termWindow_->mouseMoveEvent(me); + //QApplication::sendEvent(m_pWindow, me); +#endif +} + +void FQTermScreen::mouseReleaseEvent(QMouseEvent *me) { + termWindow_->mouseReleaseEvent(me); + //QApplication::sendEvent(m_pWindow, me); +} + +void FQTermScreen::wheelEvent(QWheelEvent *we) { + if (FQTermPref::getInstance()->isWheelSupported_) { + QApplication::sendEvent(termWindow_, we); + } else { + QApplication::sendEvent(scrollBar_, we); + } +} + + +/* ------------------------------------------------------------------------ */ +/* */ +/* Font */ +/* */ +/* ------------------------------------------------------------------------ */ + +void FQTermScreen::initFontMetrics() { + //issue 98 + if (param_->isFontAutoFit_ == 1) { + englishFont_ = new QFont(param_->englishFontName_); + nonEnglishFont_ = new QFont(param_->otherFontName_); + + updateFont(); + } else { + englishFont_ = new QFont(param_->englishFontName_, qMax(8, param_->englishFontSize_)); + nonEnglishFont_ = new QFont(param_->otherFontName_, qMax(8, param_->otherFontSize_)); + + setFontMetrics(); + } + + englishFont_->setWeight(QFont::Normal);; + nonEnglishFont_->setWeight(QFont::Normal); + + // m_pFont->setStyleHint(QFont::System, + // m_pWindow->m_pFrame->m_pref.bAA ? + // QFont::PreferAntialias : QFont::NoAntialias); + updateFixedPitchInfo(); +} + +void FQTermScreen::updateFont() { + int nPixelSize; + int nIniSize = + qMax(8, qMin(clientRectangle_.height() / termBuffer_->getNumRows(), + clientRectangle_.width() *2 / termBuffer_->getNumColumns())); + //FIXME: WTF???? + for (nPixelSize = nIniSize - 3; nPixelSize <= nIniSize + 3; nPixelSize++) { + englishFont_->setPixelSize(nPixelSize); + nonEnglishFont_->setPixelSize(nPixelSize); + + setFontMetrics(); + if ((termBuffer_->getNumRows() *charHeight_) > clientRectangle_.height() || + (termBuffer_->getNumColumns() *charWidth_) > clientRectangle_.width()) { + while (nPixelSize > 5) { + nPixelSize--; + englishFont_->setPixelSize(nPixelSize); + nonEnglishFont_->setPixelSize(nPixelSize); + + setFontMetrics(); + //changed by dp to get larger font... + if ((termBuffer_->getNumRows()*charHeight_) <= clientRectangle_.height() + && (termBuffer_->getNumColumns() *charWidth_) <= + clientRectangle_.width()) { + break; + } + } + break; + } + } + + englishFont_->setWeight(QFont::Normal); + nonEnglishFont_->setWeight(QFont::Normal); + setFontAntiAliasing(FQTermPref::getInstance()->openAntiAlias_); +} + +void FQTermScreen::setFontMetrics() { + + QFontMetrics nonEnglishFM(*nonEnglishFont_); + QFontMetrics englishFM(*englishFont_); + + // FIXME: find a typical character for the current language. + int cn = nonEnglishFM.width(QChar(0x4e2D)); + int en = englishFM.width('W'); + + int pix_size = nonEnglishFont_->pixelSize(); + while (cn % 2 && pix_size > 10) { + nonEnglishFont_->setPixelSize(--pix_size); + nonEnglishFM = QFontMetrics(*nonEnglishFont_); + cn = nonEnglishFM.width(QChar(0x4e2D)); + } + + pix_size = englishFont_->pixelSize(); + while (2 * en > cn + 1 && pix_size > 5) { + --pix_size; + englishFont_->setPixelSize(pix_size); + englishFM = QFontMetrics(*englishFont_); + en = englishFM.width('W'); +/* +#ifndef __APPLE__ + //FIXME: correctly draw chars with left/right bearing. + if ( - englishFM.leftBearing('W') - englishFM.rightBearing('W') > 0) { + en += - englishFM.leftBearing('W') - englishFM.rightBearing('W'); + } +#endif +*/ + } + + charWidth_ = qMax(float(cn) / 2 , float(en)); + + charHeight_ = qMax(englishFM.height(), nonEnglishFM.height()); + charHeight_ += param_->lineSpacing_; + //charWidth_ = ceil(qMax(charWidth_, charHeight_ * param_->charRatio_ / 100)); + charWidth_ += param_->charSpacing_; + + cnLetterSpacing_ = qMax(charWidth_ * 2 - cn, 0.0); + enLetterSpacing_ = qMax(charWidth_ - en, 0.0); + + spLetterSpacing_ = qMax(charWidth_ - englishFM.width(' '), 0.0); + + fontAscent_ = qMax(englishFM.ascent(), nonEnglishFM.ascent()); + fontDescent_ = qMax(englishFM.descent(), nonEnglishFM.descent()); + + FQ_TRACE("font", 4) << "\nNon-English font:" + << "\nheight: " << nonEnglishFM.height() + << "\nascent: " << nonEnglishFM.ascent() + << "\ndescent: " << nonEnglishFM.descent(); + + + FQ_TRACE("font", 4) << "\nEnglish font:" + << "\nheight: " << englishFM.height() + << "\nascent: " << englishFM.ascent() + << "\ndescent: " << englishFM.descent(); + + updateFixedPitchInfo(); +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* Colors */ +/* */ +/* ------------------------------------------------------------------------ */ +void FQTermScreen::setSchema() { + // the default color table + colors_[0] = Qt::black; + colors_[1] = Qt::darkRed; + colors_[2] = Qt::darkGreen; + colors_[3] = Qt::darkYellow; + colors_[4] = Qt::darkBlue; + colors_[5] = Qt::darkMagenta; + colors_[6] = Qt::darkCyan; + colors_[7] = Qt::darkGray; + colors_[8] = Qt::gray; + colors_[9] = Qt::red; + colors_[10] = Qt::green; + colors_[11] = Qt::yellow; + colors_[12] = Qt::blue; + colors_[13] = Qt::magenta; + colors_[14] = Qt::cyan; + colors_[15] = Qt::white; + + + hasBackground_ = false; + // if we have schema defined + if (QFile::exists(param_->schemaFileName_)) { + FQTermConfig *pConf = new FQTermConfig(param_->schemaFileName_); + for (int i = 0; i < 16; ++i) { + colors_[i].setNamedColor(pConf->getItemValue("color", QString("color%1").arg(i))); + } + originBackgroundPixmap_ = QPixmap(pConf->getItemValue("image", "name")); + //0 -- none 1 -- image + hasBackground_ = pConf->getItemValue("background", "type").toInt() ? 1 : 0; + backgroundRenderOption_ = pConf->getItemValue("image", "render").toInt(); + backgroundCoverage_ = pConf->getItemValue("image", "cover").toInt(); + backgroundUseAlpha_ = pConf->getItemValue("image", "usealpha").toInt(); + backgroundAlpha_ = pConf->getItemValue("image", "alpha").toInt(); + + delete pConf; + } + + // override schema using user defined Fg/Bg color + colors_[0] = param_->backgroundColor_; + colors_[7] = param_->foregroundColor_; +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* Scrollbar */ +/* */ +/* ------------------------------------------------------------------------*/ +void FQTermScreen::prevPage() { + scrollLine(-termBuffer_->getNumRows()); + setPaintState(NewData); + update(); +} + +void FQTermScreen::nextPage() { + scrollLine(termBuffer_->getNumRows()); + setPaintState(NewData); + update(); +} + +void FQTermScreen::prevLine() { + scrollLine(-1); + setPaintState(NewData); + update(); +} + +void FQTermScreen::nextLine() { + scrollLine(1); + setPaintState(NewData); + update(); +} + +void FQTermScreen::scrollLine(int delta) { + bufferStart_ += delta; + + if (bufferStart_ < 0) { + bufferStart_ = 0; + return ; + } + if (bufferStart_ > termBuffer_->getNumLines() - termBuffer_->getNumRows()) { + bufferStart_ = termBuffer_->getNumLines() - termBuffer_->getNumRows(); + return ; + } + + scrollBar_->setValue(bufferStart_); + bufferEnd_ = bufferStart_ + termBuffer_->getNumRows() - 1; + + // notify session + session_->setScreenStart(bufferStart_); + + for (int i = bufferStart_; i <= bufferEnd_; i++) { + session_->setLineAllChanged(i); + } +} + +void FQTermScreen::scrollChanged(int value) { + if (bufferStart_ == value) { + return ; + } + + if (value < 0) { + value = 0; + } + if (value > termBuffer_->getNumLines() - termBuffer_->getNumRows()) { + value = termBuffer_->getNumLines() - termBuffer_->getNumRows(); + } + + bufferStart_ = value; + bufferEnd_ = value + termBuffer_->getNumRows() - 1; + + // notify session + session_->setScreenStart(bufferStart_); + + for (int i = bufferStart_; i <= bufferEnd_; i++) { + //termBuffer_->at(i)->setChanged(-1, -1); + session_->setLineAllChanged(i); + } + + setPaintState(NewData); + update(); +} + +void FQTermScreen::updateScrollBar() { + int numLeftPixels = 0; // ß¾ + int numUpPixels = 0; // ϱ߾ + + switch (FQTermPref::getInstance()->termScrollBarPosition_) { + case 0: + scrollBar_->hide(); + clientRectangle_ = QRect(numLeftPixels, numUpPixels, + rect().width() - numLeftPixels, + rect().height() - numUpPixels); + break; + case 1: + // LEFT + scrollBar_->setGeometry(0, 0, scrollBarWidth_, rect().height()); + scrollBar_->show(); + clientRectangle_ = QRect(scrollBarWidth_ + numLeftPixels, numUpPixels, + rect().width() - scrollBarWidth_ - numLeftPixels, + rect().height() - numUpPixels); + break; + case 2: + // RIGHT + scrollBar_->setGeometry(rect().width() - scrollBarWidth_, 0, + scrollBarWidth_, rect().height()); + scrollBar_->show(); + clientRectangle_ = QRect(numLeftPixels, numUpPixels, + rect().width() - scrollBarWidth_ - numLeftPixels, + rect().height() - numUpPixels); + break; + } + setPaintState(Repaint); + update(); +} + +void FQTermScreen::bufferSizeChanged() { + FQ_VERIFY(disconnect(scrollBar_, SIGNAL(valueChanged(int)), + this, SLOT(scrollChanged(int)))); + scrollBar_->setRange(0, termBuffer_->getNumLines() - termBuffer_->getNumRows()); + scrollBar_->setSingleStep(1); + scrollBar_->setPageStep(termBuffer_->getNumRows()); + + // FIXME: should not always move scroll bar to the bottom when + // buffer size is changed. + scrollBar_->setValue(termBuffer_->getNumLines() - termBuffer_->getNumRows()); + + bufferStart_ = scrollBar_->value(); + bufferEnd_ = scrollBar_->value() + termBuffer_->getNumRows() - 1; + + // notify session + session_->setScreenStart(bufferStart_); + + FQ_VERIFY(connect(scrollBar_, SIGNAL(valueChanged(int)), + this, SLOT(scrollChanged(int)))); + + delete [] areLinesBlink_; + areLinesBlink_ = new bool[bufferEnd_ - bufferStart_ + 1]; + + scrollLine(0); +} + +void FQTermScreen::termSizeChanged(int column, int row) { + FQ_TRACE("term", 3) << "The term size is changed to " << column << "x" << row; + syncBufferAndScreen(); + bufferSizeChanged(); + this->setPaintState(Repaint); + this->repaint(); +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* Display */ +/* */ +/* ------------------------------------------------------------------------ */ + +//set pixmap background + +void FQTermScreen::updateBackgroundPixmap() { + if (!hasBackground_) + return; + + switch (backgroundRenderOption_) { + case 0: + //tile + { + backgroundPixmap_ = QPixmap(clientRectangle_.size()); + QPainter painter(&backgroundPixmap_); + painter.drawTiledPixmap(backgroundPixmap_.rect(), originBackgroundPixmap_); + } + break; + case 1: + //center + { + backgroundPixmap_ = QPixmap(clientRectangle_.size()); + backgroundPixmap_.fill(colors_[0]); + QPainter painter(&backgroundPixmap_); + int x = (backgroundPixmap_.size() - originBackgroundPixmap_.size()).width() / 2; + int y = (backgroundPixmap_.size() - originBackgroundPixmap_.size()).height() / 2; + painter.drawPixmap(x, y, originBackgroundPixmap_); + } + break; + case 2: + //stretch + backgroundPixmap_ = originBackgroundPixmap_.scaled(clientRectangle_.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + break; + } + /* + hasBackground_ = false; + backgroundPixmap_ = pixmap; + backgroundPixmapType_ = nType; + QPalette palette; + + switch (nType) { + case 0: + // none + palette.setColor(backgroundRole(), colors_[0]); + setPalette(palette); + break; + case 1: + //{ // transparent{} + break; + case 2: + // tile + if (!pixmap.isNull()) + palette.setBrush(backgroundRole(), QBrush(pixmap)); + setPalette(palette); + // updateBackgroundPixmap( pixmap ); + hasBackground_ = true; + break; + //} + case 3: + // center + if (!pixmap.isNull()) { + QPixmap pxmBg = QPixmap(size()); + QPainter painter(&pxmBg); + pxmBg.fill(colors_[0]); + painter.drawPixmap((size().width() - pixmap.width()) / 2, + (size().height() - pixmap.height()) / 2, + pixmap.width(), pixmap.height(), pixmap); + palette.setBrush(backgroundRole(), QBrush(pxmBg)); + setPalette(palette); + // updateBackgroundPixmap(pxmBg); + hasBackground_ = true; + break; + } + case 4: + // stretch + if (!pixmap.isNull()) { + float sx = (float)size().width() / pixmap.width(); + float sy = (float)size().height() / pixmap.height(); + QMatrix matrix; + matrix.scale(sx, sy); + palette.setBrush(backgroundRole(), QBrush(pixmap.transformed(matrix))); + setPalette(palette); + // updateBackgroundPixmap(pixmap.transformed( matrix )); + hasBackground_ = true; + break; + } + default: + palette.setColor(backgroundRole(), colors_[0]); + setPalette(palette); + // setBackgroundColor( m_color[0] ); + + } + */ +} + +void FQTermScreen::cursorEvent() { + if (isBlinkCursor_) { + setPaintState(Cursor); + isCursorShown_ = !isCursorShown_; + update(); + } +} + +void FQTermScreen::blinkEvent() { + if (hasBlinkText_) { + isBlinkScreen_ = !isBlinkScreen_; + setPaintState(Blink); + update(); + } +} + +void FQTermScreen::paintEvent(QPaintEvent *pe) { + FQ_TRACE("screen", 8) << "paintEvent " << pe->rect().x() << "," << pe->rect().y() << " " + << pe->rect().width() << "x" << pe->rect().height(); + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, FQTermPref::getInstance()->openAntiAlias_); + painter.setRenderHint(QPainter::TextAntialiasing, FQTermPref::getInstance()->openAntiAlias_); + if (paintState_ == System) { + repaintScreen(pe, painter); + return; + } + + if (testPaintState(Repaint)) { + FQ_TRACE("screen", 8) << "paintEvent " << "repaint"; + repaintScreen(pe, painter); + clearPaintState(Repaint); + } + + if (testPaintState(NewData)) { + if (termBuffer_->isLightBackgroundMode() != is_light_background_mode_) { + FQ_TRACE("screen", 8) << "paintEvent " << "new data repaint"; + is_light_background_mode_ = termBuffer_->isLightBackgroundMode(); + if (is_light_background_mode_) { + colors_[0] = param_->foregroundColor_; + colors_[7] = param_->backgroundColor_; + } else { + colors_[0] = param_->backgroundColor_; + colors_[7] = param_->foregroundColor_; + } + repaintScreen(pe, painter); + } else { + FQ_TRACE("screen", 8) << "paintEvent " << "new data refresh"; + refreshScreen(painter); + } + + clearPaintState(NewData); + } + + if (testPaintState(Blink)) { + FQ_TRACE("screen", 8) << "paintEvent " << "blink"; + blinkScreen(painter); + clearPaintState(Blink); + } + + if (testPaintState(Cursor)) { + FQ_TRACE("screen", 8) << "paintEvent " << "cursor"; + updateCursor(painter); + clearPaintState(Cursor); + } + + if (testPaintState(Widget)) { + updateWidgetRect(painter); + clearPaintState(Widget); + } +} + +void FQTermScreen::blinkScreen(QPainter &painter) { + painter.setBackground(QBrush(colors_[0])); + + for (int index = bufferStart_; index <= bufferEnd_; index++) { + if (areLinesBlink_[index - bufferStart_]) { + const FQTermTextLine *pTextLine = termBuffer_->getTextLineInBuffer(index); + uint linelength = pTextLine->getWidth(); + const unsigned char *attr = pTextLine->getAttributes(); + for (uint i = 0; i < linelength; ++i) { + if (GETBLINK(attr[i])) { + int startx = i; + while (i < linelength && GETBLINK(attr[i])) { + ++i; + } + drawLine(painter, index, startx, i, false); + } + } + } + } +} + +void FQTermScreen::updateCursor(QPainter &painter) { + if (termBuffer_->getCaretColumn() >= termBuffer_->getNumColumns()) { + // we only allow the cursor located beyond the terminal screen temporarily. + // just ignore this. + return; + } + + bool isCursorShown = isCursorShown_; + if (FQTermPref::getInstance()->isBossColor_) { + isCursorShown = true; + } + + if (termBuffer_->getCaretLine() <= bufferEnd_ + && termBuffer_->getCaretLine() >= bufferStart_) { + + if (!isCursorShown) { + const FQTermTextLine *pTextLine + = termBuffer_->getTextLineInBuffer(termBuffer_->getCaretLine()); + if ((int)pTextLine->getWidth() > termBuffer_->getCaretColumn()) { + int startx = pTextLine->getCellBegin(termBuffer_->getCaretColumn()); + int endx = pTextLine->getCellEnd(termBuffer_->getCaretColumn() + 1); + if ((int)pTextLine->getWidth() > endx) { + endx = pTextLine->getCellEnd(endx + 1); + } + drawLine(painter, termBuffer_->getCaretLine(), startx, endx, + termBuffer_->getCaretLine()); + } else { + //painter.fillRect(mapToRect(termBuffer_->getCaretColumn(), termBuffer_->getCaretLine(), 1, 1),colors_[0]); + drawBackground(painter, mapToRect(termBuffer_->getCaretColumn(),termBuffer_->getCaretLine(), 1, 1), 0); + } + return; + } + + QPoint pt = mapToPixel(QPoint(termBuffer_->getCaretColumn(), + termBuffer_->getCaretLine())); + switch (param_->cursorType_) { + case 0: + // block + { + int x = termBuffer_->getCaretColumn(); + int y = termBuffer_->getCaretLine(); + const FQTermTextLine *pTextLine = termBuffer_->getTextLineInBuffer(y); + if ((int)pTextLine->getWidth() > x) { + + int startx = pTextLine->getCellBegin(x); + int endx = pTextLine->getCellEnd(x + 1); + + drawLine(painter, termBuffer_->getCaretLine(), startx, endx, + termBuffer_->getCaretLine()); + + QRect rect = mapToRect(startx, termBuffer_->getCaretLine(), 1, 1); + rect.translate(0, 0); + painter.fillRect(rect, colors_[7]); + } else { + QRect rect = mapToRect(termBuffer_->getCaretColumn(), + termBuffer_->getCaretLine(), 1, 1); + rect.translate(0, 0); + painter.fillRect(rect, + colors_[7]); + } + } + break; + case 1: + // underline + painter.fillRect(pt.x(), pt.y() + 9 * charHeight_ / 10, charWidth_, + charHeight_ / 10, colors_[7]); + break; + case 2: + // I type + painter.fillRect(pt.x(), pt.y() + 1, charWidth_ / 5, charHeight_ - 1, + colors_[7]); + break; + default: + painter.fillRect(pt.x(), pt.y()+1, + charWidth_, charHeight_ - 1, colors_[7]); + } + } +} + + +// refresh the screen when +// 1. received new contents form server +// 2. scrolled by user +void FQTermScreen::refreshScreen(QPainter &painter) { + FQ_FUNC_TIMER("screen_paint", 5); + + if (cursorTimer_->isActive()) { + cursorTimer_->stop(); + } + + if (blinkTimer_->isActive()) { + blinkTimer_->stop(); + } + + hasBlinkText_ = false; + isCursorShown_ = true; + + for (int index = bufferStart_; index <= bufferEnd_; index++) { + + FQ_VERIFY(index < termBuffer_->getNumLines()); + + const FQTermTextLine *pTextLine = termBuffer_->getTextLineInBuffer(index); + + if (pTextLine->hasBlink()) { + hasBlinkText_ = true; + areLinesBlink_[index - bufferStart_] = true; + } else { + areLinesBlink_[index - bufferStart_] = false; + } + + unsigned int startx, endx; + if (!pTextLine->getDirtyCells(startx, endx)) { + continue; + } + + /* + Finally get around this for pku & ytht, don't know why some weird things + happened when only erase and draw the changed part. + */ + startx = pTextLine->getCellBegin(startx); + + int len = -1; + if ((int)endx != -1) { + len = endx - startx; + } else { + len = pTextLine->getMaxCellCount() - startx; + } + + QRect rect = mapToRect(startx, index, len, 1); + + //painter.fillRect(rect ,QBrush(colors_[0])); + drawBackground(painter, rect, 0); + + drawLine(painter, index, startx, endx); + + session_->clearLineChanged(index); + } + + updateMicroFocus(); + if (termWindow_->isConnected()) { + updateCursor(painter); + } + + + if (termWindow_->isConnected()) { + cursorTimer_->start(1000); + } + + if (hasBlinkText_) { + blinkTimer_->start(1000); + } +} + +void FQTermScreen::repaintScreen(QPaintEvent *pe, QPainter &painter) { + FQ_FUNC_TIMER("screen_paint", 5); + + //painter.setBackground(QBrush(colors_[0])); + + FQ_TRACE("screen", 5) << "Client area: " << pe->rect().width() + << "x" << pe->rect().height(); + + QRect rect = pe->rect().intersect(clientRectangle_); + //painter.eraseRect(rect); + drawBackground(painter, rect, 0); + QPoint tlPoint = mapToChar(QPoint(rect.left(), rect.top())); + + QPoint brPoint = mapToChar(QPoint(rect.right(), rect.bottom())); + + for (int y = tlPoint.y(); y <= brPoint.y(); y++) { + drawLine(painter, y); + } + if (termWindow_->getUrlStartPoint() != termWindow_->getUrlEndPoint()) { + drawUnderLine(painter, termWindow_->getUrlStartPoint(), termWindow_->getUrlEndPoint()); + } + + +} + +///////////////////////////////////////////////// +//TODO: change to a more powerful function +FQTermScreen::TextRenderingType FQTermScreen::charRenderingType(const QChar& c) { + if (c == ' ') return HalfAndSpace; + if (c.unicode() > 0x7f && c.unicode() <= 0x2dff) { + return FullAndAlign; + } else if (c.unicode() > 0x2dff) { + if (cnFixedPitch_) + return FullNotAlign; + else + return FullAndAlign; + } + return HalfAndAlign; +} + +static bool isColorBlock(const QChar& c) { + if (!FQTermPref::getInstance()->isAnsciiEnhance_) return false; + return ((c.unicode() >= 0x2581 && c.unicode() <= 0x258f) || + (c.unicode() >= 0x25e2 && c.unicode() <= 0x25e5)); +} + +///////////////////////////////////////////////// +// draw a line with the specialAtter if given. +// modified by hooey to draw part of the line. +void FQTermScreen::drawLine(QPainter &painter, int index, int startx, int endx, + bool complete) { + FQ_ASSERT(index < termBuffer_->getNumLines()); + + const FQTermTextLine *pTextLine = termBuffer_->getTextLineInBuffer(index); + const unsigned char *color = pTextLine->getColors(); + const unsigned char *attr = pTextLine->getAttributes(); + + uint linelength = pTextLine->getWidth(); + bool isSessionSelected = session_->isSelectedMenu(index); + bool isTransparent = isSessionSelected && param_->menuType_ == 2; + + menuRect_ = QRect(); + QString cstrText; + + if (startx < 0) { + startx = 0; + } + + if (endx > (long)linelength || endx < 0) { + endx = linelength; + } + + if (complete == true && isSessionSelected) { + menuRect_ = drawMenuSelect(painter, index); + startx = 0; + endx = linelength; + } + + startx = pTextLine->getCellBegin(startx); + endx = pTextLine->getCellEnd(endx); + + bool isMonoSpace = true; + if (!cnFixedPitch_ + || !enFixedPitch_) { + isMonoSpace = false; + } + + + + for (unsigned i = startx; (long)i < endx;) { + startx = i; + unsigned char tempcp = color[i]; + unsigned char tempea = attr[i]; + unsigned cell_begin = pTextLine->getCellBegin(startx); + unsigned cell_end = pTextLine->getCellEnd(cell_begin + 1); + TextRenderingType temprt; + cstrText.clear(); + pTextLine->getPlainText(cell_begin, cell_end, cstrText); + temprt = charRenderingType(cstrText[0]); + bool color_block = isColorBlock(cstrText[0]); + + bool bSelected = termBuffer_->isSelected( + QPoint(i, index), param_->isRectSelect_); + + // get str of the same attribute + while ((long)i < endx && tempcp == color[i] && tempea == attr[i] && + bSelected == termBuffer_->isSelected( + QPoint(i, index), param_->isRectSelect_)) { + unsigned cellBegin = pTextLine->getCellBegin(i); + unsigned cellEnd = pTextLine->getCellEnd(cellBegin + 1); + cstrText.clear(); + pTextLine->getPlainText(cellBegin, cellEnd, cstrText); + if (temprt != charRenderingType(cstrText[0])) { + break; + } + bool colorBlock = isColorBlock(cstrText[0]); + if (cell_end != cellEnd && colorBlock || color_block && !colorBlock) { + break; + } + ++i; + } + + cell_end = pTextLine->getCellEnd(i); + cstrText.clear(); + pTextLine->getPlainText(cell_begin, cell_end, cstrText); + + unsigned j = i; + if (j > 0 && pTextLine->getCellBegin(j) == pTextLine->getCellBegin(j - 1) + && *(pTextLine->getColors() + j) != *(pTextLine->getColors() + j - 1)) { + j++; + } + for (; j < cell_end; ++j) { + cstrText.append((QChar)URC); + } + + int text_width = cell_end - cell_begin; + + bool draw_half_begin_char = false; + + if (startx > 0 && pTextLine->getCellBegin(startx) == pTextLine->getCellBegin(startx - 1) + && *(pTextLine->getColors() + startx) != *(pTextLine->getColors() + startx - 1)) { +//#if defined(WIN32) + draw_half_begin_char = true; +//#else +// startx++; +//#endif + } + + painter.setFont((temprt == HalfAndAlign || temprt == HalfAndSpace)?*englishFont_:*nonEnglishFont_); + if (isMonoSpace && temprt != FullAndAlign) { + QFont& font = (temprt == HalfAndAlign || temprt == HalfAndSpace)?*englishFont_:*nonEnglishFont_; + if (temprt == HalfAndAlign) { + font.setLetterSpacing(QFont::AbsoluteSpacing, enLetterSpacing_); + } else if (temprt == HalfAndSpace) { + font.setLetterSpacing(QFont::AbsoluteSpacing, spLetterSpacing_); + } else { + font.setLetterSpacing(QFont::AbsoluteSpacing, cnLetterSpacing_); + } + painter.setFont(font); + if (draw_half_begin_char) { + text_width--; + draw_half_begin_char = false; + } + drawStr(painter, cstrText, startx, index, text_width, + tempcp, tempea, isTransparent, bSelected); + font.setLetterSpacing(QFont::AbsoluteSpacing, 0.0); + } else if (temprt == FullNotAlign) { + nonEnglishFont_->setLetterSpacing(QFont::AbsoluteSpacing, cnLetterSpacing_); + painter.setFont(*nonEnglishFont_); + if (draw_half_begin_char) { + text_width--; + draw_half_begin_char = false; + } + drawStr(painter, cstrText, startx, index, text_width, + tempcp, tempea, isTransparent, bSelected); + nonEnglishFont_->setLetterSpacing(QFont::AbsoluteSpacing, 0.0); + } else if (temprt == HalfAndSpace) { + englishFont_->setLetterSpacing(QFont::AbsoluteSpacing, spLetterSpacing_); + painter.setFont(*englishFont_); + if (draw_half_begin_char) { + text_width--; + draw_half_begin_char = false; + } + drawStr(painter, cstrText, startx, index, text_width, + tempcp, tempea, isTransparent, bSelected); + englishFont_->setLetterSpacing(QFont::AbsoluteSpacing, 0.0); + }else { + englishFont_->setLetterSpacing(QFont::AbsoluteSpacing, enLetterSpacing_); + nonEnglishFont_->setLetterSpacing(QFont::AbsoluteSpacing, cnLetterSpacing_); + if (temprt == HalfAndAlign) + painter.setFont(*englishFont_); + else if (temprt == FullAndAlign) + painter.setFont(*nonEnglishFont_); + // Draw Characters one by one to fix the variable-width font + // display problem. + int offset = 0; + for (uint j = 0; (long)j < cstrText.length(); ++j) { + // TODO_UTF16: wrong character width here. + if (temprt == HalfAndAlign) { + drawStr(painter, (QString)cstrText.at(j), + startx + offset, index, 1, + tempcp, tempea, + isTransparent, bSelected); + offset++; + } else if (temprt == FullAndAlign){ + + + int w = 2; + if (draw_half_begin_char) { + w--; + } + drawStr(painter, (QString)cstrText.at(j), + startx + offset, index, w, + tempcp, tempea, + isTransparent, bSelected); + if (draw_half_begin_char) { + draw_half_begin_char = false; + offset--; + } + offset += 2; + + } + } + nonEnglishFont_->setLetterSpacing(QFont::AbsoluteSpacing, 0.0); + englishFont_->setLetterSpacing(QFont::AbsoluteSpacing, 0.0); + } + } +} +// +// draw functions +void FQTermScreen::drawStr(QPainter &painter, const QString &str, + int x, int y, int length, + unsigned char color, unsigned char attr, + bool transparent, bool selected) { + unsigned char cp = color; + unsigned char ea = attr; + + // test bold mask or always highlighted + if (GETBRIGHT(ea) || param_->isAlwaysHighlight_) { + cp |= SET_FG_HIGHLIGHT(1); + } + + // use 8-15 color + // test dim mask + if (GETDIM(ea)) { + } + + // test underline mask + if (GETUNDERLINE(ea)) { + QFont font = painter.font(); + font.setUnderline(true); + painter.setFont(font); + } else { + QFont font = painter.font(); + font.setUnderline(false); + painter.setFont(font); + } + // test blink mask + if (GETBLINK(ea)){} + // test rapidblink mask + if (GETRAPIDBLINK(ea)){} + // test reverse mask + if (GETREVERSE(ea)) { + cp = GET_INVERSE_COLOR(cp); + } + + if (selected) { + cp = GET_INVERSE_COLOR(cp); + } + + // test invisible mask + if (GETINVISIBLE(ea)) { + } + + + + int pen_color_index = GETFG(cp); + if (!param_->isAnsiColor_) { + if (GETBG(cp) != 0) { + pen_color_index = 0; + } else { + pen_color_index = 7; + } + } + painter.setPen(colors_[pen_color_index]); + + int brush_color_index = GETBG(cp); + if (!param_->isAnsiColor_) { + if (GETBG(cp) != 0) { + brush_color_index = 7; + } else { + brush_color_index = 0; + } + } + + + QBrush brush(colors_[brush_color_index]); + + // black on white without attr + if (FQTermPref::getInstance()->isBossColor_) { + painter.setPen(Qt::black); + brush = QBrush(Qt::white); + } + + QPoint pt = mapToPixel(QPoint(x, y)); + QRect rcErase = mapToRect(x, y, length, 1); + + if (!menuRect_.intersects(rcErase)){ + if (x == 0) { + rcErase.setLeft(rcErase.left() - 1); + } + //painter.fillRect(rcErase, brush); + drawBackground(painter, rcErase, brush_color_index); + if (x == 0) { + rcErase.setLeft(rcErase.left() + 1); + } + } else { + QRect rcKeep = menuRect_.intersected(rcErase); + rcKeep.setY(rcErase.y()); + rcKeep.setHeight(rcErase.height()); + if (rcErase.left() < rcKeep.left()) { + QPoint point = rcKeep.bottomLeft(); + point.setX(point.x() + 1); + point.setY(point.y() + 1); + painter.fillRect(QRect(rcErase.topLeft(), point), + brush); + } + if (rcKeep.right() < rcErase.right()) { + QPoint point = rcErase.bottomRight(); + point.setX(point.x() + 1); + point.setY(point.y() + 1); + + painter.fillRect(QRect(rcKeep.topRight(), point), + brush); + } + } + + if (!(isBlinkScreen_ && GETBLINK(attr))) { + FQ_TRACE("draw_text", 10) << "draw text: " << str; + + QFontMetrics qm = painter.fontMetrics(); + int font_height = qm.height(); + int expected_font_height = rcErase.height(); + int height_gap = expected_font_height - font_height; + int offset = (height_gap + 1)/2; + int ascent = qm.ascent() + offset; + +//#if defined(WIN32) + int verticalAlign = Qt::AlignVCenter; + switch(param_->alignMode_) { + case 0: + verticalAlign = Qt::AlignVCenter; + break; + case 1: + verticalAlign = Qt::AlignBottom; + break; + case 2: + verticalAlign = Qt::AlignTop; + break; + } + if (length > 2 || !isColorBlock(str[0])) { + painter.drawText(rcErase, Qt::AlignRight | verticalAlign, str); + } else { + //here length == 1 or == 2, isColorBlock == true, ensured in drawLine. + //when length == 1, we are drawing the second half of the block, + //otherwise the whole block. + //(c.unicode() >= 0x2581 && c.unicode() <= 0x258f) + //7 rectangles from shorter to taller (1/8 - 7/8 on the bottom) + //1 rectangle full + //7 rectangles from thicker to thinner (7/8 - 1/8 on the left) + //(c.unicode() >= 0x25e2 && c.unicode() <= 0x25e5) + //4 triangles bottom-right, bottom-left, top-left, top-right + QPolygon bound = rcErase; + QPolygon toDraw; + QRect rcFull = mapToRect(x, y, 2, 1); + rcFull.setBottom(rcFull.bottom() + 1); + rcFull.setRight(rcFull.right() + 1); + int unic = str[0].unicode(); + if (unic >= 0x2581 && unic <= 0x2588) { + toDraw = QRect(rcFull.left(), rcFull.top() - rcFull.height() * (unic - 0x2581 + 1 - 8) / 8, rcFull.width(), rcFull.height() * (unic - 0x2581 + 1) / 8); + } else if (unic > 0x2588 && unic <= 0x258f) { + toDraw = QRect(rcFull.left(), rcFull.top(), rcFull.width() * (8 - unic + 0x2589 - 1) / 8, rcFull.height()); + } else { //triangles + QVector points; + points.push_back(rcFull.topLeft()); + points.push_back(rcFull.topRight()); + points.push_back(rcFull.bottomRight()); + points.push_back(rcFull.bottomLeft()); + points.remove(unic - 0x25e2); + toDraw = points; + } + QBrush oldBrush = painter.brush(); + painter.setBrush(colors_[pen_color_index]); + QPen oldPen = painter.pen(); + painter.setPen(Qt::transparent); + painter.drawConvexPolygon(toDraw.intersected(bound)); + painter.setBrush(oldBrush); + painter.setPen(oldPen); + } +//#else +// painter.drawText(pt.x(), pt.y() + ascent, str); +//#endif + } +} + + +void FQTermScreen::eraseRect(QPainter &, int, int, int, int, short){ + FQ_VERIFY(false); +} + +void FQTermScreen::bossColor() { + if (FQTermPref::getInstance()->isBossColor_) { + colors_[0] = Qt::white; + colors_[7] = Qt::black; + QPalette palette; + palette.setColor(backgroundRole(), Qt::white); + setPalette(palette); + + } else { + colors_[0] = param_->backgroundColor_; + colors_[7] = param_->foregroundColor_; + } + + + setPaintState(Repaint); + update(); +} + +QRect FQTermScreen::drawMenuSelect(QPainter &painter, int index) { + QRect rcSelect, rcMenu, rcInter; + // FIXME: what is this for +/* + if (termBuffer_->isSelected(index)) { + bool is_rect_sel = param_->isRectSelect_; + rcSelect = mapToRect(termBuffer_->getSelectRect(index, is_rect_sel)); + if (FQTermPref::getInstance()->isBossColor_) { + painter.fillRect(rcSelect, QBrush(colors_[0])); + } else { + painter.fillRect(rcSelect, QBrush(colors_[7])); + } + } +*/ + if (session_->isSelectedMenu(index)) { + rcMenu = mapToRect(session_->getMenuRect()); + // m_pBand->setGeometry(rcMenu); + // m_pBand->show(); + switch (param_->menuType_) { + case 0: + // underline + painter.fillRect(rcMenu.x(), rcMenu.y() + 10 * charHeight_ / 11, + rcMenu.width(), charHeight_ / 11, colors_[7]); + break; + case 2: + painter.fillRect(rcMenu, QBrush(FQTermPref::getInstance()->isBossColor_?colors_[0]:param_->menuColor_)); + break; + } + } + return rcMenu; +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* Auxilluary */ +/* */ +/* ------------------------------------------------------------------------ */ + +QSize FQTermScreen::getScreenSize() const +{ + return QSize(termBuffer_->getNumColumns() * charWidth_, termBuffer_->getNumRows() * charHeight_); +} + +QPoint FQTermScreen::mapToPixel(const QPoint &point) { + int dx = (getScreenSize().width() - clientRectangle_.width()) * FQTermPref::getInstance()->displayOffset_ / 100; + int dy = getVerticalSetting(); + QPoint pt = clientRectangle_.topLeft(); + pt.setX(pt.x() - dx); + pt.setY(pt.y() - dy); + QPoint pxlPoint; + + pxlPoint.setX(point.x() *charWidth_ + pt.x()); + pxlPoint.setY((point.y() - bufferStart_) *charHeight_ + pt.y()); + + return pxlPoint; +} +// mapToChar: get a position in the window and return the +// corresponding char position +QPoint FQTermScreen::mapToChar(const QPoint &point) { + int dx = (getScreenSize().width() - clientRectangle_.width()) * FQTermPref::getInstance()->displayOffset_ / 100; + int dy = getVerticalSetting(); + QPoint pt = clientRectangle_.topLeft(); + pt.setX(pt.x() - dx); + pt.setY(pt.y() - dy); + QPoint chPoint; + chPoint.setX(qMin(qMax(0, int((point.x() - pt.x()) / charWidth_)), + termBuffer_->getNumColumns() - 1)); + chPoint.setY(qMin(qMax(0, int((point.y() - pt.y()) / charHeight_) + bufferStart_), + bufferEnd_)); + + //FIXME add bound check + return chPoint; +} + +QRect FQTermScreen::mapToRect(int x, int y, int width, int height) { + QPoint pt = mapToPixel(QPoint(x, y)); + + if (width == -1) { + // to the end + return QRect(pt.x(), pt.y(), getScreenSize().width(), charHeight_ *height); + } else { + return QRect(pt.x(), pt.y(), width *charWidth_, charHeight_ *height); + } +} + +QRect FQTermScreen::mapToRect(const QRect &rect) { + return mapToRect(rect.x(), rect.y(), rect.width(), rect.height()); +} + +// from KImageEffect::fade +QImage &FQTermScreen::fade(QImage &img, float val, const QColor &color) { + if (img.width() == 0 || img.height() == 0) { + return img; + } + + // We don't handle bitmaps + if (img.depth() == 1) { + return img; + } + + unsigned char tbl[256]; + for (int i = 0; i < 256; i++) { + tbl[i] = (int)(val *i + 0.5); + } + + int red = color.red(); + int green = color.green(); + int blue = color.blue(); + + QRgb col; + int r, g, b, cr, cg, cb; + + if (img.depth() <= 8) { + // pseudo color + for (int i = 0; i < img.numColors(); i++) { + col = img.color(i); + cr = qRed(col); + cg = qGreen(col); + cb = qBlue(col); + if (cr > red) { + r = cr - tbl[cr - red]; + } else { + r = cr + tbl[red - cr]; + } + if (cg > green) { + g = cg - tbl[cg - green]; + } else { + g = cg + tbl[green - cg]; + } + if (cb > blue) { + b = cb - tbl[cb - blue]; + } else { + b = cb + tbl[blue - cb]; + } + img.setColor(i, qRgba(r, g, b, qAlpha(col))); + } + } else { + // truecolor + for (int y = 0; y < img.height(); y++) { + QRgb *data = (QRgb*)img.scanLine(y); + for (int x = 0; x < img.width(); x++) { + col = *data; + cr = qRed(col); + cg = qGreen(col); + cb = qBlue(col); + if (cr > red) { + r = cr - tbl[cr - red]; + } else { + r = cr + tbl[red - cr]; + } + if (cg > green) { + g = cg - tbl[cg - green]; + } else { + g = cg + tbl[green - cg]; + } + if (cb > blue) { + b = cb - tbl[cb - blue]; + } else { + b = cb + tbl[blue - cb]; + } + *data++ = qRgba(r, g, b, qAlpha(col)); + } + } + } + + return img; +} + +void FQTermScreen::inputMethodEvent(QInputMethodEvent *e) { + FQ_TRACE("ime", 5) << "Preedit: " << e->preeditString(); + FQ_TRACE("ime", 5) << "Commit: " << e->commitString(); + + FQ_TRACE("ime", 8) << "Replace: " << e->replacementStart() + << ", " << e->replacementLength(); + + if (e->preeditString().size() > 0) { + nonEnglishFont_->setLetterSpacing(QFont::AbsoluteSpacing, 0.0); + preedit_line_->setPreeditText(e, nonEnglishFont_); + nonEnglishFont_->setLetterSpacing(QFont::AbsoluteSpacing, 0.0); + QPoint pt = mapToPixel(QPoint(termBuffer_->getCaretColumn(), + termBuffer_->getCaretLine())); + preedit_line_->move(pt); + preedit_line_->show(); + preedit_line_->update(); + } else { + preedit_line_->hide(); + } + + if (e->commitString().size() > 0) { + emit inputEvent(e->commitString()); + } +} + +QVariant FQTermScreen::inputMethodQuery(Qt::InputMethodQuery property) const { + FQ_TRACE("ime", 5) << "Query: " << property; + + int row = termBuffer_->getCaretRow(); + int col = termBuffer_->getCaretColumn(); + + switch (property) { + case Qt::ImMicroFocus: + // Here we must use (column + 1, row + 1) as the result, + // otherwise MS Pinyin or GPY won't work well. + return QVariant( + QRect((termBuffer_->getCaretColumn()) * charWidth_ + + (preedit_line_->isVisible() ? + preedit_line_->getCaretOffset() : 0), + (termBuffer_->getCaretRow()) * charHeight_, + charWidth_, charHeight_)); + case Qt::ImFont: + { + nonEnglishFont_->setLetterSpacing(QFont::AbsoluteSpacing, 0.0); + QVariant var(*nonEnglishFont_); + nonEnglishFont_->setLetterSpacing(QFont::AbsoluteSpacing, 0.0); + return var; + } + case Qt::ImCurrentSelection: + return QVariant(QString()); + case Qt::ImCursorPosition: + case Qt::ImSurroundingText: + { + tmp_im_query_->clear(); + const FQTermTextLine *line = termBuffer_->getTextLineInTerm(row); + line->getPlainText(0, line->getCellEnd(col), *tmp_im_query_); + + // TODO_UTF16: here only BMP is considered. + if (Qt::ImCursorPosition) { + return QVariant(tmp_im_query_->size()); + } else { + tmp_im_query_->clear(); + line->getPlainText(0, line->getWidth(), *tmp_im_query_); + return QVariant(QString(*tmp_im_query_)); + } + } + break; + default: + return QVariant(); + } +} + +void FQTermScreen::updateFixedPitchInfo() { + QFont cnFont(*nonEnglishFont_); + QFont enFont(*englishFont_); + int cnPixelSize = nonEnglishFont_->pixelSize() <= 5 ? 12 : nonEnglishFont_->pixelSize(); + int enPixelSize = englishFont_->pixelSize() <= 5 ? 12 : englishFont_->pixelSize(); + cnFont.setPixelSize(cnPixelSize); + enFont.setPixelSize(enPixelSize); + QString cnTestString = QString::fromUtf8("\xe5\x9c\xb0\xe6\x96\xb9\xe6\x94\xbf\xe5\xba\x9c"); + cnFixedPitch_ = (QFontMetrics(cnFont).width(cnTestString) == + cnTestString.length() * QFontMetrics(cnFont).width(cnTestString.at(0))); + QString enTestString = QString::fromUtf8("www.newsmth.net"); + enFixedPitch_ = QFontInfo(enFont).fixedPitch() && + (QFontMetrics(enFont).width(enTestString) == enTestString.length() * QFontMetrics(enFont).width(enTestString.at(0))); + + FQ_TRACE("font", 10) << "\nenglish: " << enFixedPitch_ + << "\n chinese: " << cnFixedPitch_; + +} + +void FQTermScreen::setTermFont(bool isEnglish, const QFont& font) +{ + QFont *&pFont = isEnglish?englishFont_:nonEnglishFont_; + delete pFont; + if (param_->isFontAutoFit_ == 1) { + pFont = new QFont(font.family()); + pFont->setKerning(false); + } else { + pFont = new QFont(font); + pFont->setKerning(false); + setFontMetrics(); + } + updateFixedPitchInfo(); + emit termFontChange(isEnglish, font); +} + +QFont FQTermScreen::termFont(bool isEnglish) { + return isEnglish?(*englishFont_):(*nonEnglishFont_); +} + +void FQTermScreen::drawUnderLine(QPainter &painter, const QPoint& startPoint, const QPoint& endPoint) { + if (startPoint.y() == endPoint.y()) { + drawSingleUnderLine(painter, startPoint, endPoint); + } else { + drawSingleUnderLine(painter, startPoint, QPoint(termBuffer_->getNumColumns(), startPoint.y())); + drawSingleUnderLine(painter, QPoint(0, endPoint.y()), endPoint); + for (int i = startPoint.y() + 1; i < endPoint.y(); ++i) { + drawSingleUnderLine(painter, QPoint(0, i), QPoint(termBuffer_->getNumColumns(), i)); + } + } +} + +void FQTermScreen::drawSingleUnderLine(QPainter &painter, const QPoint& startPoint, const QPoint& endPoint) { + FQ_VERIFY(startPoint.y() == endPoint.y()); + QPoint realStart = mapToPixel(startPoint); + QPoint realEnd = mapToPixel(endPoint); + painter.fillRect(realStart.x(), realStart.y() + 10 * charHeight_ / 11, + realEnd.x() - realStart.x(), charHeight_ / 11, FQTermPref::getInstance()->isBossColor_?colors_[0]:param_->menuColor_); +} + +void FQTermScreen::setFontAntiAliasing( bool on /*= true*/ ) { + englishFont_->setStyleStrategy(on?QFont::PreferAntialias:QFont::NoAntialias); + nonEnglishFont_->setStyleStrategy(on?QFont::PreferAntialias:QFont::NoAntialias); +} + +void FQTermScreen::widgetHideAt(const QRect& rect){ + widgetRect_ = rect; + setPaintState(Widget); + update(); +} + +void FQTermScreen::updateWidgetRect(QPainter& painter) { + + + + QRect rect = widgetRect_.intersect(clientRectangle_); + if (rect.isEmpty()) + return; + drawBackground(painter, rect, 0); + + QPoint tlPoint = mapToChar(QPoint(rect.left(), rect.top())); + + QPoint brPoint = mapToChar(QPoint(rect.right(), rect.bottom())); + + for (int y = tlPoint.y(); y <= brPoint.y(); y++) { + const FQTermTextLine *pTextLine = termBuffer_->getTextLineInBuffer(y); + int startx = qMin(tlPoint.x(),int(pTextLine->getWidth())); + int endx = qMin(brPoint.x(), int(pTextLine->getWidth())); + startx = pTextLine->getCellBegin(startx); + endx = pTextLine->getCellEnd(endx); + drawLine(painter, y, startx, endx); + } + widgetRect_ = QRect(); +} + +void FQTermScreen::drawBackgroundPixmap(QPainter& painter, const QRect& rect) { + if (!hasBackground_ || + FQTermPref::getInstance()->isBossColor_ || + backgroundPixmap_.isNull()) { + return; + } + if (backgroundCoverage_ == 1) { //Only padding, we do not draw screen background. + QRegion clip = rect; + QRect screenRect = mapToRect(0, termBuffer_->getNumLines() - termBuffer_->getNumRows(), termBuffer_->getNumColumns(), termBuffer_->getNumRows()); + clip -= screenRect; + QVector rects = clip.rects(); + foreach(QRect r, rects) { + painter.drawPixmap(r, backgroundPixmap_, r); + } + return; + } + painter.drawPixmap(rect, backgroundPixmap_, rect); +} + +int FQTermScreen::getVerticalSetting() const { + int dy = -1; + switch (FQTermPref::getInstance()->vsetting_) + { + case 0: + { + // Top + dy = 0; + break; + } + case 1: + { + // Middle + dy = (getScreenSize().height() - clientRectangle_.height()) / 2; + break; + } + case 2: + { + // Bottom + dy = (getScreenSize().height() - clientRectangle_.height()); + break; + } + default: + { + // The logic should never get here + break; + } + } + return dy; +} + +void FQTermScreen::drawBackground(QPainter& painter, const QRect& rect, int colorIndex) { + + if (FQTermPref::getInstance()->isBossColor_) { + painter.fillRect(rect, Qt::white); + return; + } + if (hasBackground_ && !backgroundPixmap_.isNull()) { + if (colorIndex == 0 || (backgroundCoverage_ != 1 && backgroundUseAlpha_)) + drawBackgroundPixmap(painter, rect); + if (backgroundCoverage_ == 1) { //Background only padding, we draw screen background. + QRegion clip = rect; + QRect screenRect = mapToRect(0, termBuffer_->getNumLines() - termBuffer_->getNumRows(), termBuffer_->getNumColumns(), termBuffer_->getNumRows()); + clip &= screenRect; + QVector rects = clip.rects(); + foreach(QRect r, rects) { + painter.fillRect(r, colors_[colorIndex]); + } + } else { + if (backgroundUseAlpha_) + painter.setOpacity(double(backgroundAlpha_) / 100); + if (colorIndex != 0 || backgroundUseAlpha_) + painter.fillRect(rect, colors_[colorIndex]); + painter.setOpacity(1.0); + } + return; + } + painter.fillRect(rect, colors_[colorIndex]); +} +PreeditLine::PreeditLine(QWidget *parent,const QColor *colors) + : QWidget(parent), + pixmap_(new QPixmap()), + colors_(colors) { + //setFocusPolicy(Qt::NoFocus); + hide(); +} + +PreeditLine::~PreeditLine() { + delete pixmap_; +} + +void PreeditLine::setPreeditText(QInputMethodEvent *e, const QFont *font) { + QString text = e->preeditString(); + + const QColor &white_color = colors_[7]; + const QColor &black_color = colors_[0]; + + // MS Pinyin will add a white space '\u3000' in the end. Remove it. + text = text.trimmed(); + + QFontMetrics fm(*font); + QRect textRect = fm.boundingRect(text); + + int width = textRect.width(); + int height = textRect.height(); + + delete pixmap_; + pixmap_ = new QPixmap(width, height + 1); // add one pixel to shadow + // the original cursor on + // screen. + this->resize(width, height + 1); + + QPainter painter(pixmap_); + painter.fillRect(textRect, QBrush(black_color)); + + painter.setFont(*font); + painter.setBackgroundMode(Qt::OpaqueMode); + + // Parse attributes of the input method event. + for (int i = 0; i < e->attributes().size(); ++i) { + const QInputMethodEvent::Attribute &a = e->attributes().at(i); + switch(a.type) { + case QInputMethodEvent::Cursor: + FQ_TRACE("ime", 10) << "Cursor: " << a.start << ", " << a.length; + { + painter.setPen(white_color); + + int caret_begin = fm.boundingRect(text.left(a.start)).right(); + + painter.drawLine(caret_begin, 0, caret_begin, height); + painter.drawLine(caret_begin + 1, 0, caret_begin + 1, height); + + caret_offset_ = caret_begin; + } + break; + case QInputMethodEvent::TextFormat: + { + if (a.start + a.length > text.size()) { + // index over flow. ignore it. + break; + } + + const QString &sub_text = text.mid(a.start, a.length); + + int x = fm.boundingRect(text.left(a.start)).width(); + + QTextCharFormat f = + qvariant_cast(a.value).toCharFormat(); + + // Hack here. + // If the background() is of style Qt::SolidPattern, + // we consider this segment of text is highlighted. + // Otherwise it's normal preedit text. + if (f.background().style() == Qt::SolidPattern) { + QBrush bg(white_color); + bg.setStyle(Qt::SolidPattern); + + painter.setBackground(bg); + painter.setPen(black_color); + } else { + QBrush bg(black_color); + bg.setStyle(Qt::SolidPattern); + + painter.setBackground(bg); + painter.setPen(white_color); + } + + // Draw the text; + painter.drawText(x, fm.ascent(), sub_text); + + FQ_TRACE("ime", 10) << "Sub-text: " << sub_text; + FQ_TRACE("ime", 10) << "Format: " << a.start << ", " << a.length; + FQ_TRACE("ime", 10) << "Background: " << f.background(); + FQ_TRACE("ime", 10) << "Pen: " << f.textOutline(); + } + break; + case QInputMethodEvent::Language: + FQ_TRACE("ime", 10) << "Language: " << a.start << ", " << a.length; + break; + case QInputMethodEvent::Ruby: + FQ_TRACE("ime", 10) << "Ruby: " << a.start << ", " << a.length; + break; + } + } + + // Draw a line under the preedit text. + QPen pen(white_color); + pen.setStyle(Qt::DashLine); + painter.setPen(pen); + painter.drawLine(0, height - 1, width, height - 1); +} + +void PreeditLine::paintEvent(QPaintEvent *e) { + QWidget::paintEvent(e); + QPainter p(this); + p.drawPixmap(QPointF(0, 0), *pixmap_, e->rect()); +} + +} // namespace FQTerm + +#include "fqterm_screen.moc" diff --git a/src/fqterm/fqterm_screen.h b/src/fqterm/fqterm_screen.h new file mode 100644 index 0000000..5c65142 --- /dev/null +++ b/src/fqterm/fqterm_screen.h @@ -0,0 +1,281 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SCREEN_H +#define FQTERM_SCREEN_H + +#include +#include +#include +#include "fqterm_param.h" +#include "fqterm_convert.h" + +class QTextCodec; +class QColor; +class QPainter; +class QInputMethodEvent; +class QPixmap; +class QScrollBar; +class QShortcut; + +namespace FQTerm { + +class FQTermWindow; +class FQTermBuffer; +class FQTermSession; +class FQTermParam; + +class PreeditLine: public QWidget { +public: + PreeditLine(QWidget *parent,const QColor *colors); + ~PreeditLine(); + + void setPreeditText(QInputMethodEvent *e, const QFont *font); + + void paintEvent(QPaintEvent * event); + + int getCaretOffset() const {return caret_offset_;} + +private: + QPixmap *pixmap_; + int caret_offset_; + + const QColor *colors_; +}; + +class FQTermScreen: public QWidget { + Q_OBJECT; + public: + + enum PaintState { + System = 0, Repaint = 1, NewData = 2, Blink = 4, Cursor = 8, Widget = 16 + }; + enum MouseState { + Enter, Press, Move, Release, Leave + }; + + FQTermScreen(QWidget *parent, FQTermSession *session); + ~FQTermScreen(); + + void setSchema(); + void setTermFont(bool isEnglish, const QFont& font); + + QFont termFont(bool isEnglish); + + + void setPaintState(PaintState ps) { + paintState_ |= ps; + } + + void clearPaintState(PaintState ps) { + paintState_ &= ~ps; + } + + bool testPaintState(PaintState ps) { + return paintState_ & ps; + } + + + /*void clearPaintState() { + paintState_ = None; + }*/ + // Buffer cell coordinate to screen pixel. + int getBufferStart() {return bufferStart_;} + QPoint mapToPixel(const QPoint &); + + // Screen pixel coordinate to buffer cell coordinate. + QPoint mapToChar(const QPoint &); + + // Buffer cell coordinate to screen pixel. + QRect mapToRect(int x, int y, int width, int height); + QRect mapToRect(const QRect &); + private: + int paintState_; + void updateWidgetRect(QPainter& painter); + void refreshScreen(QPainter &painter); + void blinkScreen(QPainter &painter); + void updateCursor(QPainter &painter); + void repaintScreen(QPaintEvent *pe, QPainter &painter); + void syncBufferAndScreen(); + void updateBackgroundPixmap(); + void drawBackground(QPainter& painter, const QRect& rect, int colorIndex); + void drawBackgroundPixmap(QPainter& painter, const QRect& rect); + int getVerticalSetting() const; + + signals: + // 0 - enter 1 - press 2 - move 3 - release 4 - leave + void mouseAction(int, QMouseEvent*); + void inputEvent(const QString&); + void termFontChange(bool isEnglish, QFont font); + + public slots: + void bufferSizeChanged(); + void termSizeChanged(int column, int row); + void bossColor(); + void updateScrollBar(); + void setFontAntiAliasing(bool on = true); + void widgetHideAt(const QRect& rect); + + + protected: + void initFontMetrics(); + + bool event(QEvent *e); + + void resizeEvent(QResizeEvent*); + void focusInEvent(QFocusEvent*); + void focusOutEvent(QFocusEvent*); + + void paintEvent(QPaintEvent*); + + // mouse + void enterEvent(QEvent*); + void leaveEvent(QEvent*); + void mousePressEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void wheelEvent(QWheelEvent*); + + // display + void eraseRect(QPainter &, int, int, int, int, short); + void drawStr(QPainter &painter, const QString &str, + int x, int y, int length, + unsigned char color, unsigned char attr, + bool transparent, bool selected = false); + void drawLine(QPainter &, int index, int startx = -1, int endx = -1, + bool complete = true); + void drawCaret(QPainter &, bool); + QRect drawMenuSelect(QPainter &, int); + void drawUnderLine(QPainter &, const QPoint& startPoint, const QPoint& endPoint); + + // auxiluary + int getPosX(int xChar) { + return xChar *charWidth_; + } + int getPosY(int yLine) { + return yLine *charHeight_; + } + + //screen size, in pixel. + QSize getScreenSize() const; + + + + void updateFont(); + void setFontMetrics(); + + QImage &fade(QImage &, float, const QColor &); + + void inputMethodEvent(QInputMethodEvent *e); + QVariant inputMethodQuery(Qt::InputMethodQuery property)const; + + + protected slots: + void blinkEvent(); + void cursorEvent(); + void scrollChanged(int); + void prevPage(); + void nextPage(); + void prevLine(); + void nextLine(); + void scrollLine(int); + protected: + void drawSingleUnderLine(QPainter &, const QPoint& startPoint, const QPoint& endPoint); + + QRect clientRectangle_; // the display area + QRect menuRect_; + QRect widgetRect_; //we need to redraw this rect since a widget just disappeared. + + int scrollBarWidth_; + + QScrollBar *scrollBar_; + + QTimer *blinkTimer_; + QTimer *cursorTimer_; + + bool isBlinkScreen_; + bool isBlinkCursor_; + bool hasBlinkText_; + + FQTermWindow *termWindow_; + FQTermSession *session_; + const FQTermBuffer *termBuffer_; + FQTermParam *param_; + + bool is_light_background_mode_; + + QColor colors_[16]; + QFont *englishFont_; + QFont *nonEnglishFont_; + + double fontAscent_, fontDescent_; + double charWidth_, charHeight_; + double cnLetterSpacing_; + double enLetterSpacing_; + double spLetterSpacing_; + + void updateFixedPitchInfo(); + bool cnFixedPitch_; + bool enFixedPitch_; + int lineSpacing_; // for future + + bool *areLinesBlink_; + bool isCursorShown_; + + // background + bool hasBackground_; + QPixmap backgroundPixmap_; + QPixmap originBackgroundPixmap_; + //0 -- tile 1 -- center 2 -- stretch + int backgroundRenderOption_; + //0 -- Whole screen, 1 -- Only padding + int backgroundCoverage_; + bool backgroundUseAlpha_; + int backgroundAlpha_; + + + // the range of the buffer's lines to be displayed + int bufferStart_; + int bufferEnd_; + + QShortcut *gotoPrevPage_; + QShortcut *gotoNextPage_; + QShortcut *gotoPrevLine_; + QShortcut *gotoNextLine_; + + FQTermConvert encodingConverter_; + + PreeditLine *preedit_line_; + + QString *tmp_im_query_; + + //TODO: change to bit field + enum TextRenderingType{ + HalfAndAlign, FullAndAlign, FullNotAlign, HalfAndSpace + }; + TextRenderingType charRenderingType(const QChar& c); + + friend class FQTermWindow; + // for test only +}; + +} // namespace FQTerm + +#endif // FQTERM_SCREEN_H diff --git a/src/fqterm/fqterm_scriptengine.cpp b/src/fqterm/fqterm_scriptengine.cpp new file mode 100644 index 0000000..efab413 --- /dev/null +++ b/src/fqterm/fqterm_scriptengine.cpp @@ -0,0 +1,488 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + + + +#include "fqterm_scriptengine.h" +#include "fqterm_window.h" +#include "fqterm_screen.h" +#include "fqterm_session.h" +#include "fqterm_buffer.h" +#include "common.h" +#include "fqterm_path.h" + +#ifdef HAVE_PYTHON +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace FQTerm { + + +template +QScriptValue qScriptValueFromQObject(QScriptEngine *engine, Tp &qobject) { + return engine->newQObject(qobject); +} + +template +void qScriptValueToQObject(const QScriptValue &value, Tp &qobject) { + qobject = qobject_cast(value.toQObject()); +} + +template +int qScriptRegisterQObjectMetaType( + QScriptEngine *engine, const QScriptValue &prototype = QScriptValue() + ) { + return qScriptRegisterMetaType(engine, qScriptValueFromQObject, + qScriptValueToQObject, prototype); +} + + +FQTermScriptEngine::FQTermScriptEngine(FQTermWindow* parent) +: QObject(parent), + window_(parent), + engine_(NULL), + articleCopyThread_(NULL), + timerIDCount_(0) { + FQ_VERIFY(window_); + session_ = window_->getSession(); + buffer_ = window_->getSession()->getBuffer(); + screen_ = window_->getScreen(); + articleCopyThread_ = new ArticleCopyThread(*session_, session_->getWaitCondition(), session_->getBufferLock()); + FQ_VERIFY(connect(articleCopyThread_, SIGNAL(articleCopied(int, const QString)), + this, SLOT(articleCopied(int, const QString)))); + engine_ = new QScriptEngine(); + engine_->globalObject().setProperty( + "fq_session", engine_->newQObject(session_)); + engine_->globalObject().setProperty( + "fq_window", engine_->newQObject(window_)); + engine_->globalObject().setProperty( + "fq_buffer", engine_->newQObject(buffer_)); + engine_->globalObject().setProperty( + "fq_screen", engine_->newQObject(screen_)); + engine_->globalObject().setProperty( + "fqterm", engine_->newQObject(this)); +} + +FQTermScriptEngine::~FQTermScriptEngine() { + engine_->abortEvaluation(); + delete engine_; +} + +void FQTermScriptEngine::runScript( const QString& filename ) { + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + FQ_TRACE("script", 0) << "Unable to open the script file: " << filename; + QMessageBox::warning(window_, tr("FQTerm"), + tr("Unable to open the script file\n") + filename, + QMessageBox::Close); + return; + } + + QString script = QString::fromUtf8(file.readAll()); + QFileInfo fileInfo(filename); + QScriptValue result = engine_->evaluate(script, fileInfo.absoluteFilePath()); + if (engine_->hasUncaughtException()) { + int line = engine_->uncaughtExceptionLineNumber(); + FQ_TRACE("script", 0) << "uncaught exception at line " << line + << ":" << result.toString(); + QMessageBox::warning(window_, tr("FQTerm"), + tr("uncaught exception at line ") + QString::number(line) + + ":\n" + result.toString(), + QMessageBox::Close); + } +} + +void FQTermScriptEngine::stopScript() { + //all loops should be stopped here. + articleCopied_ = true; + engine_->abortEvaluation(); +} + +void FQTermScriptEngine::msgBox( const QString& msg ) { + QMessageBox::warning(window_, tr("FQTerm"), + msg, + QMessageBox::Close); +} + +int FQTermScriptEngine::caretX() { + return buffer_->getCaretColumn(); +} + +int FQTermScriptEngine::caretY() { + return buffer_->getCaretRow(); +} + +int FQTermScriptEngine::columns() { + return buffer_->getNumColumns(); +} + +int FQTermScriptEngine::rows() { + return buffer_->getNumRows(); +} + +void FQTermScriptEngine::sendString(const QString& str) { + window_->writeRawString(str); +} + +void FQTermScriptEngine::sendParsedString( const QString& str ){ + window_->externInput(str); +} + +QString FQTermScriptEngine::getText(int row) { + QString str; + if (row < rows()) + buffer_->getTextLineInTerm(row)->getAllPlainText(str); + return str; +} + +QString FQTermScriptEngine::getAttrText(int row) { + QString str; + if (row < rows()) + buffer_->getTextLineInTerm(row)->getAllAnsiText(str); + return str; +} + +bool FQTermScriptEngine::isConnected() { + return window_->isConnected(); +} + +void FQTermScriptEngine::disconnect() { + window_->disconnect(); +} + +void FQTermScriptEngine::reconnect() { + session_->reconnect(); +} + +//FIXME: UTF8 and HKSCS +QString FQTermScriptEngine::getBBSCodec() { + return session_->param().serverEncodingID_ == 0 ? "GBK" : "Big5"; +} + +QString FQTermScriptEngine::getAddress() { + return session_->param().hostAddress_; +} + +int FQTermScriptEngine::getPort() { + return session_->param().port_; +} +// connection protocol 0-telnet 1-SSH1 2-SSH2 +int FQTermScriptEngine::getProtocol() { + return session_->param().protocolType_; +} + +QString FQTermScriptEngine::getReplyKey() { + return session_->param().replyKeyCombination_; +} + +QString FQTermScriptEngine::getURL() { + return session_->getUrl(); +} + +QString FQTermScriptEngine::getIP() { + return session_->getIP(); +} + +void FQTermScriptEngine::previewImage(const QString& url) { + window_->getHttpHelper(url, true); +} + +void FQTermScriptEngine::sleep(int ms) { + int originInterval = engine_->processEventsInterval(); + engine_->setProcessEventsInterval(1); + QString busy_wait = "var start = new Date().getTime();\n" + "while(true) {if(new Date().getTime() - start > " + QString("%1").arg(ms) + ") break;}\n"; + engine_->evaluate(busy_wait); + engine_->setProcessEventsInterval(originInterval); +} + +//TODO: flags +void FQTermScriptEngine::articleCopied(int state, const QString content) { + if (state == DAE_FINISH) { + articleCopied_ = true; + articleText_ = content; + } else /*if (state == DAE_TIMEOUT)*/ { + articleCopied_ = true; + articleText_ = ""; + } +} + +QString FQTermScriptEngine::copyArticle() { + articleCopied_ = false; + articleText_ = ""; + articleCopyThread_->wait(); + articleCopyThread_->start(); + while(!articleCopied_) { + sleep(200); + } + return articleText_; +} + +void FQTermScriptEngine::finalizeScript() { + engine_->setProcessEventsInterval(-1); + stopScript(); + setParent(NULL); + //TODO: safe? + deleteLater(); +} + +void FQTermScriptEngine::writeFile( const QString& filename, const QString& str ) { + QFile file(filename); + file.open(QIODevice::WriteOnly); + file.write(U2U8(str)); + file.close(); +} + +QString FQTermScriptEngine::readFile( const QString& filename ) { + QFile file(filename); + file.open(QIODevice::ReadOnly); + QString str = U82U(file.readAll()); + file.close(); + return str; +} + +void FQTermScriptEngine::appendFile( const QString& filename, const QString& str ) { + QFile file(filename); + file.open(QIODevice::WriteOnly | QIODevice::Append); + file.write(U2U8(str)); + file.close(); +} + +QStringList FQTermScriptEngine::readFolder( const QString& path ) { + return QDir(path).entryList(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot | QDir::Readable); +} + +QString FQTermScriptEngine::platform() { +#if defined(WIN32) + return "Win"; +#elif defined(__unix__) && !defined(__APPLE__) + return "Linux"; +#else + return "Mac"; +#endif +} + +bool FQTermScriptEngine::makePath( const QString& path ){ + return QDir().mkpath(path); +} + +QString FQTermScriptEngine::newLine() { + return OS_NEW_LINE; +} + +void FQTermScriptEngine::openUrl(const QString & url) { + window_->openUrlImpl(url); +} + +QString FQTermScriptEngine::getSelect(bool color_copy) { + return buffer_->getTextSelected( + session_->param().isRectSelect_, + color_copy, + window_->parseString((const char*)session_->param().escapeString_.toLatin1())); +} + +QList FQTermScriptEngine::mapToChar(int screenX, int screenY) { + QPoint charP(screen_->mapToChar(QPoint(screenX, screenY))); + QList result; + result << charP.x() << charP.y() - screen_->getBufferStart(); + return result; +} + +int FQTermScriptEngine::charX(int screen_x) { + return screen_->mapToChar(QPoint(screen_x, 0)).x(); +} + +int FQTermScriptEngine::charY(int screen_y) { + return screen_->mapToChar(QPoint(0, screen_y)).y() - screen_->getBufferStart(); +} + +QString FQTermScriptEngine::getTextAt( int row, int column, int len ) { + if (column < 0 || column >= columns() || + row < 0 || row >= rows()) + return ""; + if (column + len > columns() || len < 0) { + len = columns() - column; + } + QString result; + buffer_->getTextLineInTerm(row)->getPlainText(column, column + len, result); + return result; +} + +QString FQTermScriptEngine::getAttrTextAt( int row, int column, int len ) { + if (column < 0 || column >= columns() || + row < 0 || row >= rows()) + return ""; + if (column + len > columns() || len < 0) { + len = columns() - column; + } + QString result; + buffer_->getTextLineInTerm(row)->getAnsiText(column, column + len, result); + return result; +} + +QString FQTermScriptEngine::getFullTextAt(int row, int column, int len) { + return getTextAt(row, buffer_->getTextLineInTerm(row)->getCellBegin(column), len); +} + +QString FQTermScriptEngine::getFullAttrText(int row, int column, int len) { + return getAttrTextAt(row, buffer_->getTextLineInTerm(row)->getCellBegin(column), len); +} + +int FQTermScriptEngine::mouseSX() { + return screen_->mapFromGlobal(QCursor::pos()).x(); +} + +int FQTermScriptEngine::mouseSY() { + return screen_->mapFromGlobal(QCursor::pos()).y(); +} + +int FQTermScriptEngine::screenX( int char_x ){ + return screen_->mapToPixel(QPoint(char_x, 0)).x(); +} + +int FQTermScriptEngine::screenY( int char_y ){ + return screen_->mapToPixel(QPoint(0, char_y + screen_->getBufferStart())).y(); +} + +bool FQTermScriptEngine::scriptCallback( const QString& func, const QScriptValueList& args ) { + QScriptValue f = engine_->globalObject().property("fqterm").property(func); + if (f.isFunction()) { + QScriptValue res = f.call(QScriptValue(), args); + if (!engine_->hasUncaughtException() && res.isBool()) { + return res.toBool(); + } else { + return false; + } + } + return false; +} + +bool FQTermScriptEngine::importFile( const QString& filename ) { + QFileInfo fileInfo(filename); + if (!fileInfo.isAbsolute()) { + //first search current running path. + if (engine_->currentContext() && engine_->currentContext()->parentContext()) { + QString runningFile = QScriptContextInfo(engine_->currentContext()->parentContext()).fileName(); + if (!runningFile.isEmpty()) { + QFileInfo current(runningFile); + fileInfo = QFileInfo(current.absolutePath() + '/' + filename); + } + } + //then look in script folder. + if (!fileInfo.exists()) { + fileInfo = QFileInfo(getPath(RESOURCE) + "script/" + filename); + } + } + if (!fileInfo.exists()) { + return false; + } + fileInfo.makeAbsolute(); + runScript(fileInfo.absoluteFilePath()); + return true; +} + +int FQTermScriptEngine::setInterval(int ms, const QScriptValue& func) { + return createTimer(ms, func, false); +} + + +void FQTermScriptEngine::clearInterval(int id) { + destroyTimer(id); +} + +void FQTermScriptEngine::serverRedraw() { + sendParsedString("^L"); +} + +void FQTermScriptEngine::clientRedraw() { + window_->refreshScreen(); +} + +void FQTermScriptEngine::setMenuRect(int row, int column, int len) { + if (column < 0 || column >= columns() || + row < 0 || row >= rows()) + return ; + if (column + len > columns() || len < 0) { + len = columns() - column; + } + row += screen_->getBufferStart(); + session_->setMenuRect(row, column, len); +} + +int FQTermScriptEngine::setTimeout(int ms, const QScriptValue& func) { + return createTimer(ms, func, true); +} + +void FQTermScriptEngine::clearTimeout(int id) { + destroyTimer(id); +} + +int FQTermScriptEngine::createTimer(int ms, const QScriptValue& func, bool singleShot) { + QTimer* timer = new QTimer(this); + timer->setInterval(ms); + timer->setSingleShot(singleShot); + int id = timerIDCount_++; + if (timerTable_.find(id) != timerTable_.end()) { + //actually impossible! + destroyTimer(id); + } + timerTable_[id] = timer; + bool res = qScriptConnect(timer, SIGNAL(timeout()), QScriptValue(), func); + timer->start(); + return id; +} + +void FQTermScriptEngine::destroyTimer(int id) { + if (timerTable_.find(id) != timerTable_.end()) { + timerTable_[id]->stop(); + delete timerTable_[id]; + timerTable_.erase(id); + } +} + +int FQTermScriptEngine::getUIEventInterval() { + return engine_->processEventsInterval(); +} + +void FQTermScriptEngine::setUIEventInterval(int ms) { + engine_->setProcessEventsInterval(ms); +} + +bool FQTermScriptEngine::isAntiIdle() { + return session_->isAntiIdle(); +} + +bool FQTermScriptEngine::isAutoReply() { + return session_->isAutoReply(); +} +} // namespace FQTerm + +#include "fqterm_scriptengine.moc" \ No newline at end of file diff --git a/src/fqterm/fqterm_scriptengine.h b/src/fqterm/fqterm_scriptengine.h new file mode 100644 index 0000000..70ca5cd --- /dev/null +++ b/src/fqterm/fqterm_scriptengine.h @@ -0,0 +1,147 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#ifndef FQTERM_SCRIPTENGINE_H +#define FQTERM_SCRIPTENGINE_H + +#include "fqterm.h" +#include +#include +#include +#include +#include +#include +#include +class QString; +class QTimer; +namespace FQTerm { +class FQTermWindow; +class FQTermSession; +class FQTermScreen; +class FQTermBuffer; +class ArticleCopyThread; +class FQTermScriptEngine : public QObject { + Q_OBJECT; +public: + FQTermScriptEngine(FQTermWindow* parent); + ~FQTermScriptEngine(); + QScriptEngine* getQtEngine() {return engine_;} + void runScript(const QString& filename); + void stopScript(); + void finalizeScript(); + +public: + bool scriptCallback(const QString& func, const QScriptValueList& args); +public slots: //script apis + //ui functions. + void msgBox(const QString& msg); + + //bbs ui functions + int caretX(); + int caretY(); + QString getText(int row); + QString getTextAt(int row, int column, int len); + //if we get from a column that contains the second part + //of a character with width == 2, we could still get it. + QString getFullTextAt(int row, int column, int len); + QString getAttrText(int row); + QString getAttrTextAt(int row, int column, int len); + QString getFullAttrText(int row, int column, int len); + void sendString(const QString& str); + void sendParsedString(const QString& str); + void serverRedraw(); + void clientRedraw(); + int columns(); + int rows(); + bool isConnected(); + void disconnect(); + void reconnect(); + QString getBBSCodec(); + QString getAddress(); + int getPort(); + int getProtocol(); + QString getReplyKey(); + QString getURL(); + QString getIP(); + void previewImage(const QString& url); + void sleep(int ms); + QString copyArticle(); + void openUrl(const QString & url); + QString getSelect(bool color_copy); + QList mapToChar(int screenX, int screenY); + //next 2 functions are map screen to char for x, y. + int charX(int screen_x); + int charY(int screen_y); + int screenX(int char_x); + int screenY(int char_y); + //mouse position is given in screen coordinate. + int mouseX() {return charX(mouseSX());} + int mouseY() {return charY(mouseSY());} + + int mouseSX(); + int mouseSY(); + + void setMenuRect(int row, int col, int len); + + bool importFile(const QString& filename); + + bool isAntiIdle(); + bool isAutoReply(); + //auxiliary functions. + //should be move to some other class. + //qt script provides so poor extensions to js. + void writeFile(const QString& filename, const QString& str); + void appendFile(const QString& filename, const QString& str); + QString readFile(const QString& filename); + QStringList readFolder(const QString& path); + QString platform(); + bool makePath(const QString& path); + QString newLine(); + + //Timer + int setInterval(int ms, const QScriptValue& func); + void clearInterval(int id); + int setTimeout(int ms, const QScriptValue& func); + void clearTimeout(int id); + + int getUIEventInterval(); + void setUIEventInterval(int ms); +private: + int createTimer(int ms, const QScriptValue& func, bool singleShot); + void destroyTimer(int id); + +private slots: + void articleCopied(int state, const QString content); +private: + QScriptEngine* engine_; + FQTermWindow* window_; + FQTermSession* session_; + FQTermScreen* screen_; + FQTermBuffer* buffer_; + ArticleCopyThread* articleCopyThread_; + bool articleCopied_; + QString articleText_; + std::map timerTable_; + int timerIDCount_; +}; + + +}//namespace FQTerm +#endif //FQTERM_SCRIPTENGINE_H \ No newline at end of file diff --git a/src/fqterm/fqterm_window.cpp b/src/fqterm/fqterm_window.cpp new file mode 100644 index 0000000..bb2c867 --- /dev/null +++ b/src/fqterm/fqterm_window.cpp @@ -0,0 +1,2531 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "addrdialog.h" +#include "articledialog.h" +#include "msgdialog.h" +#include "osdmessage.h" +#include "popwidget.h" +#include "progressBar.h" +#include "common.h" +#include "fqterm_buffer.h" +#include "fqterm_canvas.h" +#include "fqterm_config.h" +#include "fqterm_convert.h" +#include "fqterm_filedialog.h" +#include "fqterm_frame.h" +#include "fqterm_http.h" +#include "fqterm_ip_location.h" +#include "fqterm_param.h" +#include "fqterm_path.h" +#include "fqterm_screen.h" +#include "fqterm_session.h" +#include "fqterm_sound.h" +#include "fqterm_window.h" +#include "fqterm_wndmgr.h" +#include "imageviewer.h" +#include "sshlogindialog.h" +#include "statusBar.h" +#include "zmodemdialog.h" +#ifdef HAVE_PYTHON +#include +#include "fqterm_python.h" +#endif //HAVE_PYTHON +#include "fqterm_scriptengine.h" + + +namespace FQTerm { + +char FQTermWindow::directions_[][5] = { + // 4 + "\x1b[1~", // 0 HOME + "\x1b[4~", // 1 END + "\x1b[5~", // 2 PAGE UP + "\x1b[6~", // 3 PAGE DOWN + // 3 + "\x1b[A", // 4 UP + "\x1b[B", // 5 DOWN + "\x1b[D", // 6 LEFT + "\x1b[C" // 7 RIGHT +}; + +class FAQ: public QObject { + Q_OBJECT; + public slots: + FAQ() {a = 100;} + + int get() {return a;} + + private: + int a; +}; + + +//constructor +FQTermWindow::FQTermWindow(FQTermConfig *config, FQTermFrame *frame, FQTermParam param, + int addressIndex, QWidget *parent, + const char *name, Qt::WFlags wflags) + : QMainWindow(parent, wflags), + frame_(frame), + isSelecting_(false), + addressIndex_(addressIndex), + sound_(NULL), + isMouseClicked_(false), + blinkStatus_(true), + isUrlUnderLined_(false), +#ifdef HAVE_PYTHON + // the system wide script + pythonScriptLoaded_(false), + // python thread module + pModule(NULL), + pDict(NULL), +#endif + script_engine_(NULL), + externalEditor_(NULL) { + // isMouseX11_ = false; + session_ = new FQTermSession(config, param); + screen_ = new FQTermScreen(this, session_); + + config_ = config; + zmodemDialog_ = new zmodemDialog(this); + + externalEditor_ = new FQTermExternalEditor(this); + + pageViewMessage_ = new PageViewMessage(this); + tabBlinkTimer_ = new QTimer; + + setWindowIcon(QIcon("noicon")); + setWindowTitle(param.name_); + setMouseTracking(true); + setFocusProxy(screen_); + setCentralWidget(screen_); + addMenu(); + setStatusBar(NULL); + + + FQ_VERIFY(connect(pageViewMessage_, SIGNAL(hideAt(const QRect&)), + screen_, SLOT(widgetHideAt(const QRect&)))); + + FQ_VERIFY(connect(frame_, SIGNAL(bossColor()), + screen_, SLOT(bossColor()))); + + FQ_VERIFY(connect(frame_, SIGNAL(fontAntiAliasing(bool)), + screen_, SLOT(setFontAntiAliasing(bool)))); + + FQ_VERIFY(connect(frame_, SIGNAL(changeLanguage()), + this, SLOT(recreateMenu()))); + FQ_VERIFY(connect(frame_, SIGNAL(bossColor()), + screen_, SLOT(bossColor()))); + FQ_VERIFY(connect(frame_, SIGNAL(updateScroll()), + screen_, SLOT(updateScrollBar()))); + + FQ_VERIFY(connect(screen_, SIGNAL(inputEvent(const QString&)), + session_, SLOT(handleInput(const QString&)))); + + FQ_VERIFY(connect(session_, SIGNAL(zmodemStateChanged(int, int, const char*)), + this, SLOT(ZmodemState(int, int, const char *)))); + FQ_VERIFY(connect(zmodemDialog_, SIGNAL(canceled()), + session_, SLOT(cancelZmodem()))); + FQ_VERIFY(connect(session_, SIGNAL(connectionClosed()), + this, SLOT(connectionClosed()))); + FQ_VERIFY(connect(session_, SIGNAL(startAlert()), this, SLOT(startBlink()))); + FQ_VERIFY(connect(session_, SIGNAL(stopAlert()), this, SLOT(stopBlink()))); + // FQ_VERIFY(connect(session_->decoder_, SIGNAL(mouseMode(bool)), + // this, SLOT(setMouseMode(bool)))); + FQ_VERIFY(connect(session_, SIGNAL(articleCopied(int, const QString)), + this, SLOT(articleCopied(int, const QString)))); + FQ_VERIFY(connect(session_, SIGNAL(requestUserPwd(QString*, QString*, bool*)), + this, SLOT(requestUserPwd(QString *, QString *, bool *)))); + //connect telnet signal to slots + // QVERIFY(connect(session_->telnet_, SIGNAL(readyRead(int)), + // this, SLOT(readReady(int)))); + FQ_VERIFY(connect(session_, SIGNAL(sessionUpdated()), + this, SLOT(sessionUpdated()))); + FQ_VERIFY(connect(session_, SIGNAL(bellReceived()), this, SLOT(beep()))); + FQ_VERIFY(connect(session_, SIGNAL(onTitleSet(const QString&)), this, SLOT(onTitleSet(const QString&)))); + + FQ_VERIFY(connect(session_, SIGNAL(messageAutoReplied()), + this, SLOT(messageAutoReplied()))); + FQ_VERIFY(connect(session_, SIGNAL(telnetStateChanged(int)), + this, SLOT(TelnetState(int)))); + FQ_VERIFY(connect(session_, SIGNAL(errorMessage(QString)), + this, SLOT(showSessionErrorMessage(QString)))); + + FQ_VERIFY(connect(tabBlinkTimer_, SIGNAL(timeout()), this, SLOT(blinkTab()))); + + FQ_VERIFY(connect(externalEditor_, SIGNAL(done(const QString&)), this, SLOT(externalEditorDone(const QString&)))); + + FQ_VERIFY(connect(this, SIGNAL(writeStringSignal(const QString&)), this, SLOT(writeString(const QString&)), Qt::QueuedConnection)); + FQ_VERIFY(connect(this, SIGNAL(writeRawStringSignal(const QString&)), this, SLOT(writeRawString(const QString&)), Qt::QueuedConnection)); + +#if defined(WIN32) + popWindow_ = new popWidget(this, frame_); +#else + popWindow_ = new popWidget(this); +#endif + + const QString &resource_dir = getPath(RESOURCE); + + cursors_[FQTermSession::kHome] = QCursor( + QPixmap(resource_dir + "cursor/home.xpm")); + cursors_[FQTermSession::kEnd] = QCursor( + QPixmap(resource_dir + "cursor/end.xpm")); + cursors_[FQTermSession::kPageUp] = QCursor( + QPixmap(resource_dir + "cursor/pageup.xpm")); + cursors_[FQTermSession::kPageDown] = QCursor( + QPixmap(resource_dir + "cursor/pagedown.xpm")); + cursors_[FQTermSession::kUp] = QCursor( + QPixmap(resource_dir + "cursor/prev.xpm")); + cursors_[FQTermSession::kDown] = QCursor( + QPixmap(resource_dir + "cursor/next.xpm")); + cursors_[FQTermSession::kLeft] = QCursor( + QPixmap(resource_dir + "cursor/exit.xpm"), 0, 10); + cursors_[FQTermSession::kRight] = QCursor( + QPixmap(resource_dir + "cursor/hand.xpm")); + cursors_[FQTermSession::kNormal] = Qt::ArrowCursor; + + script_engine_ = new FQTermScriptEngine(this); + if (session_->param().isAutoLoadScript_ + && !session_->param().autoLoadedScriptFileName_.isEmpty()) { + const QString &filename = session_->param().autoLoadedScriptFileName_; +#ifdef HAVE_PYTHON + if (filename.trimmed().endsWith(".py", Qt::CaseInsensitive)){ + initPython(filename); + } else { + initPython(""); +#endif + runScript(filename); +#ifdef HAVE_PYTHON + } + } else { + initPython(""); +#endif //HAVE_PYTHON + } + session_->setScriptListener(this); +} + +FQTermWindow::~FQTermWindow() { +#ifdef HAVE_PYTHON + finalizePython(); +#endif //HAVE_PYTHON + script_engine_->finalizeScript(); + // delete telnet_; + delete session_; + delete popWindow_; + delete tabBlinkTimer_; + delete menu_; + delete urlMenu_; + delete screen_; + delete pageViewMessage_; + //delete script_engine_; +} + +void FQTermWindow::addMenu() { + urlMenu_ = new QMenu(screen_); + urlMenu_->addAction(tr("Preview image"), this, SLOT(previewLink())); + urlMenu_->addAction(tr("Open link"), this, SLOT(openLink())); + urlMenu_->addAction(tr("Save As..."), this, SLOT(saveLink())); + urlMenu_->addAction(tr("Copy link address"), this, SLOT(copyLink())); + urlMenu_->addSeparator(); + urlMenu_->addAction(tr("Share Selected Text and URL!"), this, SLOT(shareIt())); + const QString &resource_dir = getPath(RESOURCE); + + menu_ = new QMenu(screen_); +#if defined(__APPLE__) + // Please note that on MacOSX Qt::CTRL corresponds to Command key (apple key), + // while Qt::Meta corresponds to Ctrl key. + QKeySequence copy_shortcut(tr("Ctrl+C")); + QKeySequence paste_shortcut(tr("Ctrl+V")); +#else + QKeySequence copy_shortcut(tr("Ctrl+Insert")); + QKeySequence paste_shortcut(tr("Shift+Insert")); +#endif + menu_->addAction(QPixmap(resource_dir + "pic/copy.png"), tr("Copy"), + this, SLOT(copy()), copy_shortcut); + menu_->addAction(QPixmap(resource_dir + "pic/paste.png"), tr("Paste"), + this, SLOT(paste()), paste_shortcut); + + menu_->addAction(QPixmap(resource_dir+"pic/get_article_fulltext.png"), tr("Copy Article"), + this, SLOT(copyArticle())); + menu_->addSeparator(); + + QMenu *fontMenu = new QMenu(menu_); + fontMenu->setTitle(tr("Font")); + fontMenu->setIcon(QPixmap(resource_dir + "pic/change_fonts.png")); + for (int i = 0; i < 2; ++i) { + QAction *act = fontMenu->addAction( + FQTermParam::getLanguageName(bool(i)) + tr(" Font"), + this, SLOT(setFont())); + act->setData(i); + } + menu_->addMenu(fontMenu); + + menu_->addAction(QPixmap(resource_dir + "pic/ansi_color.png"), tr("Color"), + this, SLOT(setColor())); + menu_->addSeparator(); + menu_->addAction(QPixmap(resource_dir + "pic/preferences.png"), tr("Setting"), + this, SLOT(setting())); + menu_->addSeparator(); + menu_->addAction(tr("Open Selected As Url"), this, SLOT(openAsUrl())); + menu_->addAction(tr("Search Selected Text!"), this, SLOT(searchIt())); + menu_->addAction(tr("Share Selected Text and URL!"), this, SLOT(shareIt())); +} + +void FQTermWindow::recreateMenu() { + delete urlMenu_; + delete menu_; + addMenu(); +} + +//close event received +void FQTermWindow::closeEvent(QCloseEvent *clse) { + bool toClose = true; + if (isConnected() && FQTermPref::getInstance()->openWarnOnClose_) { + QMessageBox mb(tr("FQTerm"), + tr("Still connected, do you really want to exit?"), + QMessageBox::Warning, QMessageBox::Yes|QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape, 0, this); + if (mb.exec() != QMessageBox::Yes) { + toClose = false; + } + } + if (toClose) { + session_->close(); + } else { + clse->ignore(); + return; + } + //We no longer save setting on close from r1036. + //saveSetting(); +} + +void FQTermWindow::blinkTab() { + emit blinkTheTab(this, blinkStatus_); + blinkStatus_ = !blinkStatus_; +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* Mouse & Key */ +/* */ +/* ------------------------------------------------------------------------ */ +void FQTermWindow::enterEvent(QEvent*){} + +void FQTermWindow::leaveEvent(QEvent*) { + // TODO: code below doesn't work + // QPoint temp(0, 0); + // session_->setSelect(temp, temp, session_->isRectangleCopy_); + // QApplication::postEvent(screen_, new QPaintEvent(QRect(0, 0, 0, 0)); + // &paintEvent); +} + +void FQTermWindow::changeEvent(QEvent *e) { + if (e->type() == QEvent::WindowStateChange) { + QWindowStateChangeEvent *event = (QWindowStateChangeEvent*)(e); + Qt::WindowStates oldState = event->oldState(); + if (!isMaximized()) { + emit refreshOthers(this); + } + if ( (oldState & Qt::WindowMinimized && !isMinimized()) || + (!(oldState & Qt::WindowActive) && isActiveWindow())) { + forcedRepaintScreen(); + } + if (oldState & Qt::WindowMaximized || isMaximized()) { + emit resizeSignal(this); + } + } +} + +void FQTermWindow::resizeEvent(QResizeEvent *qResizeEvent) +{ + emit resizeSignal(this); +} + +bool FQTermWindow::event(QEvent *qevent) { + bool res = false; + QKeyEvent *keyEvent; + switch(qevent->type()) { +#ifdef __linux__ + case QEvent::ShortcutOverride: + keyEvent = (QKeyEvent *)(qevent); + if(keyEvent->key() == Qt::Key_W && + keyEvent->modifiers() == Qt::ControlModifier) { + keyEvent->accept(); + res = true; + } + break; +#endif + case QEvent::KeyPress: + keyEvent = (QKeyEvent *)(qevent); + if (keyEvent->key() == Qt::Key_Tab || + keyEvent->key() == Qt::Key_Backtab) { + // Key_Tab and Key_Backtab are special, if we don't process them here, + // the default behavoir is to move focus. see QWidget::event. + keyPressEvent(keyEvent); + keyEvent->accept(); + res = true; + } + break; + default: + break; + } + + res = res || QMainWindow::event(qevent); + + if (qevent->type() == QEvent::HoverMove + || qevent->type() == QEvent::MouseMove + || qevent->type() == QEvent::Move) { + if (res) { + FQ_TRACE("wndEvent", 10) << "Accept event: " << qevent->type() + << " " << getEventName(qevent->type()) << "."; + } else { + FQ_TRACE("wndEvent", 10) << "Ignore event: " << qevent->type() + << " " << getEventName(qevent->type()) << "."; + } + } else { + if (res) { + FQ_TRACE("wndEvent", 9) << "Accept event: " << qevent->type() + << " " << getEventName(qevent->type()) << "."; + } else { + FQ_TRACE("wndEvent", 9) << "Ignore event: " << qevent->type() + << " " << getEventName(qevent->type()) << "."; + } + } + return res; +} + +void FQTermWindow::mouseDoubleClickEvent(QMouseEvent *mouseevent) { + if (scriptMouseEvent(mouseevent)) + return; +} + +void FQTermWindow::mousePressEvent(QMouseEvent *mouseevent) { + if (scriptMouseEvent(mouseevent)) + return; + // stop the tab blinking + stopBlink(); + + // Left Button for selecting + if (mouseevent->button() & Qt::LeftButton && !(mouseevent->modifiers())) { + startSelecting(mouseevent->pos()); + } + + // Right Button + if ((mouseevent->button() & Qt::RightButton)) { + if (mouseevent->modifiers() & Qt::ControlModifier) { + // on Url + if (!session_->getUrl().isEmpty()) { + previewLink(); + } + return ; + } + +#ifdef __APPLE__ + bool additional_modifier = (mouseevent->modifiers() & !Qt::MetaModifier); +#else + bool additional_modifier = mouseevent->modifiers(); +#endif + + if (!(additional_modifier)) { + // on Url + if (!session_->getUrl().isEmpty()) { + urlMenu_->popup(mouseevent->globalPos()); + } else { + menu_->popup(mouseevent->globalPos()); + } + return ; + } + } + // Middle Button for paste + if (mouseevent->button() &Qt::MidButton && !(mouseevent->modifiers())) { + if (isConnected()) + // on Url + if (!session_->getUrl().isEmpty()) { + previewLink(); + } else { + pasteHelper(false); + } + return ; + } + + // If it is a click, there should be a press event and a release event. + isMouseClicked_ = true; + + // xterm mouse event + //session_->sendMouseState(0, me->button(), me->state(), me->pos()); +} + + +void FQTermWindow::mouseMoveEvent(QMouseEvent *mouseevent) { + bool mouseEventConsumed = scriptMouseEvent(mouseevent); + QPoint position = mouseevent->pos(); + if (!mouseEventConsumed) + { + + // selecting by leftbutton + if ((mouseevent->buttons() &Qt::LeftButton) && isSelecting_) { + onSelecting(position); + } + } + if (!(session_->param().isSupportMouse_ && isConnected())) { + return; + } + + setCursorPosition(position); + setCursorType(position); + + + if (!mouseEventConsumed) + { + if (!isUrlUnderLined_ && session_->urlStartPoint() != session_->urlEndPoint()) { + isUrlUnderLined_ = true; + urlStartPoint_ = session_->urlStartPoint(); + urlEndPoint_ = session_->urlEndPoint(); + clientRect_ = QRect(QPoint(0, urlStartPoint_.y()), QSize(session_->getBuffer()->getNumColumns(), urlEndPoint_.y() - urlStartPoint_.y() + 1)); + repaintScreen(); + + } else if (isUrlUnderLined_ && (session_->urlStartPoint() != urlStartPoint_ || session_->urlEndPoint() != urlEndPoint_)) { + clientRect_ = QRect(QPoint(0, urlStartPoint_.y()), QSize(session_->getBuffer()->getNumColumns(), urlEndPoint_.y() - urlStartPoint_.y() + 1)); + urlStartPoint_ = QPoint(); + urlEndPoint_ = QPoint(); + repaintScreen(); + isUrlUnderLined_ = false; + + } + } +} + +static bool isSupportedImage(const QString &name) { + static QList image_formats = + QImageReader::supportedImageFormats(); + + return image_formats.contains(name.section(".", -1).toLower().toUtf8()); +} + +void FQTermWindow::mouseReleaseEvent(QMouseEvent *mouseevent) { + if (scriptMouseEvent(mouseevent)) + return; + if (!isMouseClicked_) { + return ; + } + isMouseClicked_ = false; + // other than Left Button ignored + if (!(mouseevent->button() & Qt::LeftButton) || + (mouseevent->modifiers() & Qt::KeyboardModifierMask)) { + // no local mouse event + //session_->sendMouseState(3, me->button(), me->state(), me->pos()); + return ; + } + + // Left Button for selecting + QPoint currentMouseCell = screen_->mapToChar(mouseevent->pos()); + if (currentMouseCell != lastMouseCell_ && isSelecting_) { + finishSelecting(mouseevent->pos()); + return ; + } + isSelecting_ = false; + + if (!session_->param().isSupportMouse_ || !isConnected()) { + return ; + } + + // url + QString url = session_->getUrl(); + if (!url.isEmpty()) { + if (isSupportedImage(url)) { + previewLink(); + } else { + openUrl(url); + } + return ; + } + + processLClick(currentMouseCell); +} + +void FQTermWindow::wheelEvent(QWheelEvent *wheelevent) { + if (scriptWheelEvent(wheelevent)) return; + int j = wheelevent->delta() > 0 ? 4 : 5; + if (!(wheelevent->modifiers())) { + if (FQTermPref::getInstance()->isWheelSupported_ && isConnected()) { + session_->writeStr(directions_[j]); + } + return ; + } + //session_->sendMouseState(j, Qt::NoButton, we->state(), we->pos()); +} + +//keyboard input event +void FQTermWindow::keyPressEvent(QKeyEvent *keyevent) { + if (keyevent->isAutoRepeat() && !session_->getBuffer()->isAutoRepeatMode()) { + FQ_TRACE("sendkey", 5) + << "The terminal is set to not allow repeated key events."; + keyevent->accept(); + return; + } + if (scriptKeyEvent(keyevent)) + return; + + keyevent->accept(); + + if (!isConnected()) { + if (keyevent->key() == Qt::Key_Return || keyevent->key() == Qt::Key_Enter) { + session_->reconnect(); + } + return ; + } + + // stop the tab blinking + stopBlink(); + if (!session_->readyForInput()) { + return; + } + // message replying + session_->leaveIdle(); + + Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers(); + int key = keyevent->key(); + sendKey(key, modifier, keyevent->text()); +} +/* +void FQTermWindow::focusInEvent (QFocusEvent *event) { + QMainWindow::focusInEvent(event); + screen_->setFocus(Qt::OtherFocusReason); +} +*/ + +//connect slot +void FQTermWindow::connectHost() { + pageViewMessage_->display(tr("Not connected"), screen_->mapToPixel(QPoint(1, 1))); + session_->setProxy(session_->param().proxyType_, + session_->param().isAuthentation_, + session_->param().proxyHostName_, + session_->param().proxyPort_, + session_->param().proxyUserName_, + session_->param().proxyPassword_); + session_->connectHost(session_->param().hostAddress_, session_->param().port_); + config_->setItemValue("global", "lastaddrindex", QString("%1").arg(addressIndex_)); +} + +bool FQTermWindow::isConnected() { + return session_->isConnected(); +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* Telnet State */ +/* */ +/* ------------------------------------------------------------------------ */ + +void FQTermWindow::sessionUpdated() { + refreshScreen(); + //send a mouse move event to make mouse-related change + QMouseEvent* me = new QMouseEvent( + QEvent::MouseMove, mapFromGlobal(QCursor::pos()), + QCursor::pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier); + QApplication::postEvent(this, me); +} + +void FQTermWindow::requestUserPwd(QString *user, QString *pwd, bool *isOK) { + SSHLoginDialog login(user, pwd, this); + *isOK = (login.exec() == QDialog::Accepted); +} + +void FQTermWindow::ZmodemState(int type, int value, const char *status) { + QString strMsg; + //to be completed + switch (type) { + case RcvByteCount: + case SndByteCount: + zmodemDialog_->setProgress(value); + return; + case RcvTimeout: + /* receiver did not respond, aborting */ + strMsg = QString(tr("Time out!")); + break; + case SndTimeout: + /* value is # of consecutive send timeouts */ + strMsg = QString(tr("Time out after trying %1 times")).arg(value); + break; + case RmtCancel: + /* remote end has cancelled */ + strMsg = QString(tr("Canceled by remote peer %1")).arg(status); + break; + case ProtocolErr: + /* protocol error has occurred, val=hdr */ + strMsg = QString( + tr("Unhandled header %1 at state %2")).arg(value).arg(status); + break; + case RemoteMessage: + /* message from remote end */ + strMsg = QString(tr("Msg from remote peer: %1")).arg(status); + break; + case DataErr: + /* data error, val=error count */ + strMsg = QString(tr("Data errors %1")).arg(value); + break; + case FileErr: + /* error writing file, val=errno */ + strMsg = QString(tr("Falied to write file")); + break; + case FileBegin: + /* file transfer begins, str=name */ + FQ_TRACE("window", 1) << "Starting file " << status; + zmodemDialog_->setFileInfo(session_->bbs2unicode(status), value); + zmodemDialog_->setProgress(0); + zmodemDialog_->clearErrorLog(); + zmodemDialog_->show(); + zmodemDialog_->setModal(true); + return; + case FileEnd: + /* file transfer ends, str=name */ + zmodemDialog_->hide(); + return; + case FileSkip: + /* file being skipped, str=name */ + strMsg = QString(tr("Skipping file %1")).arg(status); + break; + } + zmodemDialog_->addErrorLog(strMsg); +} + +// telnet state slot +void FQTermWindow::TelnetState(int state) { + switch (state) { + case TSRESOLVING: + pageViewMessage_->display(tr("Resolving host name"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSHOSTFOUND: + pageViewMessage_->display(tr("Host found"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSHOSTNOTFOUND: + pageViewMessage_->display(tr("Host not found"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSCONNECTING: + pageViewMessage_->display(tr("Connecting..."), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSHOSTCONNECTED: + pageViewMessage_->display(tr("Connected"), screen_->mapToPixel(QPoint(1, 1))); + frame_->updateMenuToolBar(); + break; + case TSPROXYCONNECTED: + pageViewMessage_->display(tr("Connected to proxy"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSPROXYAUTH: + pageViewMessage_->display(tr("Proxy authentation"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSPROXYFAIL: + pageViewMessage_->display(tr("Proxy failed"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSREFUSED: + pageViewMessage_->display(tr("Connection refused"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSREADERROR: + pageViewMessage_->display(tr("Error when reading from server"), screen_->mapToPixel(QPoint(1, 1)), + PageViewMessage::Error); + break; + case TSCLOSED: + pageViewMessage_->display(tr("Connection closed"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSCLOSEFINISH: + pageViewMessage_->display(tr("Connection close finished"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSCONNECTVIAPROXY: + pageViewMessage_->display(tr("Connect to host via proxy"), screen_->mapToPixel(QPoint(1, 1))); + break; + case TSEGETHOSTBYNAME: + pageViewMessage_->display( + tr("Error in gethostbyname"), screen_->mapToPixel(QPoint(1, 1)), PageViewMessage::Error); + break; + case TSEINIWINSOCK: + pageViewMessage_->display( + tr("Error in startup winsock"), screen_->mapToPixel(QPoint(1, 1)), PageViewMessage::Error); + break; + case TSERROR: + pageViewMessage_->display( + tr("Error in connection"), screen_->mapToPixel(QPoint(1, 1)), PageViewMessage::Error); + break; + case TSPROXYERROR: + pageViewMessage_->display(tr("Error in proxy"), screen_->mapToPixel(QPoint(1, 1)), PageViewMessage::Error); + break; + case TSWRITED: + break; + } +} + +void FQTermWindow::showSessionErrorMessage(QString reason) { + if (reason == tr("User Cancel")) { + return; + } + QMessageBox::critical(this, tr("Session error"), reason); +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* UI Slots */ +/* */ +/* ------------------------------------------------------------------------ */ + + +void FQTermWindow::copy() { + QClipboard *clipboard = QApplication::clipboard(); + + QString selected_text = session_->getBuffer()->getTextSelected( + session_->param().isRectSelect_, + session_->param().isColorCopy_, + parseString((const char*)session_->param().escapeString_.toLatin1())); + + QByteArray cstrText = session_->unicode2bbs(selected_text); + + // TODO_UTF16: avoid this replacement. + if (!FQTermPref::getInstance()->escapeString_.isEmpty()) { + cstrText.replace( + parseString((const char*)session_->param().escapeString_.toLatin1()), + parseString(FQTermPref::getInstance()->escapeString_.toLatin1())); + } + selected_text = session_->bbs2unicode(cstrText); + + // TODO_UTF16: there are three modes: Clipboard, Selection, FindBuffer. + clipboard->setText(selected_text, QClipboard::Clipboard); + clipboard->setText(selected_text, QClipboard::Selection); +} + +void FQTermWindow::paste() { + pasteHelper(true); +} + +void FQTermWindow::writePasting(const QString& content) +{ + QByteArray cstrText = session_->unicode2bbs(content); + + // TODO_UTF16: avoid this replacement. + if (!FQTermPref::getInstance()->escapeString_.isEmpty()) { + cstrText.replace( + parseString(FQTermPref::getInstance()->escapeString_.toLatin1()), + parseString((const char*)session_->param().escapeString_.toLatin1())); + } + + if (session_->param().isAutoWrap_) { + // convert to unicode for word wrap + QString strText; + strText = session_->bbs2unicode(cstrText); + // insert '\n' as needed + for (uint i = 0; (long)i < strText.length(); i++) { + uint j = i; + uint k = 0, l = 0; + while ((long)j < strText.length() && strText.at(j) != QChar('\n')) { + if (FQTermPref::getInstance()->widthToWrapWord_ - (l - k) >= 0 + && FQTermPref::getInstance()->widthToWrapWord_ - (l - k) < 2) { + strText.insert(j, QChar('\n')); + k = l; + j++; + break; + } + // double byte or not + if (strText.at(j).row() == '\0') { + l++; + } else { + l += 2; + } + j++; + } + i = j; + } + + cstrText = session_->unicode2bbs(strText); + } + + session_->write(cstrText, cstrText.length()); +} + +void FQTermWindow::pasteHelper(bool clip) { + if (!isConnected()) { + return ; + } + + // TODO_UTF16: there are three modes: Clipboard, Selection, FindBuffer. + QClipboard *clipboard = QApplication::clipboard(); + + // TODO_UTF16: what's the termFrame_->clipboardEncodingID_? + /* + if (termFrame_->clipboardEncodingID_ == 0) { + if (clip) { + cstrText = U2G(clipboard->text(QClipboard::Clipboard)); + } + else { + cstrText = U2G(clipboard->text(QClipboard::Selection)); + } + + if (session_->param().serverEncodingID_ == 1) { + char *str = encodingConverter_.G2B(cstrText, cstrText.length()); + cstrText = str; + delete [] str; + } + } else { + if (clip) { + cstrText = U2B(clipboard->text(QClipboard::Clipboard)); + } else { + cstrText = U2B(clipboard->text(QClipboard::Selection)); + } + + if (session_->param().serverEncodingID_ == 0) { + char *str = encodingConverter_.B2G(cstrText, cstrText.length()); + cstrText = str; + delete [] str; + } + } + */ + + QString clipStr; + + if (clip) { + clipStr = clipboard->text(QClipboard::Clipboard); + } else { + clipStr = clipboard->text(QClipboard::Selection); + } + + writePasting(clipStr); +} + +void FQTermWindow::openAsUrl() { + QString selected_text = session_->getBuffer()->getTextSelected( + session_->param().isRectSelect_, + session_->param().isColorCopy_, + parseString((const char*)session_->param().escapeString_.toLatin1())); + openUrl(selected_text); +} + +void FQTermWindow::searchIt() +{ + script_engine_->runScript(getPath(RESOURCE) + "script/search.js"); + QScriptValueList qvl; + qvl << FQTermPref::getInstance()->searchEngine_; + if (!script_engine_->scriptCallback("searchSelected", qvl)) { + //fall back to google. + QString selected_text = session_->getBuffer()->getTextSelected( + session_->param().isRectSelect_, + session_->param().isColorCopy_, + parseString((const char*)session_->param().escapeString_.toLatin1())); + QString searchUrl = "http://www.google.com/search?client=fqterm&rls=en&q=" + selected_text + "&sourceid=fqterm"; + QByteArray url = QUrl(searchUrl).toEncoded(); + openUrlImpl(url); + } +} + +void FQTermWindow::shareIt() +{ + script_engine_->runScript(getPath(RESOURCE) + "script/weiboshare.js"); +} + +void FQTermWindow::fastPost() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString clipStr = clipboard->text(QClipboard::Clipboard); + QString lineEnd("\n"); + QString postTitle = clipStr.left(clipStr.indexOf(lineEnd)); + + sendParsedString("^p"); + writeRawString(postTitle); + writeRawString(QString("\n\n")); + writePasting(clipStr); + sendParsedString("^W\n"); +} + + +void FQTermWindow::externalEditor() { + externalEditor_->start(); +} + + +void FQTermWindow::externalEditorDone(const QString& str) { + QByteArray rawStr = session_->unicode2bbs_smart(str); + session_->write(rawStr, rawStr.length()); +} + + +void FQTermWindow::copyArticle() { + if (!isConnected()) { + return ; + } + + session_->copyArticle(); +} + +void FQTermWindow::setColor() { + addrDialog set(this, session_->param()); + + set.setCurrentTabIndex(addrDialog::Display); + int res = set.exec(); + if (res != 0) { + updateSetting(set.param()); + if (res == 2) + saveSetting(false); + } + +} + +void FQTermWindow::disconnect() { + session_->close(); + + connectionClosed(); +} + +void FQTermWindow::showIP(bool show) { + pageViewMessage_->hide(); + if (!show) { + return; + } + QString country, city; + QString url = session_->getIP(); + FQTermIPLocation *ipLocation = FQTermIPLocation::getInstance(); + + QRect screenRect = screen_->rect(); + QPoint messagePos; + QRect globalIPRectangle = QRect(screen_->mapToRect(ipRectangle_)); + QFontMetrics fm(qApp->font()); + int charHeight = fm.height(); + + int midLine = (screenRect.top() + screenRect.bottom()) / 2; + int ipMidLine = (globalIPRectangle.top() + globalIPRectangle.bottom()) / 2; + if (ipMidLine < midLine) { + // "There is Plenty of Room at the Bottom." -- Feyman, 1959 + messagePos.setY(globalIPRectangle.bottom() + 0.618 * charHeight); + } else { + messagePos.setY(globalIPRectangle.top() + - 0.618 * charHeight + - pageViewMessage_->size().height()); + } + + QString displayText; + if (ipLocation == NULL) { + displayText = tr("IP database file does NOT exist"); + } else if (!ipLocation->getLocation(url, country, city)) { + displayText = tr("Invalid IP"); + } else { + displayText = country + " " + city; + } + + QRect messageSize(pageViewMessage_->displayCheck(displayText, + PageViewMessage::Info)); + PageViewMessage::Alignment ali; + if (messageSize.width() + globalIPRectangle.left() >= screenRect.right()) { + //"But There is No Room at the Right" -- Curvelet, 2007 + messagePos.setX(globalIPRectangle.right()); + ali = PageViewMessage::TopRight; + } else { + messagePos.setX(globalIPRectangle.left()); + ali = PageViewMessage::TopLeft; + } + + pageViewMessage_->display( + displayText, + PageViewMessage::Info, + 0, messagePos, ali); +} + +void FQTermWindow::runScript() { + // get the previous dir + QStringList fileList; + FQTermFileDialog fileDialog(config_); + + fileList = fileDialog.getOpenNames("Choose a Javascript file", "JavaScript File (*.js)"); + + if (!fileList.isEmpty() && fileList.count() == 1) { + runScript(fileList.at(0)); + } +} + +void FQTermWindow::stopScript() { + script_engine_->stopScript(); +} + +void FQTermWindow::viewMessages() { + msgDialog msg(this); + + QByteArray dlgSize = +// frame_->config()->getItemValue("global", "msgdialog").toLatin1(); + config_->getItemValue("global", "msgdialog").toLatin1(); + const char *dsize = dlgSize.constData(); + if (!dlgSize.isEmpty()) { + int x, y, cx, cy; + sscanf(dsize, "%d %d %d %d", &x, &y, &cx, &cy); + msg.resize(QSize(cx, cy)); + msg.move(QPoint(x, y)); + } else { + msg.resize(QSize(300, 500)); + msg.move(QPoint(20,20)); + } + + msg.setMessageText(allMessages_); + msg.exec(); + + QString strSize = QString("%1 %2 %3 %4").arg(msg.x()).arg(msg.y()).arg + (msg.width()).arg(msg.height()); +// frame_->config()->setItemValue("global", "msgdialog", strSize); + config_->setItemValue("global", "msgdialog", strSize); +} + +void FQTermWindow::setting() { + addrDialog set(this, session_->param()); + int res = set.exec(); + if (res != 0) { + updateSetting(set.param()); + if (res == 2) + saveSetting(false); + } +} + +void FQTermWindow::toggleAntiIdle() { + session_->setAntiIdle(!session_->isAntiIdle()); +} + +void FQTermWindow::toggleAutoReply() { + session_->setAutoReply(!session_->isAutoReply()); +} + +void FQTermWindow::toggleAutoReconnect() { + session_->setAutoReconnect(!session_->param().isAutoReconnect_); +} + +void FQTermWindow::connectionClosed() { + stopBlink(); + + pageViewMessage_->display(tr("Connection closed"), screen_->mapToPixel(QPoint(1, 1))); + + frame_->updateMenuToolBar(); + + setCursor(cursors_[FQTermSession::kNormal]); + + refreshScreen(); + + if (!getSession()->param().isAutoReconnect_ && getSession()->param().isAutoCloseWin_) { + emit(connectionClosed(this)); + } +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* Events */ +/* */ +/* ------------------------------------------------------------------------ */ + +void FQTermWindow::articleCopied(int e, const QString content) { + if (e == DAE_FINISH) { +// articleDialog article(frame_->config(), this); + articleDialog article(config_, this); + + // Fix focus-losing bug. + // dsize should be a pointer to a non-temprary object. + QByteArray dlgSize = +// frame_->config()->getItemValue("global", "articledialog").toLatin1(); + config_->getItemValue("global", "articledialog").toLatin1(); + + const char *dsize = dlgSize.constData(); + + if (!dlgSize.isEmpty()) { + int x, y, cx, cy; + sscanf(dsize, "%d %d %d %d", &x, &y, &cx, &cy); + article.resize(QSize(cx, cy)); + article.move(QPoint(x, y)); + } else { + article.resize(QSize(300, 500)); + article.move(20,20); + } + article.articleText_ = content; + + article.ui_.textBrowser->setPlainText(article.articleText_); + article.exec(); + QString strSize = QString("%1 %2 %3 %4").arg(article.x()).arg(article.y()) + .arg(article.width()).arg(article.height()); +// frame_->config()->setItemValue("global", "articledialog", strSize); + config_->setItemValue("global", "articledialog", strSize); + } else if (e == DAE_TIMEOUT) { + QMessageBox::warning(this, "timeout", "download article timeout, aborted"); +#ifdef HAVE_PYTHON + } else if (e == PYE_ERROR) { + QMessageBox::warning(this, "Python script error", pythonErrorMessage_); + } else if (e == PYE_FINISH) { + QMessageBox::information(this, "Python script finished", + "Python script file executed successfully"); +#endif //HAVE_PYTHON + } +} + +/* ------------------------------------------------------------------------ */ +/* */ +/* Aux Func */ +/* */ +/* ------------------------------------------------------------------------ */ + +QByteArray FQTermWindow::parseString(const QByteArray &cstr, int *len) { + QByteArray parsed = ""; + + if (len != 0) { + *len = 0; + } + + for (uint i = 0; (long)i < cstr.length(); i++) { + if (cstr.at(i) == '^') { + i++; + if ((long)i < cstr.length()) { + parsed += FQTERM_CTRL(cstr.at(i)); + if (len != 0) { + *len = *len + 1; + } + } + } else if (cstr.at(i) == '\\') { + i++; + if ((long)i < cstr.length()) { + if (cstr.at(i) == 'n') { + parsed += CHAR_CR; + } else if (cstr.at(i) == 'r') { + parsed += CHAR_LF; + } else if (cstr.at(i) == 't') { + parsed += CHAR_TAB; + } + if (len != 0) { + *len = *len + 1; + } + } + } else { + parsed += cstr.at(i); + if (len != 0) { + *len = *len + 1; + } + } + } + + return parsed; +} + +void FQTermWindow::messageAutoReplied() { + pageViewMessage_->display("You have messages", PageViewMessage::Info, 0); +} + +void FQTermWindow::saveSetting(bool ask /* = true*/) { + if (addressIndex_ == -1) { + return ; + } + + //save these options silently + FQTermConfig pConf(getPath(USER_CONFIG) + "address.cfg"); + FQTermParam param; + loadAddress(&pConf, addressIndex_, param); + param.isAutoCopy_ = session_->param().isAutoCopy_; + param.isAutoWrap_ = session_->param().isAutoWrap_; + param.isRectSelect_ = session_->param().isRectSelect_; + param.isColorCopy_ = session_->param().isColorCopy_; + saveAddress(&pConf, addressIndex_, param); + pConf.save(getPath(USER_CONFIG) + "address.cfg"); + + if (param == session_->param()) { + return; + } + + QMessageBox mb("FQTerm", "Setting changed do you want to save it?", + QMessageBox::Warning, QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape, 0, this); + if (!ask || mb.exec() == QMessageBox::Yes) { + saveAddress(&pConf, addressIndex_, session_->param()); + pConf.save(getPath(USER_CONFIG) + "address.cfg"); + } +} + +int FQTermWindow::externInput(const QByteArray &cstrText) { + QByteArray cstrParsed = parseString(cstrText); + return session_->write(cstrParsed, cstrParsed.length()); +} + +int FQTermWindow::externInput(const QString &cstrText) { + return externInput(session_->unicode2bbs_smart(cstrText)); +} + +int FQTermWindow::writeRawString(const QString& str) { + QByteArray rawStr = session_->unicode2bbs_smart(str); + return session_->write(rawStr, rawStr.length()); +} + +void FQTermWindow::sendParsedString(const char *str) { + int length; + QByteArray cstr = parseString(str, &length); + session_->write(cstr, length); +} + + +bool FQTermWindow::postQtScriptCallback(const QString& func, const QScriptValueList & args) { + return script_engine_->scriptCallback(func, args); +} + +#ifdef HAVE_PYTHON +bool FQTermWindow::postPythonCallback( const QString& func, PyObject* pArgs ) +{ + return pythonCallback(func, pArgs); +} +#endif //HAVE_PYTHON + +// void FQTermWindow::setMouseMode(bool on) { +// isMouseX11_ = on; +// } + +// /* 0-left 1-middle 2-right 3-relsase 4/5-wheel +// * +// */ +// //void FQTermWindow::sendMouseState( int num, +// // Qt::ButtonState btnstate, Qt::ButtonState keystate, const QPoint& pt ) +// void FQTermWindow::sendMouseState(int num, Qt::KeyboardModifier btnstate, +// Qt::KeyboardModifier keystate, const QPoint &pt) { +// /* +// if(!m_bMouseX11) +// return; +// +// QPoint ptc = screen_->mapToChar(pt); +// +// if(btnstate&Qt::LeftButton) +// num = num==0?0:num; +// else if(btnstate&Qt::MidButton) +// num = num==0?1:num; +// else if(btnstate&Qt::RightButton) +// num = num==0?2:num; +// +// int state = 0; +// if(keystate&Qt::ShiftModifier) +// state |= 0x04; +// if(keystate&Qt::MetaModifier) +// state |= 0x08; +// if(keystate&Qt::ControlModifier) +// state |= 0x10; +// +// // normal buttons are passed as 0x20 + button, +// // mouse wheel (buttons 4,5) as 0x5c + button +// if(num>3) num += 0x3c; +// +// char mouse[10]; +// sprintf(mouse, "\033[M%c%c%c", +// num+state+0x20, +// ptc.x()+1+0x20, +// ptc.y()+1+0x20); +// m_pTelnet->write( mouse, strlen(mouse) ); +// */ +// } + +/* ------------------------------------------------------------------------ */ +/* */ +/* Python Func */ +/* */ +/* ------------------------------------------------------------------------ */ +#ifdef HAVE_PYTHON + + +void FQTermWindow::runPythonScript() { + QStringList fileList; + FQTermFileDialog fileDialog(config_); + + fileList = fileDialog.getOpenNames("Choose a Python file", "Python File (*.py)"); + + if (!fileList.isEmpty() && fileList.count() == 1) { + runPythonScriptFile(fileList.at(0)); + } +} + +void FQTermWindow::runPythonScriptFile(const QString& file) { + QString str(QString("%1").arg(long(this))); + char* lp = fq_strdup(str.toUtf8().data()); + char *argv[2]={lp,NULL}; + // get the global python thread lock + PyEval_AcquireLock(); + + PyInterpreterState * mainInterpreterState = frame_->getPythonHelper()->getPyThreadState()->interp; + + // create a thread state object for this thread + PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState); + PyThreadState_Swap(myThreadState); + + + PySys_SetArgv(1, argv); + + runPythonFile(file); + + //Clean up this thread's python interpreter reference + PyThreadState_Swap(NULL); + PyThreadState_Clear(myThreadState); + PyThreadState_Delete(myThreadState); + PyEval_ReleaseLock(); + free((void*)lp); +} + +bool FQTermWindow::pythonCallback(const QString & func, PyObject* pArgs) { + if(!pythonScriptLoaded_) { + Py_DECREF(pArgs); + return false; + }; + + bool done = false; + // get the global lock + PyEval_AcquireLock(); + // get a reference to the PyInterpreterState + + //Python thread references + + PyInterpreterState * mainInterpreterState = frame_->getPythonHelper()->getPyThreadState()->interp; + // create a thread state object for this thread + PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState); + PyThreadState_Swap(myThreadState); + + PyObject *pF = PyString_FromString(func.toUtf8()); + PyObject *pFunc = PyDict_GetItem(pDict, pF); + Py_DECREF(pF); + + if (pFunc && PyCallable_Check(pFunc)) + { + PyObject *pValue = PyObject_CallObject(pFunc, pArgs); + Py_DECREF(pArgs); + if (pValue != NULL) + { + if (PyBool_Check(pValue) && pValue == Py_True) + done = true; + Py_DECREF(pValue); + } + else + { + //QMessageBox::warning(this,"Python script error", getException()); + printf("%p: Python script error\n", this, getException().toUtf8().data()); + } + } + else + { + PyErr_Print(); + printf("Cannot find python %s callback function\n", func.toUtf8().data()); + } + + // swap my thread state out of the interpreter + PyThreadState_Swap(NULL); + // clear out any cruft from thread state object + PyThreadState_Clear(myThreadState); + // delete my thread state object + PyThreadState_Delete(myThreadState); + // release the lock + PyEval_ReleaseLock(); + + if (func == "autoReply") + startBlink(); + + return done; +} + + +int FQTermWindow::runPythonFile( const QString& file ) +{ + QString buffer("def work_thread():\n" + "\ttry:\n\t\texecfile('"); + buffer += QString(file).replace("\\", "\\\\"); + + /* Have to do it like this. PyRun_SimpleFile requires you to pass a + * stdio file pointer, but Vim and the Python DLL are compiled with + * different options under Windows, meaning that stdio pointers aren't + * compatible between the two. Yuk. + * + * Put the string "execfile('file')" into buffer. But, we need to + * escape any backslashes or single quotes in the file name, so that + * Python won't mangle the file name. + * ---- kafa + */ + + /* Put in the terminating "')" and a null */ + buffer += "',{})\n\0"; + + buffer += QString("\texcept:\n" + "\t\texc, val, tb = sys.exc_info()\n" + "\t\tlines = traceback.format_exception(exc, val, tb)\n" + "\t\terr = string.join(lines)\n" + "\t\tprint err\n" + "\t\tf=open('%1','w')\n" + "\t\tf.write(err)\n" + "\t\tf.close()\n").arg(getErrOutputFile(this)); + + buffer += QString("\t\tfqterm.formatError(%1)\n").arg((long)this); + buffer += "\t\texit\n"; + + /* Execute the file */ + PyRun_SimpleString("import thread,string,sys,traceback,fqterm"); + PyRun_SimpleString(buffer.toUtf8()); + PyRun_SimpleString( "thread.start_new_thread(work_thread,())\n"); + + return 0; +} + +void FQTermWindow::initPython(const QString& file) { + + // get the global python thread lock + PyEval_AcquireLock(); + + // get a reference to the PyInterpreterState + PyInterpreterState * mainInterpreterState = frame_->getPythonHelper()->getPyThreadState()->interp; + + + + // create a thread state object for this thread + PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState); + PyThreadState_Swap(myThreadState); + + Py_InitModule4("fqterm", fqterm_methods, + NULL,(PyObject*)NULL,PYTHON_API_VERSION); + + PyImport_AddModule("fqterm"); + + if(!file.isEmpty() ) + { + QFileInfo info(file); + PyRun_SimpleString("import sys"); + PyRun_SimpleString(QString("sys.path.append(\"%1/\")").arg(info.absolutePath()).toUtf8().data()); + PyObject *pName = PyString_FromString(info.baseName().toUtf8().data()); + pModule = PyImport_Import(pName); + //PyErr_Print(); + Py_DECREF(pName); + if (pModule != NULL) + pDict = PyModule_GetDict(pModule); + else + { + //printf("Failed to PyImport_Import\n"); + } + + if(pDict != NULL ) + pythonScriptLoaded_ = true; + else + { + //printf("Failed to PyModule_GetDict\n"); + } + } + + //Clean up this thread's python interpreter reference + PyThreadState_Swap(NULL); + PyThreadState_Clear(myThreadState); + PyThreadState_Delete(myThreadState); + PyEval_ReleaseLock(); + +} + +void FQTermWindow::finalizePython() +{ + // get the global python thread lock + PyEval_AcquireLock(); + + // get a reference to the PyInterpreterState + PyInterpreterState * mainInterpreterState = frame_->getPythonHelper()->getPyThreadState()->interp; + + // create a thread state object for this thread + PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState); + PyThreadState_Swap(myThreadState); + + //Displose of current python module so we can reload in constructor. + if(pModule!=NULL) + Py_DECREF(pModule); + + //Clean up this thread's python interpreter reference + PyThreadState_Swap(NULL); + PyThreadState_Clear(myThreadState); + PyThreadState_Delete(myThreadState); + PyEval_ReleaseLock(); +} + +#endif //HAVE_PYTHON + +/* ------------------------------------------------------------------------ */ +/* */ +/* HTTP Func */ +/* */ +/* ------------------------------------------------------------------------ */ + +void FQTermWindow::openLink() { + QString url = session_->getUrl(); + if (!url.isEmpty()) { + openUrlImpl(url); + } +} + +void FQTermWindow::saveLink() { + QString url = session_->getUrl(); + if (!url.isEmpty()) + getHttpHelper(url, false); +} + +void FQTermWindow::openUrl(QString url) +{ + QString caption = tr("URL Dialog"); + QString strUrl = url; + QTextEdit *textEdit = new QTextEdit(); + textEdit->setPlainText(strUrl); + //textEdit->setFocus(); + textEdit->setTabChangesFocus(true); + textEdit->moveCursor(QTextCursor::End); + + + QPushButton *okButton = new QPushButton(tr("&Open URL")); + QPushButton *cancelButton = new QPushButton(tr("&Cancel")); +// okButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); +// cancelButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + + + QGridLayout *layout = new QGridLayout; + layout->addWidget(textEdit, 0, 0, 1, -1); + layout->addWidget(okButton, 1, 3); + layout->addWidget(cancelButton, 1, 4); + + QDialog dlg(this); + + QFontMetrics fm(qApp->font()); + + + connect(okButton, SIGNAL(pressed()), &dlg, SLOT(accept())); + connect(cancelButton, SIGNAL(pressed()), &dlg, SLOT(reject())); + + + dlg.setWindowTitle(caption); + dlg.setLayout(layout); + dlg.resize(fm.width(QString(30, 'W')), fm.height() * (fm.width(strUrl) / fm.width(QString(30, 'W')) + 5)); + textEdit->clearFocus(); + okButton->setFocus(Qt::TabFocusReason); + if (dlg.exec()) { + openUrlImpl(textEdit->toPlainText()); + } +} + + +void FQTermWindow::openUrlImpl(QString url) +{ + const QString &httpBrowser = FQTermPref::getInstance()->httpBrowser_; + if (httpBrowser.isNull() || httpBrowser.isEmpty()) { +#if QT_VERSION >= 0x040400 + QDesktopServices::openUrl(QUrl::fromEncoded(url.toLocal8Bit())); +#else + QDesktopServices::openUrl(url); +#endif + } else { + runProgram(httpBrowser, url); + } +} + + +void FQTermWindow::previewLink() { + getHttpHelper(session_->getUrl(), true); +} + +void FQTermWindow::copyLink() { + QString strUrl; + strUrl = session_->bbs2unicode(session_->getUrl().toLatin1()); + + QClipboard *clipboard = QApplication::clipboard(); + + clipboard->setText(strUrl, QClipboard::Selection); + clipboard->setText(strUrl, QClipboard::Clipboard); +} + +void FQTermWindow::getHttpHelper(const QString &url, bool preview) { + + const QString &strPool = FQTermPref::getInstance()->poolDir_; + + FQTermHttp *http = new FQTermHttp(config_, this, strPool, session_->param().serverEncodingID_); + if (getSession()->param().proxyType_ != 0) { + QString host = getSession()->param().proxyHostName_; + int port = getSession()->param().proxyPort_; + bool auth = getSession()->param().isAuthentation_; + QString user = auth ? getSession()->param().proxyUserName_ : QString(); + QString pass = auth ? getSession()->param().proxyPassword_ : QString(); + switch (getSession()->param().proxyType_) + { + case 1: + case 2: + //no support in qt. + FQ_TRACE("network", 0) << "proxy type not supported by qt, download will not use proxy."; + break; + case 3: + http->setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, host, port, user, pass)); + break; + case 4: + http->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, host, port, user, pass)); + break; + } + } + FQTerm::StatusBar::instance()->newProgressOperation(http).setDescription(tr("Waiting header...")).setAbortSlot(http, SLOT(cancel())).setMaximum(100); + FQTerm::StatusBar::instance()->resetMainText(); + FQTerm::StatusBar::instance()->setProgress(http, 0); + + FQ_VERIFY(connect(http, SIGNAL(headerReceived(FQTermHttp *, const QString &)), + this, SLOT(startHttpDownload(FQTermHttp*,const QString&)))); + + FQ_VERIFY(connect(http,SIGNAL(done(QObject*)),this,SLOT(httpDone(QObject*)))); + + FQ_VERIFY(connect(http, SIGNAL(message(const QString &)), + pageViewMessage_, SLOT(showText(const QString &)))); + + FQ_VERIFY(connect(http, SIGNAL(done(QObject*)), + FQTerm::StatusBar::instance(), + SLOT(endProgressOperation(QObject*)))); + + FQ_VERIFY(connect(http, SIGNAL(percent(int)), + FQTerm::StatusBar::instance(), SLOT(setProgress(int)))); + + FQ_VERIFY(connect(http, SIGNAL(previewImage(const QString &, bool, bool)), + this, SLOT(httpPreviewImage(const QString &, bool, bool)))); + + + http->getLink(url, preview); +} + +void FQTermWindow::startHttpDownload( + FQTermHttp *pHttp, const QString &filedesp) { + FQTerm::StatusBar::instance()->newProgressOperation(pHttp).setDescription + (filedesp).setAbortSlot(pHttp, SLOT(cancel())).setMaximum(100); + + FQTerm::StatusBar::instance()->resetMainText(); +} + +void FQTermWindow::httpDone(QObject *pHttp) { + pHttp->deleteLater(); +} + +void FQTermWindow::httpPreviewImage(const QString &filename, bool raiseViewer, bool done) +{ + if (config_->getItemValue("preference", "image").isEmpty() || done) { + previewImage(filename, raiseViewer); + } +} + +void FQTermWindow::previewImage(const QString &filename, bool raiseViewer) { +// QString strViewer = frame_->config()->getItemValue("preference", "image"); + QString strViewer = config_->getItemValue("preference", "image"); + + if (strViewer.isEmpty()) { + frame_->viewImages(filename, raiseViewer); + } else if(raiseViewer) { + runProgram(strViewer, filename); + } + +} + +void FQTermWindow::beep() { + if (session_->param().isBeep_) { + if (session_->param().isBuzz_) { + frame_->buzz(this); + } + if (FQTermPref::getInstance()->beepSoundFileName_.isEmpty() || + FQTermPref::getInstance()->openBeep_ == 3) { + qApp->beep(); + } + else { + sound_ = NULL; + + switch (FQTermPref::getInstance()->beepMethodID_) { + case 0: + sound_ = + new FQTermSystemSound(FQTermPref::getInstance()->beepSoundFileName_); + break; + case 1: + sound_ = + new FQTermExternalSound(FQTermPref::getInstance()->beepPlayerName_, + FQTermPref::getInstance()->beepSoundFileName_); + break; + } + + if (sound_) { + sound_->start(); + } + } + } + + QString strMsg = session_->getMessage(); + if (!strMsg.isEmpty()) { + allMessages_ += strMsg + "\n\n"; + } + + session_->setSendingMessage(); +} + + +void FQTermWindow::onTitleSet(const QString& title) { + setWindowTitle(title); +} + + +void FQTermWindow::startBlink() { + if (FQTermPref::getInstance()->openTabBlinking_) { + if (!tabBlinkTimer_->isActive()) { + tabBlinkTimer_->start(500); + } + } +} + +void FQTermWindow::stopBlink() { + if (tabBlinkTimer_->isActive()) { + tabBlinkTimer_->stop(); + emit blinkTheTab(this, TRUE); + } +} + +void FQTermWindow::setCursorType(const QPoint& mousePosition) { + QRect rcOld; + bool isUrl = false; + if (FQTermPref::getInstance()->openUrlCheck_) { + showIP(session_->isIP(ipRectangle_, rcOld)); + if (session_->isUrl(urlRectangle_, rcOld)) { + setCursor(Qt::PointingHandCursor); + isUrl = true; + } + } + if (!isUrl) { + FQTermSession::CursorType cursorType = + session_->getCursorType(screen_->mapToChar(mousePosition)); + setCursor(cursors_[cursorType]); + } +} + +void FQTermWindow::setCursorPosition(const QPoint& mousePosition) { + // set cursor pos, repaint if state changed + QRect rc; + if (session_->setCursorPos(screen_->mapToChar(mousePosition), rc)) { + screen_->repaint(screen_->mapToRect(rc)); + + //re-check whether the cursor is still on the selected rectangle -- dp + QPoint localPos = mapFromGlobal(QCursor::pos()); //local. + if (!session_->getMenuRect().contains(screen_->mapToChar(localPos))) + { + QRect dummyRect; + rc = session_->getMenuRect(); + session_->setCursorPos(screen_->mapToChar(localPos), dummyRect); + screen_->repaint(screen_->mapToRect(rc)); + //restore the state. + session_->setCursorPos(screen_->mapToChar(mousePosition), dummyRect); + } + } +} + +void FQTermWindow::refreshScreen() { + screen_->setPaintState(FQTermScreen::NewData); + screen_->update(); +} + +void FQTermWindow::repaintScreen() { + + screen_->setPaintState(FQTermScreen::Repaint); + if (clientRect_ != QRect()) { + screen_->repaint(screen_->mapToRect(clientRect_)); + } else { + screen_->repaint(); + } + clientRect_ = QRect(); +// screen_->update(clientRect_); +} + +void FQTermWindow::enterMenuItem() { + char cr = CHAR_CR; + QRect rc = session_->getMenuRect(); + FQTermSession::PageState ps = session_->getPageState(); + switch (ps) { + case FQTermSession::Menu: + case FQTermSession::MailMenu: + case FQTermSession::TOP10: + if (!rc.isEmpty()) { + char cMenu = session_->getMenuChar(); + session_->write(&cMenu, 1); + session_->write(&cr, 1); + } + break; + case FQTermSession::ArticleList: + case FQTermSession::BoardList: + case FQTermSession::FriendMailList: + case FQTermSession::EliteArticleList: + if (!rc.isEmpty()) { + int n = rc.y() - session_->getBuffer()->getCaretLine(); + // scroll lines + int cursorType = n>0?FQTermSession::kDown:FQTermSession::kUp; + n = qAbs(n); + while (n) { + session_->write(directions_[cursorType], 4); + n--; + } + } + session_->write(&cr, 1); + break; + default: + // TODO: process other PageState. + break; + } +} + +void FQTermWindow::processLClick(const QPoint& cellClicked) { + int cursorType = session_->getCursorType(cellClicked); + switch(cursorType) + { + case FQTermSession::kHome: + case FQTermSession::kEnd: + case FQTermSession::kPageUp: + case FQTermSession::kPageDown: + session_->writeStr(directions_[cursorType]); + break; + case FQTermSession::kUp: + case FQTermSession::kDown: + case FQTermSession::kLeft: + session_->writeStr(directions_[cursorType]); + break; + case FQTermSession::kRight: //Hand + enterMenuItem(); + break; + case FQTermSession::kNormal: + char cr = CHAR_CR; + session_->write(&cr, 1); + break; + } +} + +void FQTermWindow::startSelecting(const QPoint& mousePosition) { + // clear the selected before + session_->clearSelect(); + sessionUpdated(); + + // set the selecting flag + isSelecting_ = true; + lastMouseCell_ = screen_->mapToChar(mousePosition); +} + +void FQTermWindow::onSelecting(const QPoint& mousePosition) { + if (mousePosition.y() < childrenRect().top()) { + screen_->scrollLine(-1); + } + if (mousePosition.y() > childrenRect().bottom()) { + screen_->scrollLine(1); + } + + QPoint curMouseCell = screen_->mapToChar(mousePosition); + session_->setSelect(lastMouseCell_, curMouseCell); + sessionUpdated(); +} + +void FQTermWindow::finishSelecting(const QPoint& mousePosition) { + QPoint currentMouseCell = screen_->mapToChar(mousePosition); + session_->setSelect(currentMouseCell, lastMouseCell_); + refreshScreen(); + if (session_->param().isAutoCopy_) { + copy(); + } + isSelecting_ = false; +} + +void FQTermWindow::sendKey(const int keyCode, const Qt::KeyboardModifiers modifier, + const QString &t) { + if (keyCode == Qt::Key_Shift || keyCode == Qt::Key_Control + || keyCode == Qt::Key_Meta || keyCode == Qt::Key_Alt) { + return; + } + + int key = keyCode; + QString text = t; + +#ifdef __APPLE__ + // On Mac, pressing Command Key (Apple Key) will set the ControlModifier flag. + bool alt_on = ((modifier & Qt::ControlModifier) || (modifier & Qt::AltModifier)); + bool ctrl_on = (modifier & Qt::MetaModifier); +#else + bool alt_on = ((modifier & Qt::MetaModifier) || (modifier & Qt::AltModifier)); + bool ctrl_on = (modifier & Qt::ControlModifier); +#endif + bool shift_on = (modifier & Qt::ShiftModifier); + +#ifdef __APPLE__ + // Bullshit! Qt4.4.0 on Mac generates weird key evnets. + // fix them here. + + if (ctrl_on) { + static const char char_map[][2] = { + {'@', '\x00'}, {'A', '\x01'}, {'B', '\x02'}, {'C', '\x03'}, {'D', '\x04'}, + {'E', '\x05'}, {'F', '\x06'}, {'G', '\x07'}, {'H', '\x08'}, {'J', '\x0a'}, + {'K', '\x0b'}, {'L', '\x0c'}, {'N', '\x0e'}, {'O', '\x0f'}, {'P', '\x10'}, + {'Q', '\x11'}, {'R', '\x12'}, {'S', '\x13'}, {'T', '\x14'}, {'U', '\x15'}, + {'V', '\x16'}, {'W', '\x17'}, {'X', '\x18'}, {'Y', '\x19'}, {'Z', '\x1a'}, + {'\\', '\x1c'}, {']', '\x1d'}, {'^', '\x1e'}, {'_', '\x1f'} + }; + + const int num = sizeof(char_map)/2; + + int expected_key = key; + + for (int i = 0; i < num; ++i) { + const char *c = char_map[i]; + if (c[0] == key) { + expected_key = c[1]; + break; + } + } + + if (expected_key != key) { + FQ_TRACE("sendkey", 5) << "translate the key code from " + << (int)key << "(" << (char)key << ")" + << " to " + << (int)expected_key + << "(" << (char)expected_key << ")" + << ", and change the text appropriately." ; + key = expected_key; + text.clear(); + text.append((char) expected_key); + } + } + + if (!ctrl_on && alt_on && !shift_on) { + if (text.size() == 0 && 0 <= key && key <= 128) { + FQ_TRACE("sendkey", 5) + << "add appropriate text according to the key code."; + text.append((char)key); + } + } + + if (!ctrl_on && alt_on && shift_on) { + // fix the key code when both shift key and meta/alt key are pressed. + static const char char_map[][2] = { + {'`', '~'}, {'1', '!'}, {'2', '@'}, {'3', '#'}, {'4', '$'}, + {'5', '%'}, {'6', '^'}, {'7', '&'}, {'8', '*'}, {'9', '('}, + {'0', ')'}, {'-', '_'}, {'=', '+'}, {'[', '{'}, {']', '}'}, + {'\\', '|'}, {';', ':'}, {'\'', '"'}, {',', '<'},{'.', '>'}, + {'/', '?'} + }; + const int num = sizeof(char_map)/2; + + int expected_key = key; + + for (int i = 0; i < num; ++i) { + const char *c = char_map[i]; + if (c[0] == key) { + expected_key = c[1]; + break; + } + } + + if (expected_key != key) { + FQ_TRACE("sendkey", 5) << "translate the key code from " + << (int)key << "(" << (char)key << ")" + << " to " + << (int)expected_key + << "(" << (char)expected_key << ")"; + key = expected_key; + } + + if (text.size() == 0) { + text.append(key); + } else { + text[0] = key; + } + FQ_TRACE("sendkey", 5) + << "set the text for this key event as the keycode."; + } +#endif + + FQ_TRACE("sendkey", 5) << "(alt " << (alt_on? " on": "off") + << ", ctrl " << (ctrl_on? " on": "off") + << ", shift " << (shift_on? " on": "off") << ")" + << " key: " << key + << " text: " << (text.size() == 0 ? "NULL" : text) + << " (in hex: " + << dumpHexString << text.toStdString() + << dumpNormalString << ")"; + + if (session_->getBuffer()->isAnsiMode()) { + if (session_->getBuffer()->isCursorMode()) { + switch(key) { + case Qt::Key_Up: + session_->writeStr("\x1bOA"); + return; + case Qt::Key_Down: + session_->writeStr("\x1bOB"); + return; + case Qt::Key_Left: + session_->writeStr("\x1bOD"); + return; + case Qt::Key_Right: + session_->writeStr("\x1bOC"); + return; + } + } else { + switch(key) { + case Qt::Key_Up: + session_->writeStr("\x1b[A"); + return; + case Qt::Key_Down: + session_->writeStr("\x1b[B"); + return; + case Qt::Key_Left: + session_->writeStr("\x1b[D"); + return; + case Qt::Key_Right: + session_->writeStr("\x1b[C"); + return; + } + } + } else { + // VT52 mode + switch(key) { + case Qt::Key_Up: + // Do NOT change the parameter to "\x1bA". + session_->writeStr("\x1b" "A"); + return; + case Qt::Key_Down: + // Do NOT change the parameter to "\x1bB". + session_->writeStr("\x1b" "B"); + return; + case Qt::Key_Left: + // Do NOT change the parameter to "\x1bD". + session_->writeStr("\x1b" "D"); + return; + case Qt::Key_Right: + // Do NOT change the parameter to "\x1bC". + session_->writeStr("\x1b" "C"); + return; + } + } + + if (!session_->getBuffer()->isNumericMode() && + (modifier & Qt::KeypadModifier)) { + switch(key) { + case Qt::Key_0: + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + case Qt::Key_7: + case Qt::Key_8: + case Qt::Key_9: + { + char tmp[] = "\x1bOp"; + tmp[2] = 'p' + key - Qt::Key_0; + session_->writeStr(tmp); + } + return; + case Qt::Key_Plus: + session_->writeStr("\x1bOl"); + return; + case Qt::Key_Minus: + session_->writeStr("\x1bOm"); + return; + case Qt::Key_Period: + session_->writeStr("\x1bOn"); + return; + case Qt::Key_Asterisk: + session_->writeStr("\x1bOM"); + return; + } + } + + switch (key) { + case Qt::Key_Home: + session_->writeStr(directions_[0]); + return; + case Qt::Key_End: + session_->writeStr(directions_[1]); + return; + case Qt::Key_PageUp: + session_->writeStr(directions_[2]); + return; + case Qt::Key_PageDown: + session_->writeStr(directions_[3]); + return; + case Qt::Key_Up: + session_->writeStr(directions_[4]); + return; + case Qt::Key_Down: + session_->writeStr(directions_[5]); + return; + case Qt::Key_Left: + session_->writeStr(directions_[6]); + return; + case Qt::Key_Right: + session_->writeStr(directions_[7]); + return; + case Qt::Key_F1: + session_->writeStr("\x1b[11~"); + return; + case Qt::Key_F2: + session_->writeStr("\x1b[12~"); + return; + case Qt::Key_F3: + session_->writeStr("\x1b[13~"); + return; + case Qt::Key_F4: + session_->writeStr("\x1b[14~"); + return; + case Qt::Key_F5: + session_->writeStr("\x1b[15~"); + return; + case Qt::Key_F6: + session_->writeStr("\x1b[17~"); + return; + case Qt::Key_F7: + session_->writeStr("\x1b[18~"); + return; + case Qt::Key_F8: + session_->writeStr("\x1b[19~"); + return; + case Qt::Key_F9: + session_->writeStr("\x1b[20~"); + return; + case Qt::Key_F10: + session_->writeStr("\x1b[21~"); + return; + case Qt::Key_F11: + session_->writeStr("\x1b[23~"); + return; + case Qt::Key_F12: + session_->writeStr("\x1b[24~"); + return; + } + + if (text.length() > 0) { + if (alt_on) { + // Use ESC to emulate Alt-XX key. + session_->writeStr("\x1b"); + } + + if (ctrl_on) { + switch(key) { + case Qt::Key_At: // Ctrl-@ + case Qt::Key_Space: // Ctrl-SPACE + // send NULL + session_->write("\x0", 1); + return; + case Qt::Key_AsciiCircum: // Ctrl-^ + case Qt::Key_AsciiTilde: // Ctrl-~ + case Qt::Key_QuoteLeft: // Ctrl-` + // send RS + session_->write("\x1e", 1); + return; + case Qt::Key_Underscore: // Ctrl-_ + case Qt::Key_Question: // Ctrl-? + // send US + session_->write("\x1f", 1); + return; + } + } + + if (key == Qt::Key_Backspace) { + if (shift_on) { + session_->writeStr("\x1b[3~"); + } else { + if (session_->param().backspaceType_ == 0) + session_->writeStr("\x08"); + else + session_->writeStr("\x7f"); + } + return; + } + + if (key == Qt::Key_Delete) { + if (shift_on) { + if (session_->param().backspaceType_ == 0) + session_->writeStr("\x08"); + else + session_->writeStr("\x7f"); + } else { + session_->writeStr("\x1b[3~"); + } + return; + } + + if (key == Qt::Key_Return) { + if (session_->getBuffer()->isNewLineMode()) { + session_->write("\r\n", 2); + } else { + session_->write("\r", 1); + } + return; + } + + QByteArray cstrTmp = session_->unicode2bbs_smart(text); + session_->write(cstrTmp, cstrTmp.length()); + } + return; +} + +void FQTermWindow::forcedRepaintScreen() { + QResizeEvent *re = new QResizeEvent(screen_->size(), screen_->size()); + QApplication::postEvent(screen_, re); +} + +void FQTermWindow::updateSetting(const FQTermParam& param) { + session_->updateSetting(param); + screen_->setTermFont(true, + QFont(param.englishFontName_, + param.englishFontSize_)); + screen_->setTermFont(false, + QFont(param.otherFontName_, + param.otherFontSize_)); + screen_->setSchema(); + + setWindowTitle(param.name_); + + forcedRepaintScreen(); +} + +void FQTermWindow::setFont() +{ + bool isEnglish = + ((QAction*)(sender()))->data().toBool(); + setFont(isEnglish); +} + +void FQTermWindow::setFont(bool isEnglish) { + bool ok; + QString& fontName = isEnglish?session_->param().englishFontName_:session_->param().otherFontName_; + int& fontSize = isEnglish?session_->param().englishFontSize_:session_->param().otherFontSize_; + QFont font(fontName, fontSize); + font = QFontDialog::getFont(&ok, font, this, tr("Font Selector") +#ifdef __APPLE__ +, QFontDialog::DontUseNativeDialog +#endif + ); + if (ok == true) { + if (FQTermPref::getInstance()->openAntiAlias_) { + font.setStyleStrategy(QFont::PreferAntialias); + } + screen_->setTermFont(isEnglish, font); + fontName = font.family(); + fontSize = font.pointSize(); + forcedRepaintScreen(); + } +} + + +void FQTermWindow::runScript(const QString &filename) { + script_engine_->runScript(filename); +} + +//----------- +static int translateQtModifiers(Qt::KeyboardModifiers modifiers) { + int state = 0; + if (modifiers &Qt::AltModifier) { + state |= SBS_ALT; + } + if (modifiers &Qt::ControlModifier) { + state |= SBS_CTRL; + } + if (modifiers &Qt::ShiftModifier) { + state |= SBS_SHIFT; + } + return state; +} + +static int translateQtButton(Qt::MouseButtons btnstate) { + int state = 0; + if(btnstate&Qt::LeftButton) + state |= SBS_LEFT_BUTTON; + if(btnstate&Qt::RightButton) + state |= SBS_RIGHT_BUTTON; + if(btnstate&Qt::MidButton) + state |= SBS_MID_BUTTON; + return state; +} + +bool FQTermWindow::scriptKeyEvent( QKeyEvent *keyevent ){ + bool res = false; + int state = 0; + state |= translateQtModifiers(keyevent->modifiers()); + + res = postScriptCallback(SFN_KEY_EVENT +#ifdef HAVE_PYTHON + ,Py_BuildValue("liii", this, SKET_KEY_PRESS, state, keyevent->key()) +#endif //HAVE_PYTHON + ,QScriptValueList() << SKET_KEY_PRESS << state << keyevent->key()); + return res; +} + +bool FQTermWindow::scriptMouseEvent(QMouseEvent *mouseevent){ + int type = SMET_UNKOWN; + switch (mouseevent->type()) + { + case QEvent::MouseButtonPress: + type = SMET_MOUSE_PRESS; + break; + case QEvent::MouseButtonRelease: + type = SMET_MOUSE_RELEASE; + break; + case QEvent::MouseButtonDblClick: + type = SMET_MOUSE_DBCLICK; + break; + case QEvent::MouseMove: + type = SMET_MOUSE_MOVE; + break; + } + + int delta = 0; + int state=0; + + state |= translateQtButton(mouseevent->button()); + state |= translateQtModifiers(mouseevent->modifiers()); + + QPoint ptc = screen_->mapToChar(mouseevent->pos()); + ptc.setY(ptc.y() - screen_->getBufferStart()); + int res = postScriptCallback(SFN_MOUSE_EVENT +#ifdef HAVE_PYTHON + ,Py_BuildValue("liiiii", this, type, state, ptc.x(), ptc.y(),delta) +#endif //HAVE_PYTHON + ,QScriptValueList() << type << state << ptc.x() << ptc.y() << delta); + return res; +} + +bool FQTermWindow::scriptWheelEvent( QWheelEvent *wheelevent ) { + int type = SMET_WHEEL; + int delta = 0; + int state=0; + state |= translateQtModifiers(wheelevent->modifiers()); + QPoint ptc = screen_->mapToChar(wheelevent->pos()); + ptc.setY(ptc.y() - screen_->getBufferStart()); + int res = postScriptCallback(SFN_MOUSE_EVENT +#ifdef HAVE_PYTHON + ,Py_BuildValue("liiiii", this, type, state, ptc.x(), ptc.y(),wheelevent->delta()) +#endif //HAVE_PYTHON + ,QScriptValueList() << type << state << ptc.x() << ptc.y() << wheelevent->delta()); + return res; +} + +const QString FQTermExternalEditor::textEditName_ = "external editor input"; + +FQTermExternalEditor::FQTermExternalEditor(QWidget* parent) +: QObject(parent), + editorProcess_(NULL), + started_(false) { + editorProcess_ = new QProcess(this); + FQ_VERIFY(connect(editorProcess_, SIGNAL(stateChanged(QProcess::ProcessState)), + this, SLOT(stateChanged(QProcess::ProcessState)))); + clearTempFileContent(); +} + +FQTermExternalEditor::~FQTermExternalEditor() { + editorProcess_->kill(); + QFile::remove(getTempFilename()); + delete editorProcess_; +} + +void FQTermExternalEditor::execDialog() { + QDialog *dialog = new QDialog((QWidget *)parent()); + QGridLayout *layout = new QGridLayout(dialog); + QTextEdit *text = new QTextEdit(dialog); + text->setObjectName(textEditName_); + layout->addWidget(text); + QBoxLayout *rowLayout = new QBoxLayout(QBoxLayout::LeftToRight, dialog); + layout->addLayout(rowLayout, 1, 0, Qt::AlignHCenter); + QPushButton *ok = new QPushButton(tr("OK"), dialog); + QPushButton *cancel = new QPushButton(tr("Cancel"), dialog); + rowLayout->addWidget(ok); + rowLayout->addWidget(cancel); + FQ_VERIFY(connect(ok, SIGNAL(clicked()), + dialog, SLOT(accept()))); + FQ_VERIFY(connect(cancel, SIGNAL(clicked()), + dialog, SLOT(reject()))); + FQ_VERIFY(connect(dialog, SIGNAL(accepted()), + this, SLOT(readDialogData()))); + FQ_VERIFY(connect(dialog, SIGNAL(rejected()), + this, SLOT(closeDialog()))); + dialog->setModal(true); + dialog->exec(); +} + +void FQTermExternalEditor::readDialogData() { + QDialog *dialog = (QDialog*)sender(); + QTextEdit* edit = (QTextEdit*)dialog->findChild(textEditName_); + if (edit) { + emit done(edit->toPlainText()); + } + closeDialog(); +} + +void FQTermExternalEditor::closeDialog() { + sender()->deleteLater(); +} + +void FQTermExternalEditor::start() { + if (FQTermPref::getInstance()->externalEditor_.isEmpty()) { + execDialog(); + return; + } + if (started_) + return; + started_ = true; + if (FQTermPref::getInstance()->externalEditorArg_.isEmpty()) { + editorProcess_->start(FQTermPref::getInstance()->externalEditor_, QStringList() << getTempFilename()); + } else { + FQ_TRACE("editor", 5) << FQTermPref::getInstance()->externalEditorArg_.arg(getTempFilename()); + editorProcess_->start(FQTermPref::getInstance()->externalEditor_ + " " + FQTermPref::getInstance()->externalEditorArg_.arg(getTempFilename())); + } +} + + +QString FQTermExternalEditor::getTempFilename() { + return getPath(USER_CONFIG) + "tmp_do_not_use.txt"; +} + +void FQTermExternalEditor::clearTempFileContent() { + QFile file(getTempFilename()); + file.open(QIODevice::Truncate | QIODevice::WriteOnly); + file.write("\xEF\xBB\xBF"); + file.flush(); + file.close(); +} + +void FQTermExternalEditor::stateChanged( QProcess::ProcessState state ) { + //FQ_TRACE("editor", 0) << "stateChanged: " << state << editorProcess_->readAllStandardOutput() << editorProcess_->readAllStandardError(); + if (!started_ || state != QProcess::NotRunning) + return; + QFile file(getTempFilename()); + file.open(QIODevice::ReadOnly); + QString result = U82U(file.readAll()); + file.close(); +#if !defined(WIN32) && !defined(__APPLE__) + if (result.endsWith(OS_NEW_LINE)) { + result.resize(result.size() - 1); + } +#endif + emit done(result); + clearTempFileContent(); + started_ = false; +} +} // namespace FQTerm +#include "fqterm_window.moc" diff --git a/src/fqterm/fqterm_window.h b/src/fqterm/fqterm_window.h new file mode 100644 index 0000000..011bf86 --- /dev/null +++ b/src/fqterm/fqterm_window.h @@ -0,0 +1,345 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_WINDOW_H +#define FQTERM_WINDOW_H + +#include +#include +#include +#include +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "fqterm_param.h" +#include "fqterm_config.h" +#include "fqterm_convert.h" +#include "fqterm_session.h" + +class QCloseEvent; +class QEvent; +class QKeyEvent; +class QMouseEvent; +class QMouseEvent; +class QProgressBar; +class QWheelEvent; + +namespace FQTerm { + +//class QProgressDialog; +class PageViewMessage; +class FQTermConfig; +class FQTermImage; +class FQTermFrame; +class FQTermHttp; +class FQTermScreen; +class FQTermSession; +class FQTermSound; +class FQTermWindow; +class popWidget; +class zmodemDialog; +class FQTermScriptEngine; + +class FQTermExternalEditor : public QObject { + Q_OBJECT; +public: + FQTermExternalEditor(QWidget* parent); + ~FQTermExternalEditor(); + void start(); +signals: + void done(const QString&); +public slots: + void stateChanged(QProcess::ProcessState state); +protected slots: + void readDialogData(); + void closeDialog(); +private: + void execDialog(); + QString getTempFilename(); + void clearTempFileContent(); + + static const QString textEditName_; + bool started_; + QProcess* editorProcess_; +}; + +class FQTermWindow : public QMainWindow, + public FQTermScriptEventListener { + friend class FQTermScreen; + + Q_OBJECT; + public: + FQTermWindow(FQTermConfig *, FQTermFrame *frame, FQTermParam param, int addr = -1, QWidget + *parent = 0, const char *name = 0, Qt::WFlags wflags = Qt::Window); + ~FQTermWindow(); + + void connectHost(); + bool isConnected(); + + void disconnect(); + //redraw the dirty lines + void refreshScreen(); + //repaint a dirty rectangle. + void repaintScreen(); + //force a repaint by sending a resize event + void forcedRepaintScreen(); + void viewMessages(); + void toggleAutoReply(); + void toggleAntiIdle(); + void toggleAutoReconnect(); + void setFont(bool isEnglish); + void saveSetting(bool ask = true); + + void runScript(const QString & filename); + int externInput(const QByteArray &); + int externInput(const QString &); + void getHttpHelper(const QString &, bool); + + void openUrl(QString url); + void openUrlImpl(QString url); + + FQTermSession * getSession() const { return session_; } + FQTermScreen * getScreen() const {return screen_;} + QPoint getUrlStartPoint() const { return urlStartPoint_; } + QPoint getUrlEndPoint() const { return urlEndPoint_; } + + //FQTermScriptEventListener +private: + virtual bool postQtScriptCallback(const QString& func, const QScriptValueList & args = QScriptValueList()); +#ifdef HAVE_PYTHON + virtual bool postPythonCallback(const QString& func, PyObject* pArgs); +#endif //HAVE_PYTHON + +public: + virtual long windowID() {return long(this);} + //end FQTermScriptEventListener + +signals: + void resizeSignal(FQTermWindow*); + void refreshOthers(FQTermWindow*); + void blinkTheTab(FQTermWindow*, bool); + void connectionClosed(FQTermWindow*); + public slots: + // ui + void copy(); + void paste(); + void openAsUrl(); + void searchIt(); + void shareIt(); + void externalEditor(); + void fastPost(); + void copyArticle(); + void setting(); + void setColor(); + void runScript(); + void stopScript(); + + void sendParsedString(const char*); + void showIP(bool show = true); + + void beep(); + void startBlink(); + void stopBlink(); + void onTitleSet(const QString& title); + + void connectionClosed(); + + void messageAutoReplied(); + + void pasteHelper(bool); + + QByteArray parseString(const QByteArray &, int *len = 0); + + // void sendMouseState(int, Qt::KeyboardModifier, Qt::KeyboardModifier, const + // QPoint &); + + + protected slots: + void setFont(); + void recreateMenu(); + + //refresh screen & reset cursor position + void sessionUpdated(); + + void requestUserPwd(QString *userName, QString *password, bool *isOK); + + void TelnetState(int); + void ZmodemState(int, int, const char *); + void showSessionErrorMessage(QString); + + void blinkTab(); + + void externalEditorDone(const QString& str); + + //http menu + void previewLink(); + void saveLink(); + void openLink(); + void copyLink(); + void previewImage(const QString &filename, bool raiseViewer); + void httpPreviewImage(const QString &filename, bool raiseViewer, bool done); + void startHttpDownload(FQTermHttp *, const QString &filedesp); + + void httpDone(QObject*); + + // decode + // void setMouseMode(bool); + void articleCopied(int e, const QString content); + + + protected: + bool event(QEvent*); + + void resizeEvent(QResizeEvent *); + void mouseDoubleClickEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void wheelEvent(QWheelEvent*); + void enterEvent(QEvent*); + void leaveEvent(QEvent*); + void changeEvent(QEvent*); + void closeEvent(QCloseEvent*); + void keyPressEvent(QKeyEvent*); + //void focusInEvent (QFocusEvent *); + + private: + FQTermFrame *frame_; + FQTermScreen *screen_; + FQTermSession *session_; + QString allMessages_; + // before calling repaintScreen(), pls + // fill this rectangle. + QRect clientRect_; + QPoint urlEndPoint_; + QPoint urlStartPoint_; + + QMenu *menu_; + QMenu *urlMenu_; + + static char directions_[][5]; + QCursor cursors_[9]; + + FQTermConvert encodingConverter_; + + // mouse select + QPoint lastMouseCell_; + bool isSelecting_; + + // address setting + int addressIndex_; + + // url rect + QRect urlRectangle_; + + //ip rect + QRect ipRectangle_; + + // play sound + FQTermSound *sound_; + + + FQTermConfig *config_; + zmodemDialog *zmodemDialog_; + + //osd + PageViewMessage *pageViewMessage_; + + popWidget *popWindow_; + QTimer *tabBlinkTimer_; + + bool isMouseClicked_; + bool blinkStatus_; + + bool isUrlUnderLined_; + + FQTermScriptEngine *script_engine_; + FQTermExternalEditor *externalEditor_; + private: + void addMenu(); + + void setCursorPosition(const QPoint& mousePosition); + //set cursor type according to the content + //show ip location info if openUrlCheck is set + void setCursorType(const QPoint& mousePosition); + + + void enterMenuItem(); + void processLClick(const QPoint& cellClicked); + + void startSelecting(const QPoint& mousePosition); + void onSelecting(const QPoint& mousePosition); + void finishSelecting(const QPoint& mousePosition); + + void updateSetting(const FQTermParam& param); + + void sendKey(const int key, const Qt::KeyboardModifiers modifier, + const QString &text); + + bool scriptKeyEvent(QKeyEvent *keyevent); + bool scriptMouseEvent(QMouseEvent *mouseevent); + bool scriptWheelEvent(QWheelEvent *wheelevent); + + void writePasting(const QString& content); + + +signals: + //these 2 signals are connected to corresponding slots to + //make write thread safe. + int writeStringSignal(const QString& str); + int writeRawStringSignal(const QString& str); +public slots: + //for script + int writeString(const QString& str) {return externInput(str);} + int writeRawString(const QString& str); +public: + void writeString_ts(const QString& str) {emit writeStringSignal(str);} + void writeRawString_ts(const QString& str) {emit writeRawStringSignal(str);} + + + +//python support +#ifdef HAVE_PYTHON +public: + QString getPythonErrorMessage() { + return pythonErrorMessage_; + } + void runPythonScript(); + void runPythonScriptFile(const QString&); + +protected: + bool pythonCallback(const QString &, PyObject*); + int runPythonFile(const QString& file); + void initPython(const QString& file); + void finalizePython(); + //void sendMouseState(int, ButtonState, ButtonState, const QPoint&); +private: + PyObject *pModule, *pDict; + bool pythonScriptLoaded_; + QString pythonErrorMessage_; +#endif + +}; + +} // namespace FQTerm + +#endif // FQTERM_WINDOW_H + diff --git a/src/fqterm/fqterm_wndmgr.cpp b/src/fqterm/fqterm_wndmgr.cpp new file mode 100644 index 0000000..0e90b1c --- /dev/null +++ b/src/fqterm/fqterm_wndmgr.cpp @@ -0,0 +1,381 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +///////////////////////////////////////////////////////////////// +//TODO: This class has too many overlap with MDI Area. +//It should inherit the QMdiArea... +///////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fqterm_frame.h" +#include "fqterm_path.h" +#include "fqterm_screen.h" +#include "fqterm_trace.h" +#include "fqterm_window.h" +#include "fqterm_wndmgr.h" +#ifdef HAVE_PYTHON +#include +#endif //HAVE_PYTHON +namespace FQTerm { + +//constructor +FQTermWndMgr::FQTermWndMgr(QWidget *parent, const char *name) + : QMdiArea(parent), + subWindowMax_(true), + subWindowSize_(640, 480), + tabBar_(NULL) + { + tabBar_ = new FQTermTabBar(this); + tabBar_->setShape(QTabBar::RoundedSouth); + FQ_VERIFY(connect(tabBar_, SIGNAL(currentChanged(int)), + this, SLOT(activateTheWindow(int)))); + FQ_VERIFY(connect(tabBar_, SIGNAL(rightClicked(int,const QPoint&)), + this, SLOT(onTabRightClicked(int,const QPoint&)))); + FQ_VERIFY(connect(tabBar_, SIGNAL(doubleClicked(int,const QPoint&)), + this, SLOT(onTabDoubleClicked(int,const QPoint&)))); + setObjectName(name); + termFrame_ = (FQTermFrame*)parent; + isAfterRemoved_ = false; +} + +//destructor +FQTermWndMgr::~FQTermWndMgr(){} + + +//remove window-tab-iconset +bool FQTermWndMgr::closeWindow(FQTermWindow *mw) { + FQ_FUNC_TRACE("wndmgr", 3); + QMdiSubWindow* subWindow = FQToMDI(mw); + if (subWindow) { + return subWindow->close(); + } + return false; +} + +bool FQTermWndMgr::closeAllWindow() { + FQ_FUNC_TRACE("wndmgr", 3); + + bool anyConnected = false; + + for (int i = 0; i < subWindowList().size(); ++i) { + FQTermWindow * window = (FQTermWindow *)(subWindowList()[i]->widget()); + if (window->isConnected()) { + anyConnected = true; + break; + } + } + + bool warn = FQTermPref::getInstance()->openWarnOnClose_; + if (anyConnected && warn) { + QMessageBox mb(tr("FQTerm"), + tr("Still connected, do you really want to exit?"), + QMessageBox::Warning, QMessageBox::Yes|QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape, 0, this); + if (mb.exec() != QMessageBox::Yes) { + return false; + } + } + FQTermPref::getInstance()->openWarnOnClose_ = false; + while (count() > 0) { + bool closed = subWindowList().at(0)->close(); + if (!closed) { + FQTermPref::getInstance()->openWarnOnClose_ = warn; + return false; + } + } + FQTermPref::getInstance()->openWarnOnClose_ = warn; + return true; +} + + + +//active the window when switch the tab +void FQTermWndMgr::activateTheWindow(int n) { + FQ_FUNC_TRACE("wndmgr", 3); + + if (n < 0 || n >= count() || subWindowList().at(n) == activeSubWindow()) + return; + + QMdiSubWindow *subWindow = subWindowList().at(n); + + // Fix the refresh bug by send PaintEvent to session screen. + //subWindow->setFocus(); + setActiveSubWindow(subWindow); + +} + +//blink the tab when message come in +void FQTermWndMgr::blinkTheTab(FQTermWindow *mw, bool bVisible) { + FQ_FUNC_TRACE("wndmgr", 10); + static QIcon a_icon(getPath(RESOURCE) + "pic/tabpad.png"); + static QIcon b_icon(getPath(RESOURCE) + "pic/transp.png"); + + //find where it is + QMdiSubWindow* subWindow = FQToMDI(mw); + if (!subWindow) + return; + int n = subWindowList().indexOf(subWindow); + QIcon *icon = icons_.at(n); + //FIXME: QIcon::Automatic + if (bVisible) { + icon->addFile(getPath(RESOURCE) + "pic/tabpad.png"); + + tabBar_->setTabIcon(n, a_icon); + } else { + //,QIcon::Automatic); + icon->addFile(getPath(RESOURCE) + "pic/transp.png"); + tabBar_->setTabIcon(n, b_icon); + } + //,QIcon::Automatic); + + + + + tabBar_->update(); +} + +//return the number of connected window +int FQTermWndMgr::count() { + return subWindowList().count(); +} + +FQTermWindow *FQTermWndMgr::activeWindow() { + return MDIToFQ(activeSubWindow()); +} + + +bool FQTermWndMgr::afterRemove() { + if (isAfterRemoved_) { + isAfterRemoved_ = false; + return true; + } else { + return false; + } +} + +void FQTermWndMgr::refreshAllExcept(FQTermWindow *termWindow) { + for (int i = 0; i < subWindowList().count(); ++i) { + FQTermWindow * window = (FQTermWindow *)(subWindowList()[i]->widget()); + if (window != termWindow) { + window->repaintScreen(); + } + } +} + + +FQTermWindow* FQTermWndMgr::newWindow( const FQTermParam ¶m, FQTermConfig* config, QIcon* icon, int index /*= -1*/ ) +{ + FQTermWindow *window = new FQTermWindow(config, termFrame_, param, index, this, 0); + //add window-tab-icon to window manager + + + QMdiSubWindow* subWindow = addSubWindow(window); + subWindow->setAttribute(Qt::WA_OpaquePaintEvent); + subWindow->setAttribute(Qt::WA_DeleteOnClose); + + icons_.append(icon); + if (count() == 1) { + termFrame_->enableMenuToolBar(true); + } + //if no this call, the tab wont display untill you resize the window + int idx = tabBar_->addTab(*icon, window->windowTitle()); + tabBar_->updateGeometry(); + tabBar_->update(); + + subWindow->resize(subWindowSize_); + if (subWindowMax_) { + subWindow->setWindowFlags(Qt::SubWindow | Qt::CustomizeWindowHint | Qt::WindowMinMaxButtonsHint); + subWindow->showMaximized(); + } else { + subWindow->setWindowFlags(Qt::SubWindow | (Qt::CustomizeWindowHint + | Qt::WindowMinMaxButtonsHint + | Qt::WindowSystemMenuHint)); + subWindow->show(); + } + tabBar_->setTabData(idx, qVariantFromValue((QObject*)window)); + FQ_VERIFY(connect(window, SIGNAL(destroyed(QObject*)), + this ,SLOT(onSubWindowClosed(QObject*)))); + FQ_VERIFY(connect(window, SIGNAL(resizeSignal(FQTermWindow*)), + this, SLOT(subWindowResized(FQTermWindow*)))); + FQ_VERIFY(connect(this, SIGNAL(subWindowActivated(QMdiSubWindow*)), + this, SLOT(onSubWindowActivated(QMdiSubWindow*)))); + FQ_VERIFY(connect(window, SIGNAL(blinkTheTab(FQTermWindow*, bool)), + this, SLOT(blinkTheTab(FQTermWindow*, bool)))); + FQ_VERIFY(connect(window, SIGNAL(refreshOthers(FQTermWindow*)), + this, SLOT(refreshAllExcept(FQTermWindow*)))); + FQ_VERIFY(connect(window, SIGNAL(connectionClosed(FQTermWindow*)), + this, SLOT(closeWindow(FQTermWindow*)), Qt::QueuedConnection)); + return window; +} + +void FQTermWndMgr::onSubWindowClosed(QObject* obj) { + + for (int i = 0; i < tabBar_->count(); ++i) { + if (tabBar_->tabData(i) == qVariantFromValue(obj)) { + if (count() == 0) { + termFrame_->enableMenuToolBar(false); + } + if (i == tabBar_->currentIndex()) + isAfterRemoved_ = true; + tabBar_->removeTab(i); + icons_.removeAt(i); + } + } + +} + +//--------------------------- +//record subwindows' size +//--------------------------- +void +FQTermWndMgr::subWindowResized(FQTermWindow *mw) { + QMdiSubWindow* subWindow = FQToMDI(mw); + if (!subWindow) + return; + Qt::WindowFlags wfs = subWindow->windowFlags(); + + if (!(subWindowMax_ = subWindow->isMaximized())){ + if (!subWindow->isMinimized()) { + subWindowSize_ = subWindow->frameSize(); + } + subWindow->setWindowFlags(wfs | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); + } + else { + subWindow->setWindowFlags(wfs & ~Qt::WindowSystemMenuHint); + } + +} + +void FQTermWndMgr::cascade() { + QSize oldSize = subWindowSize_; + cascadeSubWindows(); + foreach(QMdiSubWindow* subWindow, subWindowList()) { + if (subWindow) { + subWindow->resize(oldSize); + } + } +} + +void FQTermWndMgr::tile() { + tileSubWindows(); +} + +void FQTermWndMgr::activateNextWindow() { + activateTheWindow((activeWindowIndex() + 1) % count()); +} + +void FQTermWndMgr::activatePrevWindow() { + activateTheWindow((activeWindowIndex() - 1 + count()) % count()); +} + +FQTermWindow * FQTermWndMgr::nthWindow(int n) { + return (FQTermWindow *)(subWindowList()[n]->widget()); +} + +void FQTermWndMgr::onSubWindowActivated(QMdiSubWindow * subWindow) { + int n = subWindowList().indexOf(subWindow); + if (n == -1) + return; + FQTermWindow* mw = MDIToFQ(subWindow); + if (mw->isMaximized() && + afterRemove()) { + mw->showNormal(); + mw->showMaximized(); + } + if (tabBar_->currentIndex() != n) { + FQ_VERIFY(disconnect(this, SIGNAL(subWindowActivated(QMdiSubWindow*)), + this, SLOT(onSubWindowActivated(QMdiSubWindow*)))); + tabBar_->setCurrentIndex(n); + FQ_VERIFY(connect(this, SIGNAL(subWindowActivated(QMdiSubWindow*)), + this, SLOT(onSubWindowActivated(QMdiSubWindow*)))); + } + termFrame_->updateMenuToolBar(); +} + +void FQTermWndMgr::onTabRightClicked(int index, const QPoint& p) { + QMenu* menu = FQToMDI(nthWindow(index))->systemMenu(); + menu->popup(p); +} + +void FQTermWndMgr::onTabDoubleClicked(int index, const QPoint& p) { + closeWindow(nthWindow(index)); +} + +FQTermWindow* FQTermWndMgr::MDIToFQ( QMdiSubWindow* subWindow ) +{ + if (!subWindowList().contains(subWindow)) + return NULL; + return (FQTermWindow*)subWindow->widget(); +} + +QMdiSubWindow* FQTermWndMgr::FQToMDI( FQTermWindow* window ) +{ + for (int i = 0; i < subWindowList().count(); ++i) { + if ((FQTermWindow*)(subWindowList()[i]->widget()) == window) { + return subWindowList()[i]; + } + } + return NULL; +} + +int FQTermWndMgr::FQToIndex( FQTermWindow* window ) +{ + return subWindowList().indexOf(FQToMDI(window)); +} + +bool FQTermWndMgr::event( QEvent* e ) { + if (e->type() == QEvent::ShortcutOverride) { + QKeyEvent* ke = (QKeyEvent*)e; + if (ke->key() == Qt::Key_W && ke->modifiers() == Qt::ControlModifier) { + ke->accept(); + return true; + } + } + return QMdiArea::event(e); +} +void FQTermTabBar::mouseReleaseEvent( QMouseEvent * me ) { + int index = tabAt(me->pos()); + if (index != -1 && me->button() == Qt::RightButton && me->modifiers() == Qt::NoModifier) { + emit rightClicked(index, mapToGlobal(me->pos())); + } +} + +void FQTermTabBar::mouseDoubleClickEvent( QMouseEvent * me ) { + int index = tabAt(me->pos()); + if (index != -1 && me->button() == Qt::LeftButton && me->modifiers() == Qt::NoModifier) { + emit doubleClicked(index, mapToGlobal(me->pos())); + } +} +} // namespace FQTerm + +#include "fqterm_wndmgr.moc" diff --git a/src/fqterm/fqterm_wndmgr.h b/src/fqterm/fqterm_wndmgr.h new file mode 100644 index 0000000..5038d8f --- /dev/null +++ b/src/fqterm/fqterm_wndmgr.h @@ -0,0 +1,115 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_WND_MGR_H +#define FQTERM_WND_MGR_H + +#include +#include +#include +#include +#include +#include +#include + +class QEvent; +class QIcon; +class QSize; +class FQTermConfig; +namespace FQTerm { + +class FQTermWindow; +class FQTermFrame; + +class FQTermTabBar : public QTabBar { + Q_OBJECT; +public: + FQTermTabBar(QWidget *parent = 0) : QTabBar(parent) {} +protected: + virtual void mouseReleaseEvent(QMouseEvent * me); + virtual void mouseDoubleClickEvent(QMouseEvent * me); +signals: + void rightClicked(int index, const QPoint& p); + void doubleClicked(int index, const QPoint& p); +}; + +class FQTermWndMgr: public QMdiArea { + Q_OBJECT; + public: + FQTermWndMgr(QWidget *parent = 0, const char *name = 0); + ~FQTermWndMgr(); + + QTabBar* tabBar() {return tabBar_;} + + FQTermWindow* newWindow(const FQTermParam ¶m, FQTermConfig* config, QIcon* icon, int index = -1); + bool closeAllWindow(); + + + + FQTermWindow *activeWindow(); + int activeWindowIndex() { + return FQToIndex(activeWindow()); + } + FQTermWindow *nthWindow(int n); + int count(); + + //sub-window position & size + + bool getSubWindowMax() const { return subWindowMax_; } + void setSubWindowMax(bool val) { subWindowMax_ = val; } + QSize getSubWindowSize() const { return subWindowSize_; } + void setSubWindowSize(QSize val) { subWindowSize_ = val; } + + public slots: + bool closeWindow(FQTermWindow *mw); + void onSubWindowClosed(QObject* obj); + //record subwindows' size changes + void subWindowResized(FQTermWindow *); + void activateTheWindow(int n); + void activateNextWindow(); + void activatePrevWindow(); + void refreshAllExcept(FQTermWindow *mw); + void blinkTheTab(FQTermWindow *mw, bool bVisible); + void cascade(); + void tile(); + +protected: + + QList icons_; + FQTermFrame *termFrame_; + bool isAfterRemoved_; + QSize subWindowSize_; + bool subWindowMax_; + FQTermTabBar* tabBar_; + + FQTermWindow* MDIToFQ(QMdiSubWindow* subWindow); + QMdiSubWindow* FQToMDI(FQTermWindow* window); + int FQToIndex(FQTermWindow* window); + bool afterRemove(); + bool event(QEvent* e); +protected slots: + void onSubWindowActivated(QMdiSubWindow * subWindow); + void onTabRightClicked(int index, const QPoint& p); + void onTabDoubleClicked(int index, const QPoint& p); +}; + +} // namespace FQTerm + +#endif // FQTERM_WND_MGR_H diff --git a/src/fqterm/main.cpp b/src/fqterm/main.cpp new file mode 100644 index 0000000..40969fd --- /dev/null +++ b/src/fqterm/main.cpp @@ -0,0 +1,135 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#if defined(WIN32) +#include +#include +#else +#include +#include +#include +#endif + +#if defined(FQTERM_USE_STATIC_QT) + // You can change the definition of FQTERM_USE_STATIC_QT in + // fqterm/CMakeLists.txt.{linux, macos, win32}. + + // static link Qt4 plugins. + void loadNecessaryQtPlugins() {} + #include + Q_IMPORT_PLUGIN(qkrcodecs) + Q_IMPORT_PLUGIN(qcncodecs) + Q_IMPORT_PLUGIN(qjpcodecs) + Q_IMPORT_PLUGIN(qtwcodecs) + Q_IMPORT_PLUGIN(qjpeg) + Q_IMPORT_PLUGIN(qgif) + Q_IMPORT_PLUGIN(qmng) +#else + // dynamic link Qt4 plugins. + #include + void loadNecessaryQtPlugins() { + static QPluginLoader qkrcodecsLoader( "qkrcodecs" ); + static QPluginLoader qcncodecsLoader( "qcncodecs" ); + static QPluginLoader qjpcodecsLoader( "qjpcodecs" ); + static QPluginLoader qtwcodecsLoader( "qtwcodecs" ); + static QPluginLoader qjpegLoader("qjpeg"); + static QPluginLoader qgifLoader("qgif"); + static QPluginLoader qmngLoader("qmng"); + + qkrcodecsLoader.load(); + qcncodecsLoader.load(); + qjpcodecsLoader.load(); + qtwcodecsLoader.load(); + qjpegLoader.load(); + qgifLoader.load(); + qmngLoader.load(); + } +#endif + +#include +#include +#include +#include + +#include "fqterm.h" +#include "fqterm_app.h" +#include "fqterm_frame.h" +#include "fqterm_path.h" +#include "fqterm_trace.h" +#include "fqterm_config.h" +#include "fqterm_param.h" +#include "fqterm_text_line.h" + + + + +int main(int argc, char **argv) { +#if defined(WIN32) +#else + QApplication::setGraphicsSystem("raster"); +#endif + FQTerm::FQTermApplication a(argc, argv); + // Set trace categories and level. + FQTerm::setMaxTraceLevel(1); + for (int i = 1; i < argc; ++i) { + QString str(argv[i]); + bool ok; + int max_level = str.toInt(&ok, 0); + + if (ok) { + FQTerm::setMaxTraceLevel(max_level); + } else { + FQTerm::addAllowedCategory(argv[i]); + } + } + + using namespace FQTerm; + + loadNecessaryQtPlugins(); + + // char buf[] = "\xc8\xb8"; + // QString ucs2 = QTextCodec::codecForName("Big5")->toUnicode(buf); + // QVector ucs4 = ucs2.toUcs4(); + // QByteArray utf8 = ucs2.toUtf8(); + // const char *utf8c = utf8.constData(); + + // FQ_TRACE("text", 0) << "\n" << dumpHexString << std::string(buf, sizeof(buf) - 1) + // << dumpNormalString << " \n-->" + // << dumpNormalString << "\nucs4 " << ucs4.size() << " " << ucs4[0] + // << dumpNormalString << "\nucs2 " << ucs2.size() << " " << ucs2.at(0).unicode() + // << dumpNormalString << "\nutf8 " << dumpHexString << utf8c; + //return 0; + + if (!iniSettings()) { + return -1; + } + + FQTermFrame *mw = new FQTermFrame(); + mw->setWindowTitle("FQTerm " + QString(FQTERM_VERSION_STRING)); + mw->setWindowIcon(QPixmap(getPath(RESOURCE) + "pic/fqterm.png")); + mw->show(); + a.setQuitOnLastWindowClosed(false); + FQ_VERIFY(a.connect(mw, SIGNAL(destroyed(QObject*)), &a, SLOT(mainWindowDestroyed(QObject*)), Qt::QueuedConnection)); + FQ_VERIFY(a.connect(&a, SIGNAL(saveData()), mw, SLOT(saveSetting()))); + int res = a.exec(); + return res; +} diff --git a/src/protocol/CMakeLists.txt b/src/protocol/CMakeLists.txt new file mode 100644 index 0000000..c515590 --- /dev/null +++ b/src/protocol/CMakeLists.txt @@ -0,0 +1,65 @@ +set(export_SRCS + fqterm_socket.cpp + fqterm_socket.h + fqterm_ssh_socket.h + fqterm_ssh_socket.cpp +) + +set(internal_SRCS + internal/crc32.h + internal/fqterm_serialization.h + internal/fqterm_ssh_auth.h + internal/fqterm_ssh_buffer.h + internal/fqterm_ssh_cipher.h + internal/fqterm_ssh_const.h + internal/fqterm_ssh_des.h + internal/fqterm_ssh_hash.h + internal/fqterm_ssh_kex.h + internal/fqterm_ssh2_kex.h + internal/fqterm_ssh_mac.h + internal/fqterm_ssh_md5.h + internal/fqterm_ssh_packet.h + internal/fqterm_ssh1_packet.h + internal/fqterm_ssh2_packet.h + internal/fqterm_ssh_rsa.h + internal/fqterm_ssh_channel.h + internal/fqterm_ssh_types.h + internal/fqterm_ssh_pubkey.h + internal/crc32.cpp + internal/fqterm_ssh_auth.cpp + internal/fqterm_ssh_buffer.cpp + internal/fqterm_ssh_des.cpp + internal/fqterm_ssh_kex.cpp + internal/fqterm_ssh2_kex.cpp + internal/fqterm_ssh_mac.cpp + internal/fqterm_ssh_md5.cpp + internal/fqterm_ssh_packet.cpp + internal/fqterm_ssh1_packet.cpp + internal/fqterm_ssh2_packet.cpp + internal/fqterm_ssh_rsa.cpp + internal/fqterm_ssh_channel.cpp +) + +qt4_automoc( + ${export_SRCS} + ${internal_SRCS} +) + +include_directories( + ${QT_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} + ${QT_QTNETWORK_INCLUDE_DIR} + ${OPENSSL_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/internal + ${CMAKE_CURRENT_SOURCE_DIR}/../common + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_library(fqterm_protocol + ${export_SRCS} + ${internal_SRCS} +) + +add_dependencies(fqterm_protocol + fqterm_common +) diff --git a/src/protocol/fqterm_socket.cpp b/src/protocol/fqterm_socket.cpp new file mode 100644 index 0000000..131044a --- /dev/null +++ b/src/protocol/fqterm_socket.cpp @@ -0,0 +1,672 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include + +#include +#include +#include + +#include "fqterm.h" +#include "fqterm_socket.h" +#include "fqterm_trace.h" + +#if !defined(Q_OS_BSD4) && !defined(_OS_FREEBSD_) \ + && !defined(Q_OS_MACX) && !defined(Q_OS_DARWIN) +#include +#endif + +namespace FQTerm { + +/* hack from wget/http.c */ +#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3)) +static void base64_encode(const char *s, char *store, int length); +static char *basic_authentication_encode(const char *user, const char *passwd, + const char *header); +static int parse_http_status_line(const char *line, const char + **reason_phrase_ptr); + +const char wingate_enter = 'J' &0x1f; + +//============================================================================== +//FQTermSocketPrivate + +//============================================================================== +FQTermSocketPrivate::FQTermSocketPrivate(QObject *parent) + : QObject(parent) { + m_socket = new QTcpSocket(this); + + // proxy related + proxy_type = NOPROXY; + proxy_state = 0; + bauth = false; + + FQ_VERIFY(connect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected()))); + FQ_VERIFY(connect(m_socket, SIGNAL(hostFound()), this, SIGNAL(hostFound()))); + FQ_VERIFY(connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(connectionClosed()))); + + FQ_VERIFY(connect(m_socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()))); + FQ_VERIFY(connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(error(QAbstractSocket::SocketError)))); +} + +FQTermSocketPrivate::~FQTermSocketPrivate() { + delete m_socket; +} + +void FQTermSocketPrivate::setProxy(int nProxyType, bool bAuth, const QString &strProxyHost, + quint16 uProxyPort, const QString &strProxyUsr, + const QString &strProxyPwd) { + proxy_type = nProxyType; + if (proxy_type == NOPROXY) { + return ; + } + bauth = bAuth; + proxy_host = strProxyHost; + proxy_port = uProxyPort; + proxy_usr = strProxyUsr; + proxy_pwd = strProxyPwd; +} + +void FQTermSocketPrivate::socketConnected() { + QByteArray strPort; + QByteArray command(9, 0); + + char *proxyauth; + char *request; + int len = 0; + + switch (proxy_type) { + case NOPROXY: + // no proxy + emit connected(); + return ; + case WINGATE: + // Wingate Proxy + strPort.setNum(port); + writeBlock(host.toLocal8Bit()); + writeBlock(" "); + writeBlock(strPort); + writeBlock(&wingate_enter); // CTRL+J + emit socketState(TSHOSTCONNECTED); + return ; + case SOCKS4: + // Socks4 Proxy + command.resize(9); + command[0] = '\x04'; + command[1] = '\x01'; + memcpy(command.data() + 2, &addr_host.sin_port, 2); + memcpy(command.data() + 4, &addr_host.sin_addr, 4); + writeBlock(command); + proxy_state = 1; + emit socketState(TSPROXYCONNECTED); + return ; + case SOCKS5: + // Socks5 Proxy + if (bauth) { + command.resize(4); + command[0] = '\x05'; + command[1] = '\x02'; + command[2] = '\x02'; + command[3] = '\x00'; + writeBlock(command); + } + else { + command.resize(3); + command[0] = '\x05'; + command[1] = '\x01'; + command[2] = '\x00'; + writeBlock(command); + } + proxy_state = 1; + emit socketState(TSPROXYCONNECTED); + return ; + case HTTP: + proxyauth = NULL; + if (bauth) { + proxyauth = basic_authentication_encode(proxy_usr.toLocal8Bit(), + proxy_pwd.toLocal8Bit(), "Proxy-Authorization"); + } + + len = proxyauth != NULL ? strlen(proxyauth): 0; + + request = new char[host.length() + len + 81]; + + sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n""%s\r\n", host.toLatin1().constData(), port, + proxyauth != NULL ? proxyauth : ""); + + + writeBlock(request); + delete [] request; + free(proxyauth); + proxy_state = 1; + emit socketState(TSPROXYCONNECTED); + return ; + default: + emit socketState(TSHOSTCONNECTED); + return ; + } +} + +void FQTermSocketPrivate::socketReadyRead() { + if (proxy_type == NOPROXY || proxy_state == 0) { + emit readyRead(); + } + + int nbytes, nread; + QByteArray from_socket; + // get the data size + nbytes = bytesAvailable(); + if (nbytes <= 0) { + return ; + } + + //resize input buffer + from_socket.resize(0); + + //read data from socket to from_socket + from_socket = readBlock(nbytes); + nread = from_socket.size(); + //do some checks + if (nread <= 0) { + FQ_TRACE("socket", 0) << "Failed to read socket: " << nread << " <= 0"; + return ; + } + if (nread > nbytes) { + FQ_TRACE("socket", 0) << "Overflow when reading socket: " + << " nread = " << nread + << " > nbytes = " << nbytes; + return ; + } + + // Socks4 Proxy Reply + if (proxy_type == SOCKS4 && proxy_state == 1) { + if (nread != 8) { + emit socketState(TSPROXYERROR); + return ; + } + + if (from_socket.at(1) == 90) { + emit connected(); + } else { + emit socketState(TSPROXYFAIL); + } + proxy_state = 0; + return ; + } + + // HTTP Proxy Reply + if (proxy_type == HTTP && proxy_state != 0) { + const char *error; + int statcode = parse_http_status_line(from_socket.data(), &error); + if (statcode >= 200 && statcode < 300) { + emit connected(); + } else { + emit socketState(TSPROXYFAIL); + } + proxy_state = 0; + return ; + } + + // Socks5 Proxy Reply + if (proxy_type == SOCKS5 && proxy_state != 0) { + socks5_reply(from_socket, nread); + return ; + } +} + +void FQTermSocketPrivate::flush() { + m_socket->flush(); +} + +///////////////////////////////////////////////////// +//originally version from qhostaddress.cpp, qt4.3.2, --dp +static bool isIp4(const QString& address) +{ + QStringList ipv4 = address.split(QLatin1String(".")); + if (ipv4.count() != 4) + return false; + + for (int i = 0; i < 4; ++i) { + bool ok = false; + uint byteValue = ipv4.at(i).toUInt(&ok); + if (!ok || byteValue > 255) + return false; + + } + + return true; +} +///////////////////////////////////////////////////////// + +void FQTermSocketPrivate::connectToHost(const QString &hostname, quint16 portnumber) { + host = hostname; + port = portnumber; + addr_host.sin_port = htons(portnumber); + + if (proxy_type == NOPROXY) { + m_socket->connectToHost(host, port); + } else { + //get ip addr from name + struct hostent *hostent; +#if defined(_OS_WIN32_) || defined(Q_OS_WIN32) + WSADATA wsd; + if (WSAStartup(0x202, &wsd) != 0) { + emit socketState(TSEINIWINSOCK); + WSACleanup(); + return ; + } +#endif + // QHostAddress ha(host); + //ipv4 address check -- dp + if(isIp4(host)) { + hostent = gethostbyaddr( host.toLocal8Bit(), host.length(), AF_INET ); + FQ_TRACE("ssh", 1) << "by addr"; + } else { + hostent = gethostbyname(host.toLocal8Bit()); + FQ_TRACE("ssh", 1) << "by name"; + } + + if (hostent == NULL) { + emit socketState(TSEGETHOSTBYNAME); + return ; + } + //now only ipv4 support + memcpy(&addr_host.sin_addr, hostent->h_addr, 4); + m_socket->connectToHost(proxy_host, proxy_port); + } + +} + +void FQTermSocketPrivate::close() { + m_socket->close(); +} + +QByteArray FQTermSocketPrivate::readBlock(unsigned long maxlen) { + return m_socket->read(maxlen); +} + +long FQTermSocketPrivate::writeBlock(const QByteArray &data) { + return m_socket->write(data); +} + +unsigned long FQTermSocketPrivate::bytesAvailable() { + return m_socket->bytesAvailable(); +} + +/*------------------------------------------------------------------------ + * connect command for socks5 + *------------------------------------------------------------------------ + */ +void FQTermSocketPrivate::socks5_connect() { + QByteArray command(10, 0); + command[0] = '\x05'; + command[1] = '\x01'; + command[2] = '\x00'; + command[3] = '\x01'; + memcpy(command.data() + 4, &addr_host.sin_addr, 4); + memcpy(command.data() + 8, &addr_host.sin_port, 2); + writeBlock(command); +} + +/*------------------------------------------------------------------------ + * authentation command for socks5 + *------------------------------------------------------------------------ + */ +void FQTermSocketPrivate::socks5_auth() { + int ulen = proxy_usr.length(); + int plen = proxy_pwd.length(); + QByteArray command(3+ulen + plen, 0); + sprintf((char*)command.data(), " %s %s", proxy_usr.toLocal8Bit().data(), + proxy_pwd.toLocal8Bit().data()); + command[0] = '\x01'; + command[1] = ulen; + command[2+ulen] = plen; + writeBlock(command); +} + +/*------------------------------------------------------------------------ + * reply from socks5 + *------------------------------------------------------------------------ + */ +void FQTermSocketPrivate::socks5_reply(const QByteArray &from_socket, int nread) { + if (proxy_state == 1) { // Socks5 Proxy Replay 1 + if (nread != 2) { + proxy_state = 0; + emit socketState(TSPROXYERROR); + return ; + } + switch (from_socket.at(1)) { + case '\x00': + // no authentation needed + socks5_connect(); + proxy_state = 3; + emit socketState(TSCONNECTVIAPROXY); + return ; + case '\x02': + //need user/password + socks5_auth(); + proxy_state = 2; + emit socketState(TSPROXYAUTH); + return ; + case '\xff': + proxy_state = 0; + emit socketState(TSPROXYFAIL); + return ; + default: + proxy_state = 0; + emit socketState(TSPROXYFAIL); + return ; + } + } else if (proxy_state == 2) { //Socks5 Proxy Replay 2 + if (nread != 2) { + proxy_state = 0; + emit socketState(TSPROXYERROR); + return ; + } + + + if (from_socket.at(1) != '\00') { + proxy_state = 0; + emit socketState(TSPROXYFAIL); + return ; + } + socks5_connect(); + proxy_state = 3; + emit socketState(TSCONNECTVIAPROXY); + return ; + } else if (proxy_state == 3) { //Socks5 Proxy Replay 3 + proxy_state = 0; + if (nread != 10) { + emit socketState(TSPROXYERROR); + return ; + } + if (from_socket.at(1) != '\00') { + emit socketState(TSPROXYFAIL); + return ; + } + emit connected(); + return ; + } else { + proxy_state = 0; + return ; + } +} + +/* hack from wget/http.c */ +/* How many bytes it will take to store LEN bytes in base64. */ +#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3)) + +/* Encode the string S of length LENGTH to base64 format and place it + to STORE. STORE will be 0-terminated, and must point to a writable + buffer of at least 1+BASE64_LENGTH(length) bytes. */ +static void base64_encode(const char *s, char *store, int length) { + /* Conversion table. */ + static char tbl[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' + }; + int i; + unsigned char *p = (unsigned char*)store; + + /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ + for (i = 0; i < length; i += 3) { + *p++ = tbl[s[0] >> 2]; + *p++ = tbl[((s[0] &3) << 4) + (s[1] >> 4)]; + *p++ = tbl[((s[1] &0xf) << 2) + (s[2] >> 6)]; + *p++ = tbl[s[2] &0x3f]; + s += 3; + } + /* Pad the result if necessary... */ + if (i == length + 1) { + *(p - 1) = '='; + } else if (i == length + 2) { + *(p - 1) = *(p - 2) = '='; + } + /* ...and zero-terminate it. */ + *p = '\0'; +} + +/* Create the authentication header contents for the `Basic' scheme. + This is done by encoding the string `USER:PASS' in base64 and + prepending `HEADER: Basic ' to it. */ +static char *basic_authentication_encode(const char *user, const char *passwd, + const char *header) { + char *t1, *t2, *res; + int len1 = strlen(user) + 1+strlen(passwd); + int len2 = BASE64_LENGTH(len1); + + t1 = (char*)alloca(len1 + 1); + sprintf(t1, "%s:%s", user, passwd); + t2 = (char*)alloca(1+len2); + base64_encode(t1, t2, len1); + res = (char*)malloc(len2 + 11+strlen(header)); + sprintf(res, "%s: Basic %s\r\n", header, t2); + + return res; +} + +/* Parse the HTTP status line, which is of format: + + HTTP-Version SP Status-Code SP Reason-Phrase + + The function returns the status-code, or -1 if the status line is + malformed. The pointer to reason-phrase is returned in RP. */ +static int parse_http_status_line(const char *line, const char + **reason_phrase_ptr) { + /* (the variables must not be named `major' and `minor', because + that breaks compilation with SunOS4 cc.) */ + int mjr, mnr, statcode; + const char *p; + + *reason_phrase_ptr = NULL; + + /* The standard format of HTTP-Version is: `HTTP/X.Y', where X is + major version, and Y is minor version. */ + if (strncmp(line, "HTTP/", 5) != 0) { + return -1; + } + line += 5; + + /* Calculate major HTTP version. */ + p = line; + for (mjr = 0; QChar(*line).isDigit(); line++) { + mjr = 10 * mjr + (*line - '0'); + } + if (*line != '.' || p == line) { + return -1; + } + ++line; + + /* Calculate minor HTTP version. */ + p = line; + for (mnr = 0; QChar(*line).isDigit(); line++) { + mnr = 10 * mnr + (*line - '0'); + } + if (*line != ' ' || p == line) { + return -1; + } + /* Wget will accept only 1.0 and higher HTTP-versions. The value of + minor version can be safely ignored. */ + if (mjr < 1) { + return -1; + } + ++line; + + /* Calculate status code. */ + if (!(QChar(*line).isDigit() && QChar(line[1]).isDigit() && QChar(line[2]) + .isDigit())) { + return -1; + } + statcode = 100 *(*line - '0') + 10 *(line[1] - '0') + (line[2] - '0'); + + /* Set up the reason phrase pointer. */ + line += 3; + /* RFC2068 requires SPC here, but we allow the string to finish + here, in case no reason-phrase is present. */ + if (*line != ' ') { + if (! *line) { + *reason_phrase_ptr = line; + } else { + return -1; + } + } else { + *reason_phrase_ptr = line + 1; + } + + return statcode; +} + + +//============================================================================== +//FQTermTelnetSocket +//============================================================================== + +FQTermTelnetSocket::FQTermTelnetSocket() + : FQTermSocket() { + private_socket_ = new FQTermSocketPrivate(); + FQ_VERIFY(connect(private_socket_, SIGNAL(connected()), this, SIGNAL(connected()))); + FQ_VERIFY(connect(private_socket_, SIGNAL(hostFound()), this, SIGNAL(hostFound()))); + FQ_VERIFY(connect(private_socket_, SIGNAL(connectionClosed()), this, SIGNAL(connectionClosed()))); + FQ_VERIFY(connect(private_socket_, SIGNAL(delayedCloseFinished()), + this, SIGNAL(delayedCloseFinished()))); + FQ_VERIFY(connect(private_socket_, SIGNAL(readyRead()), this, SIGNAL(readyRead()))); + FQ_VERIFY(connect(private_socket_, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(error(QAbstractSocket::SocketError)))); + FQ_VERIFY(connect(private_socket_, SIGNAL(socketState(int)), this, SIGNAL(socketState(int)))); +} + +FQTermTelnetSocket::~FQTermTelnetSocket() { + delete private_socket_; +} + +void FQTermTelnetSocket::flush() { + private_socket_->flush(); +} + +void FQTermTelnetSocket::setProxy(int nProxyType, bool bAuth, + const QString &strProxyHost, + quint16 uProxyPort, + const QString &strProxyUsr, + const QString &strProxyPwd) { + private_socket_->setProxy(nProxyType, bAuth, strProxyHost, uProxyPort, strProxyUsr, + strProxyPwd); +} + +void FQTermTelnetSocket::connectToHost(const QString &host, quint16 port) { + private_socket_->connectToHost(host, port); +} + +void FQTermTelnetSocket::close() { + private_socket_->close(); +} + +QByteArray FQTermTelnetSocket::readBlock(unsigned long maxlen) { + return private_socket_->readBlock(maxlen); +} + +long FQTermTelnetSocket::writeBlock(const QByteArray &data) { + return private_socket_->writeBlock(data); +} + +unsigned long FQTermTelnetSocket::bytesAvailable() { + return private_socket_->bytesAvailable(); +} + + +FQTermLocalSocket::FQTermLocalSocket( const QString& shell_bin ) : shell_bin_(shell_bin) +{ + shell_process_ = new QProcess(); + shell_process_->setProcessChannelMode(QProcess::MergedChannels); + FQ_VERIFY(connect(shell_process_, SIGNAL(started()), this, SIGNAL(connected()))); + FQ_VERIFY(connect(shell_process_, SIGNAL(stateChanged(QProcess::ProcessState)), this , SLOT(stateChanged(QProcess::ProcessState)))); + FQ_VERIFY(connect(shell_process_, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)))); + //FQ_VERIFY(connect(shell_process_, SIGNAL(delayedCloseFinished()), this, SIGNAL(delayedCloseFinished()))); + FQ_VERIFY(connect(shell_process_, SIGNAL(readyRead()), this, SIGNAL(readyRead()))); + //TODO: Error + //FQ_VERIFY(connect(shell_process_, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(error(QAbstractSocket::SocketError)))); + //FQ_VERIFY(connect(shell_process_, SIGNAL(socketState(int)), this, SIGNAL(socketState(int)))); +} + +FQTermLocalSocket::~FQTermLocalSocket() +{ + delete shell_process_; +} + +void FQTermLocalSocket::connectToHost( const QString &host, quint16 port ) +{ + shell_process_->start("E:/yxl/test.exe"/*C:/Windows/System32/cmd.exeshell_bin*/, QIODevice::ReadWrite | QIODevice::Unbuffered); +} + +void FQTermLocalSocket::close() +{ + shell_process_->close(); +} + +QByteArray FQTermLocalSocket::readBlock( unsigned long maxlen ) +{ + return shell_process_->read(maxlen); +} + +long FQTermLocalSocket::writeBlock( const QByteArray &data ) +{ + int count = shell_process_->write(data); + + //char c; +// shell_process_->getChar(&c); +// shell_process_->ungetChar(c); + if (bytesAvailable()) + { + emit readyRead(); + } + return count; +} + +unsigned long FQTermLocalSocket::bytesAvailable() +{ + return shell_process_->bytesAvailable(); +} + +void FQTermLocalSocket::finished( int exitCode, QProcess::ExitStatus exitStatus ) +{ + emit connectionClosed(); +} +void FQTermLocalSocket::stateChanged(QProcess::ProcessState newState) +{ + switch(newState) + { + case QProcess::NotRunning: + break; + case QProcess::Starting: + emit hostFound(); + shell_process_->write("dir\n"); + break; + case QProcess::Running: + break; + + } +} + + +} // namespace FQTerm + +#include "fqterm_socket.moc" diff --git a/src/protocol/fqterm_socket.h b/src/protocol/fqterm_socket.h new file mode 100644 index 0000000..2d6240b --- /dev/null +++ b/src/protocol/fqterm_socket.h @@ -0,0 +1,196 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SOCKET_H +#define FQTERM_SOCKET_H + +// _OS_X_ not defined if i dont include it +#include + +// different +#if defined(Q_OS_WIN32) || defined(_OS_WIN32_) + +#include + +#elif defined(Q_OS_BSD4) || defined(_OS_FREEBSD_) \ + || defined(Q_OS_MACX) || defined(Q_OS_DARWIN) + +#include +#include +#include +#include + +#else + +#include +#include +#include +#include + +#endif + +#include +#include +#include +#include + +class QTcpSocket; +namespace FQTerm { +/* + * Socket with proxy support. + * + */ +class FQTermSocketPrivate: public QObject { + + Q_OBJECT; + public: + FQTermSocketPrivate(QObject *parent_ = 0); + + ~FQTermSocketPrivate(); + + void flush(); + void setProxy(int nProxyType, bool bAuth, const QString &strProxyHost, + quint16 uProxyPort, const QString &strProxyUsr, + const QString &strProxyPwd); + void connectToHost(const QString &hostname, quint16 portnumber); + void close(); + QByteArray readBlock(unsigned long maxlen); + long writeBlock(const QByteArray &data); + unsigned long bytesAvailable(); + + signals: + void connected(); + void hostFound(); + void connectionClosed(); + void delayedCloseFinished(); + void readyRead(); + void error(QAbstractSocket::SocketError); + void socketState(int); + + protected slots: + void socketConnected(); + void socketReadyRead(); + + protected: + // socks5 function + void socks5_connect(); + void socks5_auth(); + void socks5_reply(const QByteArray &, int); + + private: + // proxy + int proxy_type; + QString proxy_host; + QString proxy_usr; + quint16 proxy_port; + QString proxy_pwd; + QString host; + quint16 port; + int proxy_state; + bool bauth; + + struct sockaddr_in addr_host; + + QTcpSocket *m_socket; +}; + +// Virtual base class for FQTermTelnetSocket and FQTermSSHSocket +class FQTermSocket: public QObject { + + Q_OBJECT; + public: + FQTermSocket(QObject *parent = 0): QObject(parent) {} + + virtual ~FQTermSocket() {} + + virtual void flush() = 0; + virtual void setProxy(int nProxyType, bool bAuth, + const QString &strProxyHost, + quint16 uProxyPort, + const QString &strProxyUsr, + const QString &strProxyPwd) = 0; + virtual void connectToHost(const QString &host, quint16 port) = 0; + virtual void close() = 0; + virtual QByteArray readBlock(unsigned long maxlen) = 0; + virtual long writeBlock(const QByteArray &data) = 0; + virtual unsigned long bytesAvailable() = 0; + virtual bool readyForInput() {return true;} + virtual bool setTermSize(int col, int row) {return 0;} + signals: + void sshAuthOK(); + void connected(); + void hostFound(); + void connectionClosed(); + void delayedCloseFinished(); + void readyRead(); + void error(QAbstractSocket::SocketError); + void errorMessage(QString); + void socketState(int); + void requestUserPwd(QString *user, QString *pwd, bool *isOK); +}; + +class FQTermTelnetSocket: public FQTermSocket { + private: + FQTermSocketPrivate *private_socket_; + + public: + FQTermTelnetSocket(); + + ~FQTermTelnetSocket(); + + void flush(); + void setProxy(int nProxyType, bool bAuth, const QString &strProxyHost, + quint16 uProxyPort, const QString &strProxyUsr, + const QString &strProxyPwd); + void connectToHost(const QString &host, quint16 port); + void close(); + QByteArray readBlock(unsigned long maxlen); + long writeBlock(const QByteArray &data); + unsigned long bytesAvailable(); +}; + +class FQTermLocalSocket: public FQTermSocket { + Q_OBJECT; +private: + QString shell_bin_; + QProcess* shell_process_; +public: + FQTermLocalSocket(const QString& shell_bin); + ~FQTermLocalSocket(); + void flush(){} + void setProxy(int nProxyType, bool bAuth, const QString &strProxyHost, + quint16 uProxyPort, const QString &strProxyUsr, + const QString &strProxyPwd){} + void connectToHost(const QString &host, quint16 port); + void close(); + QByteArray readBlock(unsigned long maxlen); + long writeBlock(const QByteArray &data); + unsigned long bytesAvailable(); + +public slots: + void stateChanged(QProcess::ProcessState newState); + void finished (int exitCode, QProcess::ExitStatus exitStatus); +}; + + + +} // namespace FQTerm + +#endif // FQTERM_SOCKET_H diff --git a/src/protocol/fqterm_ssh_socket.cpp b/src/protocol/fqterm_ssh_socket.cpp new file mode 100644 index 0000000..4c1e77a --- /dev/null +++ b/src/protocol/fqterm_ssh_socket.cpp @@ -0,0 +1,352 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_ssh_socket.h" +#include "fqterm_ssh_packet.h" +#include "fqterm_ssh1_packet.h" +#include "fqterm_ssh2_packet.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_ssh_rsa.h" +#include "fqterm_ssh_kex.h" +#include "fqterm_ssh2_kex.h" +#include "fqterm_ssh_const.h" +#include "fqterm_ssh_auth.h" +#include "fqterm_ssh_channel.h" +#include "fqterm_trace.h" +#include +namespace FQTerm { + +#define V1STR "SSH-1.5-FQTermSSH\n" +#define V2STR "SSH-2.0-FQTermSSH\n" +#define SSH_V1_C "SSH-1.5-FQTermSSH" +#define SSH_V2_C "SSH-2.0-FQTermSSH" + +FQTermSSHSocket::FQTermSSHSocket(int col, int row, const QString& termtype, const char *sshuser, const char *sshpasswd) + : termtype_(termtype) { + col_ = col; + row_ = row; + init_user_ = sshuser; + init_passwd_ = sshpasswd; + + private_socket_ = new FQTermSocketPrivate(); + + input_buffer_ = NULL; + output_buffer_ = NULL; + socket_buffer_ = NULL; + packet_receiver_ = NULL; + packet_sender_ = NULL; + key_exchanger_ = NULL; + authentication_ = NULL; + ssh_channel_ = NULL; + ssh_version_ = 1; + is_channel_ok_ = false; + auth_ok_emitted_ = false; + + FQ_VERIFY(connect(private_socket_, SIGNAL(hostFound()), this, SIGNAL(hostFound()))); + FQ_VERIFY(connect(private_socket_, SIGNAL(connected()), this, SIGNAL(connected()))); + FQ_VERIFY(connect(private_socket_, SIGNAL(connectionClosed()), this, SIGNAL(connectionClosed()))); + FQ_VERIFY(connect(private_socket_, SIGNAL(delayedCloseFinished()), this, SIGNAL(delayedCloseFinished()))); + FQ_VERIFY(connect(private_socket_, SIGNAL(error(QAbstractSocket::SocketError )), this, SIGNAL(error(QAbstractSocket::SocketError )))); + FQ_VERIFY(connect(private_socket_, SIGNAL(socketState(int)), this, SIGNAL(socketState(int)))); + + FQ_VERIFY(connect(private_socket_, SIGNAL(readyRead()), this, SLOT(socketReadyRead()))); +} + +FQTermSSHSocket::~FQTermSSHSocket() { + delete private_socket_; + delete input_buffer_; + delete output_buffer_; + delete socket_buffer_; + delete packet_receiver_; + delete packet_sender_; + delete key_exchanger_; + delete authentication_; + delete ssh_channel_; +} + +void FQTermSSHSocket::init(int ssh_version) { + // Actually we could reuse these buffers, sender/receivers, and etc. + // but in that case reset methods should be added to all these classes. + // Guys lazy as me won't do that. + + delete input_buffer_; + delete output_buffer_; + delete socket_buffer_; + delete packet_receiver_; + delete packet_sender_; + delete key_exchanger_; + delete authentication_; + delete ssh_channel_; + + is_channel_ok_ = false; + auth_ok_emitted_ = false; + + if (ssh_version == 1) { + input_buffer_ = new FQTermSSHBuffer(1024); + output_buffer_ = new FQTermSSHBuffer(1024); + socket_buffer_ = new FQTermSSHBuffer(1024); + packet_receiver_ = new FQTermSSH1PacketReceiver; + packet_sender_ = new FQTermSSH1PacketSender; + key_exchanger_ = new FQTermSSH1Kex(SSH_V1_C, server_name_.toAscii().constData()); + authentication_ = new FQTermSSH1PasswdAuth(init_user_, init_passwd_); + ssh_channel_ = new FQTermSSH1Channel; + + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), this, SLOT(handlePacket(int)))); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetError(QString)), this, SLOT(handleError(QString)))); + + FQ_VERIFY(connect(packet_sender_, SIGNAL(dataToWrite()), this, SLOT(writeData()))); + + FQ_VERIFY(connect(key_exchanger_, SIGNAL(kexOK()), this, SLOT(kexOK()))); + FQ_VERIFY(connect(key_exchanger_, SIGNAL(kexError(QString)), this, SLOT(handleError(QString)))); + FQ_VERIFY(connect(key_exchanger_, SIGNAL(reKex()), packet_receiver_, SLOT(resetEncryption()))); + FQ_VERIFY(connect(key_exchanger_, SIGNAL(reKex()), packet_sender_, SLOT(resetEncryption()))); + FQ_VERIFY(connect(key_exchanger_, SIGNAL(startEncryption(const u_char*)), packet_receiver_, SLOT(startEncryption(const u_char*)))); + FQ_VERIFY(connect(key_exchanger_, SIGNAL(startEncryption(const u_char*)), packet_sender_, SLOT(startEncryption(const u_char*)))); + + FQ_VERIFY(connect(authentication_, SIGNAL(requestUserPwd(QString *, QString *, bool *)), this, SIGNAL(requestUserPwd(QString *, QString *, bool *)))); + FQ_VERIFY(connect(authentication_, SIGNAL(authOK()), this, SLOT(authOK()))); + FQ_VERIFY(connect(authentication_, SIGNAL(authError(QString)), this, SLOT(handleError(QString)))); + + FQ_VERIFY(connect(ssh_channel_, SIGNAL(channelOK()), this, SLOT(channelOK()))); + FQ_VERIFY(connect(ssh_channel_, SIGNAL(channelReadyRead(const char *, int)), this, SLOT(channelReadyRead(const char *, int)))); + + key_exchanger_->initKex(packet_receiver_, packet_sender_); + } else { + input_buffer_ = new FQTermSSHBuffer(1024); + output_buffer_ = new FQTermSSHBuffer(1024); + socket_buffer_ = new FQTermSSHBuffer(1024); + packet_receiver_ = new FQTermSSH2PacketReceiver; + packet_sender_ = new FQTermSSH2PacketSender; + key_exchanger_ = new FQTermSSH2Kex(SSH_V2_C, server_name_.toAscii().constData()); + authentication_ = new FQTermSSH2PasswdAuth(init_user_, init_passwd_); + ssh_channel_ = new FQTermSSH2Channel; + + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), this, SLOT(handlePacket(int)))); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetError(QString)), this, SLOT(handleError(QString)))); + + FQ_VERIFY(connect(packet_sender_, SIGNAL(dataToWrite()), this, SLOT(writeData()))); + + FQ_VERIFY(connect(key_exchanger_, SIGNAL(kexOK()), this, SLOT(kexOK()))); + FQ_VERIFY(connect(key_exchanger_, SIGNAL(kexError(QString)), this, SLOT(handleError(QString)))); + FQ_VERIFY(connect(key_exchanger_, SIGNAL(reKex()), packet_receiver_, SLOT(resetEncryption()))); + FQ_VERIFY(connect(key_exchanger_, SIGNAL(reKex()), packet_sender_, SLOT(resetEncryption()))); + + FQ_VERIFY(connect(key_exchanger_, SIGNAL(startEncryption(const u_char*)), packet_receiver_, SLOT(startEncryption(const u_char*)))); + FQ_VERIFY(connect(key_exchanger_, SIGNAL(startEncryption(const u_char*)), packet_sender_, SLOT(startEncryption(const u_char*)))); + + FQ_VERIFY(connect(authentication_, SIGNAL(requestUserPwd(QString *, QString *, bool *)), this, SIGNAL(requestUserPwd(QString *, QString *, bool *)))); + FQ_VERIFY(connect(authentication_, SIGNAL(authOK()), this, SLOT(authOK()))); + FQ_VERIFY(connect(authentication_, SIGNAL(authError(QString)), this, SLOT(handleError(QString)))); + + FQ_VERIFY(connect(ssh_channel_, SIGNAL(channelOK()), this, SLOT(channelOK()))); + FQ_VERIFY(connect(ssh_channel_, SIGNAL(channelReadyRead(const char *, int)), this, SLOT(channelReadyRead(const char *, int)))); + FQ_VERIFY(connect(ssh_channel_, SIGNAL(channelError(QString)), this, SLOT(handleError(QString)))); + + key_exchanger_->initKex(packet_receiver_, packet_sender_); + } +} + +void FQTermSSHSocket::kexOK() { + FQ_TRACE("sshsocket", 3) << "Key exchange completed!"; + authentication_->initAuth(packet_receiver_, packet_sender_); +} + +void FQTermSSHSocket::authOK() { + FQ_TRACE("sshsocket", 3) << "Auth completed!"; + ssh_channel_->initChannel(packet_receiver_, packet_sender_, col_, row_, termtype_); +} + +void FQTermSSHSocket::channelOK() { + FQ_TRACE("sshsocket", 3) << "Channel established!"; + is_channel_ok_ = true; + //auth_ok_emitted_ = false; +} + +void FQTermSSHSocket::channelReadyRead(const char *data, int len) { + input_buffer_->putRawData(data, len); + emit readyRead(); +} + +unsigned long FQTermSSHSocket::socketWriteBlock(const char *data, unsigned long len) { + QByteArray to_write(data, len); + return private_socket_->writeBlock(to_write); +} + +void FQTermSSHSocket::socketReadyRead() { + if (!auth_ok_emitted_ && is_channel_ok_) { + auth_ok_emitted_ = true; + emit sshAuthOK(); + } + unsigned long size; + + switch (ssh_socket_state_) { + case BeforeSession: + { + QByteArray str; + int version; + size = private_socket_->bytesAvailable(); + str = private_socket_->readBlock(size); + + server_name_ = QString(str).trimmed(); // remove the newline + version = chooseVersion(str.data()); + + FQ_TRACE("sshsocket", 3) << "SSH server: " << server_name_; + FQ_TRACE("sshsocket", 3) << "SSH version chosen: " << version; + + if (version == 1) { + init(1); + ssh_version_ = 1; + socketWriteBlock(V1STR, strlen(V1STR)); + } else if (version == 2) { + init(2); + ssh_version_ = 2; + socketWriteBlock(V2STR, strlen(V2STR)); + } else { + handleError(tr("Unknown SSH version. " + "Check if you set the right server and port.")); + return ; + } + ssh_socket_state_ = SockSession; + private_socket_->flush(); + break; + } + case SockSession: + parsePacket(); + } +} + +void FQTermSSHSocket::parsePacket() { + unsigned long size; + QByteArray data; + size = private_socket_->bytesAvailable(); + data = private_socket_->readBlock(size); + + socket_buffer_->putRawData(data.data(), size); + packet_receiver_->parseData(socket_buffer_); +} + +int FQTermSSHSocket::chooseVersion(const QString &ver) { + QString verion = ver.mid(ver.indexOf("-") + 1); + verion = verion.left(verion.indexOf("-")); + + if (verion == "1.99" || verion == "1.3" || verion == "1.5") { + return 1; + } else if (verion == "2.0") { + return 2; + } else { + return - 1; + } +} + +void FQTermSSHSocket::connectToHost(const QString &host_name, quint16 port) { + ssh_socket_state_ = BeforeSession; + private_socket_->connectToHost(host_name, port); +} + +void FQTermSSHSocket::writeData() { + socketWriteBlock((const char*)packet_sender_->output_buffer_->data(), + packet_sender_->output_buffer_->len()); + private_socket_->flush(); +} + +void FQTermSSHSocket::handlePacket(int type) { + if (ssh_version_ == 1) { + switch (type) { + case SSH1_MSG_DISCONNECT: + char *reason; + reason = (char*)packet_receiver_->getString(); + FQ_TRACE("sshsocket", 1) << "Disconnect because: " << reason; + delete [] reason; + break; + default: + return ; + } + } else { + // ssh_version_ == 2; + switch (type) { + case SSH2_MSG_DISCONNECT: + char *reason; + packet_receiver_->consume(4); + reason = (char*)packet_receiver_->getString(); + FQ_TRACE("sshsocket", 1) << "Disconnect because: " << reason; + delete[] reason; + break; + default: + return ; + } + } +} + +unsigned long FQTermSSHSocket::bytesAvailable() { + return input_buffer_->len(); +} + +QByteArray FQTermSSHSocket::readBlock(unsigned long size) { + QByteArray data(size, 0); + input_buffer_->getRawData(data.data(), size); + return data; +} + +long FQTermSSHSocket::writeBlock(const QByteArray &data) { + if (!is_channel_ok_) return 0; + + unsigned long size = data.size(); + output_buffer_->putRawData(data.data(), size); + return size; +} + +void FQTermSSHSocket::flush() { + if (!is_channel_ok_) return; + + int size = output_buffer_->len(); + + ssh_channel_->sendData((const char *)output_buffer_->data(), size); + + output_buffer_->consume(size); +} + +void FQTermSSHSocket::close() { + private_socket_->close(); +} + +void FQTermSSHSocket::handleError(QString reason) { + close(); + + emit errorMessage(reason); + emit connectionClosed(); +} + +void FQTermSSHSocket::setProxy(int nProxyType, bool bAuth, + const QString &strProxyHost, + quint16 uProxyPort, + const QString &strProxyUsr, + const QString &strProxyPwd) { + private_socket_->setProxy(nProxyType, bAuth, strProxyHost, + uProxyPort, strProxyUsr, strProxyPwd); +} + +bool FQTermSSHSocket::setTermSize(int col, int row) { + if (ssh_channel_ && is_channel_ok_) + ssh_channel_->changeTermSize(col, row); + return true; +} +} // namespace FQTerm + +#include "fqterm_ssh_socket.moc" diff --git a/src/protocol/fqterm_ssh_socket.h b/src/protocol/fqterm_ssh_socket.h new file mode 100644 index 0000000..aa6fef4 --- /dev/null +++ b/src/protocol/fqterm_ssh_socket.h @@ -0,0 +1,131 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_SOCKET_H +#define FQTERM_SSH_SOCKET_H + +#include "fqterm_socket.h" + + +namespace FQTerm { + + +class FQTermSocketPrivate; + +class FQTermSSHPacketReceiver; + +class FQTermSSHPacketSender; + +class FQTermSSHBuffer; + +class FQTermSSHKex; + +class FQTermSSHAuth; + +class FQTermSSHChannel; + + +class FQTermSSHSocket: public FQTermSocket { + + Q_OBJECT; +private: + enum FQTermSSHSocketState { + + BeforeSession, SockSession + } ssh_socket_state_; + + FQTermSocketPrivate *private_socket_; + + + FQTermSSHBuffer *input_buffer_; + + FQTermSSHBuffer *output_buffer_; + + FQTermSSHBuffer *socket_buffer_; + + + FQTermSSHPacketReceiver *packet_receiver_; + + FQTermSSHPacketSender *packet_sender_; + + + FQTermSSHKex *key_exchanger_; + + FQTermSSHAuth *authentication_; + + FQTermSSHChannel *ssh_channel_; + + bool is_channel_ok_; + bool auth_ok_emitted_; + + QByteArray init_user_, init_passwd_; + + QString server_name_; + + int ssh_version_; + int col_; + int row_; + QString termtype_; + int chooseVersion(const QString &ver); + unsigned long socketWriteBlock(const char *data, unsigned long len); + void parsePacket(); + +private slots: + void handlePacket(int type); + void writeData(); + void kexOK(); + void authOK(); + void channelOK(); + void channelReadyRead(const char *data, int len); + void socketReadyRead(); + void handleError(QString); + +public: + FQTermSSHSocket(int col = 80, int row = 24, const QString& termtype = "vt100", const char *sshuser = NULL, const char *sshpasswd = NULL); + + ~FQTermSSHSocket(); + + + void setProxy(int nProxyType, //0-no proxy; 1-wingate; 2-sock4; 3-socks5 + bool bAuth, // if authentation needed + const QString &strProxyHost, quint16 uProxyPort, const QString &strProxyUsr, + const QString &strProxyPwd); + + void connectToHost(const QString &host_name, quint16 port); + + void init(int ssh_version); + + QByteArray readBlock(unsigned long size); + long writeBlock(const QByteArray &data); + + virtual bool readyForInput() {return is_channel_ok_;} + virtual bool setTermSize(int col, int row); + unsigned long bytesAvailable(); + + void flush(); + void close(); + +}; + +} // namespace FQTerm + + +#endif //FQTERM_SSH_SOCKET_H + diff --git a/src/protocol/internal/crc32.cpp b/src/protocol/internal/crc32.cpp new file mode 100644 index 0000000..2039ac8 --- /dev/null +++ b/src/protocol/internal/crc32.cpp @@ -0,0 +1,84 @@ +/* $OpenBSD: crc32.c,v 1.9 2003/02/12 21:39:50 markus Exp $ */ + +/* + * Copyright (c) 2003 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "crc32.h" + +namespace FQTerm { +static const u_int32_t crc32tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, + 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, + 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, + 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, + 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, + 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, + 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, + 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, + 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, + 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, + 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, + 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, + 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, + 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, + 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, + 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, + 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, + 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, + 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, + 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, + 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, + 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, + 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, + 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, + 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, + 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, + 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL +}; + +u_int32_t ssh_crc32(const u_char *buf, u_int32_t size) { + u_int32_t i, crc; + + crc = 0; + for (i = 0; i < size; i++) { + crc = crc32tab[(crc ^ buf[i]) &0xff] ^ (crc >> 8); + } return crc; +} + +} // namespace FQTerm diff --git a/src/protocol/internal/crc32.h b/src/protocol/internal/crc32.h new file mode 100644 index 0000000..ca95b89 --- /dev/null +++ b/src/protocol/internal/crc32.h @@ -0,0 +1,37 @@ +/* $OpenBSD: crc32.h,v 1.14 2003/02/12 21:39:50 markus Exp $ */ + +/* + * Copyright (c) 2003 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SSH_CRC32_H +#define SSH_CRC32_H +#include "fqterm_ssh_types.h" + +namespace FQTerm { + +u_int32_t ssh_crc32(const u_char *, u_int32_t); + +} // namespace FQTerm + +#endif diff --git a/src/protocol/internal/fqterm_serialization.h b/src/protocol/internal/fqterm_serialization.h new file mode 100644 index 0000000..7a858c0 --- /dev/null +++ b/src/protocol/internal/fqterm_serialization.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SERIALIZATION_H +#define FQTERM_SERIALIZATION_H + +#if defined(WIN32) +typedef unsigned __int16 u_int16_t; +#else +#include +#endif + +namespace FQTerm { + +inline u_int16_t ntohu16(const unsigned char *buf) { + return (buf[0] << 8) | buf[1]; +} + +inline u_int32_t ntohu32(const unsigned char *buf) { + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; +} + +inline void htonu32(unsigned char *buf, u_int32_t number) { + buf[0] = (number >> 24) & 0xFF; + buf[1] = (number >> 16) & 0xFF; + buf[2] = (number >> 8) & 0xFF; + buf[3] = number & 0xFF; +} + +inline void htonu16(unsigned char *buf, u_int16_t number) { + buf[0] = (number >> 8 & 0xFF); + buf[1] = (number & 0xFF); +} + +} // namespace FQTerm + +#endif // FQTERM_SERIALIZATION_H diff --git a/src/protocol/internal/fqterm_ssh1_packet.cpp b/src/protocol/internal/fqterm_ssh1_packet.cpp new file mode 100644 index 0000000..ded7fe4 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh1_packet.cpp @@ -0,0 +1,148 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_trace.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_ssh1_packet.h" +#include "fqterm_ssh_des.h" + +#include "fqterm_serialization.h" +#include "crc32.h" + +namespace FQTerm { +//============================================================================== +//FQTermSSH1PacketSender +//============================================================================== +//============================================================================== +// +// SSH1 Packet Structure: +// -------------------------------------------------------------------------- +// | length | padding | type | data | crc32 | +// -------------------------------------------------------------------------- +// | uint32 | 1-7bytes | uchar | | 4bytes| +// -------------------------------------------------------------------------- +// encrypt = padding + type + data + crc32 +// length = type + data + crc32 +// +//============================================================================== + +void FQTermSSH1PacketSender::makePacket() { + int len, padding, i; + u_int32_t rand_val = 0; + + delete output_buffer_; + + len = buffer_->len() + 4; //CRC32 + padding = 8-(len % 8); + + output_buffer_ = new FQTermSSHBuffer(len + padding + 4); //pktlen and crc32 + output_buffer_->putInt(len); + + for (i = 0; i < padding; i++) { + if (i % 4 == 0) { + rand_val = rand(); // FIXME: rand() doesn't range from 0 to 2^32. + } + + output_buffer_->putByte(rand_val &0xff); + rand_val >>= 8; + } + + output_buffer_->putRawData((const char*)buffer_->data(), buffer_->len()); + output_buffer_->putInt(ssh_crc32(output_buffer_->data() + 4, output_buffer_->len() - 4)); + + if (is_encrypt_) { + cipher_->encrypt(output_buffer_->data() + 4, output_buffer_->data() + 4, output_buffer_->len() - 4); + } + +} + +//============================================================================== +//FQTermSSH1PacketReceiver +//============================================================================== +void FQTermSSH1PacketReceiver::parseData(FQTermSSHBuffer *input) { + u_int mycrc, gotcrc; + u_char *buf = NULL; + u_char *targetData = NULL; + u_char *sourceData = NULL; + + // Get the length of the packet. + while (input->len() > 0) { + if (input->len() < 4) { + FQ_TRACE("ssh1packet", 3) << "The packet is too small."; + return ; + } + buf = input->data(); + real_data_len_ = ntohu32(buf); + + if (real_data_len_ > SSH_BUFFER_MAX) { + emit packetError(tr("parseData: The packet is too big")); + return ; + } + + u_int total_len = (real_data_len_ + 8) &~7; + u_int padding_len = total_len - real_data_len_; + + real_data_len_ -= 5; + buffer_->clear(); + + // Get the data of the packet. + if (input->len() - 4 < (long)total_len) { + FQ_TRACE("ssh1packet", 3) << "The packet is too small"; + return ; + } + + real_data_len_ = input->getInt() - 5; + targetData = new u_char[total_len]; + sourceData = new u_char[total_len]; + memset(targetData, 0, total_len); + memset(sourceData, 0, total_len); + + input->getRawData((char*)sourceData, total_len); + if (is_decrypt_) { + cipher_->decrypt(sourceData, targetData, total_len); + } else { + memcpy(targetData, sourceData, total_len); + } + + buffer_->putRawData((char*)targetData, total_len); + + // Check the crc32. + buf = buffer_->data() + total_len - 4; + mycrc = ntohu32(buf); + gotcrc = ssh_crc32(buffer_->data(), total_len - 4); + + if (mycrc != gotcrc) { + emit packetError(tr("parseData: bad CRC32")); + break; + } + + // Drop the padding. + buffer_->consume(padding_len); + + packet_type_ = buffer_->getByte(); + + emit packetAvaliable(packet_type_); + + delete [] sourceData; + delete [] targetData; + } +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh1_packet.h b/src/protocol/internal/fqterm_ssh1_packet.h new file mode 100644 index 0000000..a535635 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh1_packet.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH1_PACKET_H +#define FQTERM_SSH1_PACKET_H + +#include "fqterm_ssh_packet.h" + +namespace FQTerm { + +class FQTermSSH1PacketSender: public FQTermSSHPacketSender { +protected: + virtual void makePacket(); +}; + +class FQTermSSH1PacketReceiver: public FQTermSSHPacketReceiver { +public: + virtual void parseData(FQTermSSHBuffer *input); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH1_PACKET diff --git a/src/protocol/internal/fqterm_ssh2_kex.cpp b/src/protocol/internal/fqterm_ssh2_kex.cpp new file mode 100644 index 0000000..acae08d --- /dev/null +++ b/src/protocol/internal/fqterm_ssh2_kex.cpp @@ -0,0 +1,394 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "fqterm_ssh2_kex.h" +#include "fqterm_ssh_md5.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +static const int g = 2; +static const int q = 128; +static const unsigned char p[q]={ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +FQTermSSH2Kex::FQTermSSH2Kex(const char *V_C, const char *V_S) + : FQTermSSHKex(V_C, V_S) { + is_first_kex_ = true; + kex_state_ = FQTermSSH2Kex::BEFORE_KEXINIT; + + I_C_len_ = 0; + I_C_ = NULL; + I_S_len_ = 0; + I_S_ = NULL; + + bn_x_ = BN_new(); + bn_e_ = BN_new(); + bn_g_ = BN_new(); + bn_p_ = BN_new(); + ctx_ = BN_CTX_new(); + + bn_K_ = BN_new(); + bn_f_ = BN_new(); + + BN_set_word(bn_g_, g); + BN_bin2bn(p, q, bn_p_); + + session_id_ = NULL; +} + +FQTermSSH2Kex::~FQTermSSH2Kex() { + delete[] I_C_; + delete[] I_S_; + + BN_clear_free(bn_x_); + BN_clear_free(bn_e_); + BN_clear_free(bn_g_); + BN_clear_free(bn_p_); + BN_CTX_free(ctx_); + + BN_clear_free(bn_K_); + BN_clear_free(bn_f_); + + delete[] session_id_; +} + +void FQTermSSH2Kex::initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *packetSender) { + packet_receiver_ = packetReceiver; + packet_sender_ = packetSender; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), + this, SLOT(handlePacket(int)))); + kex_state_ = FQTermSSH2Kex::BEFORE_KEXINIT; + emit reKex(); +} + +void FQTermSSH2Kex::handlePacket(int type) { + switch (kex_state_) { + case FQTermSSH2Kex::BEFORE_KEXINIT: + negotiateAlgorithms(); + exchangeKey(); + kex_state_ = FQTermSSH2Kex::WAIT_REPLY; + break; + case FQTermSSH2Kex::WAIT_REPLY: + if (verifyKey()) { + sendNewKeys(); + kex_state_ = FQTermSSH2Kex::SESSIONKEY_SENT; + } else { + emit kexError(tr("Key exchange failed!")); + } + break; + case FQTermSSH2Kex::SESSIONKEY_SENT: + if (changeKeyAlg()) { + kex_state_ = FQTermSSH2Kex::KEYEX_OK; + emit kexOK(); + } + break; + case FQTermSSH2Kex::KEYEX_OK: + // TODO: how about Key Re-Exchange (see RFC 4253, 9. Key Re-Exchange) + break; + } +} + +void FQTermSSH2Kex::negotiateAlgorithms() { + FQ_FUNC_TRACE("ssh2kex", 10); + + if (packet_receiver_->packetType() != SSH2_MSG_KEXINIT) { + emit kexError(tr("startKex: First packet is not SSH_MSG_KEXINIT")); + return ; + } + + // 0. Backup the payload of this server packet. + I_S_len_ = packet_receiver_->packetDataLen() + 1; // add 1 bytes for packet type. + delete[] I_S_; + I_S_ = new char[I_S_len_]; + I_S_[0] = SSH2_MSG_KEXINIT; + memcpy(I_S_ + 1, packet_receiver_->buffer_->data(), I_S_len_ - 1); + + // 1. Parse server kex init packet + packet_receiver_->getRawData((char*)cookie_, 16); + + std::vector name_lists; + for (int i = 0; i < 10; ++i) { + int name_lists_len = packet_receiver_->getInt(); + if (name_lists_len > 0) { + name_lists.resize(name_lists_len); + packet_receiver_->getRawData(&name_lists[0], name_lists_len); + FQ_TRACE("ssh2kex", 5) << "Algorithms: " << QString::fromAscii(&name_lists[0], name_lists_len); + } else { + FQ_TRACE("ssh2kex", 5) << "None Algorithms"; + } + } + + bool first_kex_packet_follows = packet_receiver_->getByte(); + FQ_TRACE("ssh2kex", 5) << "first_kex_packet_follows: " << first_kex_packet_follows; + + packet_receiver_->consume(4); + + // 2. compose a kex init packet. + packet_sender_->startPacket(SSH2_MSG_KEXINIT); + packet_sender_->putRawData((const char*)cookie_, 16); // FIXME: generate new cookie_; + packet_sender_->putString("diffie-hellman-group1-sha1"); + packet_sender_->putString("ssh-rsa"); + packet_sender_->putString("3des-cbc"); + packet_sender_->putString("3des-cbc"); + packet_sender_->putString("hmac-sha1"); + packet_sender_->putString("hmac-sha1"); + packet_sender_->putString("none"); + packet_sender_->putString("none"); + packet_sender_->putString(""); + packet_sender_->putString(""); + + packet_sender_->putByte(false); + packet_sender_->putInt(0); + + // 3. backup the payload of this client packet. + I_C_len_ = packet_sender_->buffer_->len(); + delete[] I_C_; + I_C_ = new char[I_C_len_]; + memcpy(I_C_, packet_sender_->buffer_->data(), I_C_len_); + + // 4. send packet to server + packet_sender_->write(); +} + +void FQTermSSH2Kex::exchangeKey() { + BN_rand(bn_x_, q, 0, -1); + BN_mod_exp(bn_e_, bn_g_, bn_x_, bn_p_, ctx_); + + packet_sender_->startPacket(SSH2_MSG_KEXDH_INIT); + packet_sender_->putBN2(bn_e_); + packet_sender_->write(); +} + +static RSA *CreateRSAContext(unsigned char *host_key, int len); + +bool FQTermSSH2Kex::verifyKey() { + if (packet_receiver_->packetType() != SSH2_MSG_KEXDH_REPLY) { + emit kexError(tr("Expect a SSH_MSG_KEXDH_REPLY packet")); + return false; + } + + // Extract data + + int K_S_len = -1; + unsigned char *K_S = (unsigned char *)packet_receiver_->getString(&K_S_len); + + packet_receiver_->getBN2(bn_f_); + + int s_len = -1; + unsigned char *s = (unsigned char *)packet_receiver_->getString(&s_len); + + BN_mod_exp(bn_K_, bn_f_, bn_x_, bn_p_, ctx_); + + FQTermSSHBuffer *buffer = packet_sender_->output_buffer_; + + buffer->clear(); + buffer->putString(V_C_); + buffer->putString(V_S_); + buffer->putString(I_C_, I_C_len_); + buffer->putString(I_S_, I_S_len_); + buffer->putString((char *)K_S, K_S_len); + buffer->putSSH2BN(bn_e_); + buffer->putSSH2BN(bn_f_); + buffer->putSSH2BN(bn_K_); + + SHA1(buffer->data(), buffer->len(), H_); + + // Start verify + unsigned char s_H[SHA_DIGEST_LENGTH]; + SHA1(H_, SHA_DIGEST_LENGTH, s_H); + + // Ignore the first 15 bytes of the signature of H sent from server: + // algorithm_name_length[4], algorithm_name[7]("ssh-rsa") and signature_length[4]. + RSA *rsactx = CreateRSAContext(K_S, K_S_len); + int sig_len = s_len - 15; + unsigned char *sig = s + 15; + int res = RSA_verify(NID_sha1, s_H, SHA_DIGEST_LENGTH, + sig, sig_len, rsactx); + + RSA_free(rsactx); + + delete K_S; + delete s; + + return res == 1; +} + +static RSA *CreateRSAContext(unsigned char *host_key, int len) { + FQTermSSHBuffer buffer(len); + + buffer.putRawData((char *)host_key, len); + + int algo_len = -1; + unsigned char *algo = (unsigned char *)buffer.getString(&algo_len); + + FQ_VERIFY(std::string("ssh-rsa") == std::string((char *)algo)); + + int e_len = -1; + unsigned char *e = (unsigned char *)buffer.getString(&e_len); + + int n_len = -1; + unsigned char *n = (unsigned char *)buffer.getString(&n_len); + + + RSA *rsa = RSA_new(); + rsa->e = BN_new(); + BN_bin2bn(e, e_len, rsa->e); + + rsa->n = BN_new(); + BN_bin2bn(n, n_len, rsa->n); + + delete[] algo; + delete[] e; + delete[] n; + + return rsa; +} + +void FQTermSSH2Kex::sendNewKeys(){ + packet_sender_->startPacket(SSH2_MSG_NEWKEYS); + packet_sender_->write(); +} + +bool FQTermSSH2Kex::changeKeyAlg() { + if (packet_receiver_->packetType() != SSH2_MSG_NEWKEYS) { + emit kexError(tr("Expect a SSH_MSG_NEWKEYS packet")); + return false; + } + + if (session_id_ == NULL) { + session_id_ = new unsigned char[SHA_DIGEST_LENGTH]; + memcpy(session_id_, H_, SHA_DIGEST_LENGTH); + } + + packet_sender_->setEncryptionType(SSH_CIPHER_3DES); + packet_receiver_->setEncryptionType(SSH_CIPHER_3DES); + + packet_sender_->setMacType(FQTERM_SSH_HMAC_SHA1); + packet_receiver_->setMacType(FQTERM_SSH_HMAC_SHA1); + + // From RFC 4253 section 7.2: + // Initial IV client to server: HASH(K || H || "A" || session_id) + // (Here K is encoded as mpint and "A" as byte and session_id as raw + // data. "A" means the single character A, ASCII 65). + // + // Initial IV server to client: HASH(K || H || "B" || session_id) + // + // Encryption key client to server: HASH(K || H || "C" || session_id) + // + // Encryption key server to client: HASH(K || H || "D" || session_id) + // + // Integrity key client to server: HASH(K || H || "E" || session_id) + // + // Integrity key server to client: HASH(K || H || "F" || session_id) + + int IV_c2s_len = packet_sender_->getIVSize(); + unsigned char *IV_c2s = computeKey(IV_c2s_len, 'A'); + + int IV_s2c_len = packet_receiver_->getIVSize(); + unsigned char *IV_s2c = computeKey(IV_s2c_len, 'B'); + + int key_c2s_len = packet_sender_->getKeySize(); + unsigned char *key_c2s = computeKey(key_c2s_len, 'C'); + + int key_s2c_len = packet_receiver_->getKeySize(); + unsigned char *key_s2c = computeKey(key_s2c_len, 'D'); + + int mac_key_c2s_len = packet_sender_->getMacKeySize(); + unsigned char *mac_key_c2s = computeKey(mac_key_c2s_len, 'E'); + + int mac_key_s2c_len = packet_receiver_->getMacKeySize(); + unsigned char *mac_key_s2c = computeKey(mac_key_s2c_len, 'F'); + + + packet_sender_->startEncryption(key_c2s, IV_c2s); + packet_sender_->startMac(mac_key_c2s); + + packet_receiver_->startEncryption(key_s2c, IV_s2c); + packet_receiver_->startMac(mac_key_s2c); + + + delete[] IV_c2s; + delete[] IV_s2c; + delete[] key_c2s; + delete[] key_s2c; + delete[] mac_key_c2s; + delete[] mac_key_s2c; + + return true; +} + +unsigned char *FQTermSSH2Kex::computeKey(int expected_len, char flag) { + unsigned char *key = new unsigned char[expected_len + SHA_DIGEST_LENGTH]; + + int len = 0; + SHA_CTX hash; + + FQTermSSHBuffer K(BN_num_bytes(bn_K_) + 5); + K.putSSH2BN(bn_K_); + + while (len < expected_len) { + SHA1_Init(&hash); + SHA1_Update(&hash, K.data(), K.len()); + SHA1_Update(&hash, H_, SHA_DIGEST_LENGTH); + + if (len == 0) { + SHA1_Update(&hash, &flag, 1); + SHA1_Update(&hash, session_id_, SHA_DIGEST_LENGTH); + } else { + SHA1_Update(&hash, key, len); + } + + SHA1_Final(key + len, &hash); + len += SHA_DIGEST_LENGTH; + } + + return key; +} + +} // namespace FQTerm + +#include "fqterm_ssh2_kex.moc" diff --git a/src/protocol/internal/fqterm_ssh2_kex.h b/src/protocol/internal/fqterm_ssh2_kex.h new file mode 100644 index 0000000..671e094 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh2_kex.h @@ -0,0 +1,105 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH2_KEX_H +#define FQTERM_SSH2_KEX_H + +#include + +#include "fqterm_ssh_kex.h" + +namespace FQTerm { + +class FQTermSSHPacketReceiver; +class FQTermSSHPacketSender; + +class FQTermSSH2Kex: public FQTermSSHKex { + Q_OBJECT; +private: + enum FQTermSSH2KexState { + BEFORE_KEXINIT, WAIT_REPLY, SESSIONKEY_SENT, KEYEX_OK + } kex_state_; + + /* + string V_C, the client's identification string (CR and LF + excluded) + string V_S, the server's identification string (CR and LF + excluded) + string I_C, the payload of the client's SSH_MSG_KEXINIT + string I_S, the payload of the server's SSH_MSG_KEXINIT + string K_S, the host key + mpint e, exchange value sent by the client + mpint f, exchange value sent by the server + mpint K, the shared secret + */ + + int I_C_len_; + char *I_C_; + int I_S_len_; + char *I_S_; + + BIGNUM *bn_x_; + BIGNUM *bn_e_; + BIGNUM *bn_g_; + BIGNUM *bn_p_; + BN_CTX *ctx_; + + BIGNUM *bn_K_; + BIGNUM *bn_f_; + + unsigned char H_[SHA_DIGEST_LENGTH]; + + unsigned char *session_id_; + + + + + bool is_first_kex_; + + FQTermSSHRSA *host_key_; + FQTermSSHRSA *server_key_; + + u_char cookie_[16]; + int server_flag_, ciphers_, auth_; +// u_char session_id_[16]; + u_char session_key_[32]; + + void negotiateAlgorithms(); + void exchangeKey(); + bool verifyKey(); + void sendNewKeys(); + bool changeKeyAlg(); + + unsigned char *computeKey(int len, char flag); + +public: + FQTermSSH2Kex(const char *V_C, const char *V_S); + ~FQTermSSH2Kex(); + + virtual void initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *outputSender); + +public slots: + void handlePacket(int type); +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH2_KEX_H diff --git a/src/protocol/internal/fqterm_ssh2_packet.cpp b/src/protocol/internal/fqterm_ssh2_packet.cpp new file mode 100644 index 0000000..d3094d3 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh2_packet.cpp @@ -0,0 +1,267 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_trace.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_ssh2_packet.h" +#include "fqterm_ssh_des.h" + +#include "fqterm_serialization.h" +#include "crc32.h" + +namespace FQTerm { +//============================================================================== +//FQTermSSH2PacketSender +//============================================================================== +// SSH2 Packet Structure: +// uint32 packet_length +// byte padding_length +// byte[n1] payload; n1 = packet_length - padding_length - 1 +// byte[n2] random padding; n2 = padding_length +// byte[m] mac (Message Authentication Code - MAC); m = mac_length +//============================================================================== + +void FQTermSSH2PacketSender::makePacket() { + FQ_TRACE("ssh2packet", 9) << "----------------------------Send " + << (is_encrypt_ ? "Encrypted": "plain") + << " Packet---->>>>>>>"; + + // 0. compress + if (is_compressed_) { + FQ_VERIFY(false); + } + + // 1. compute the padding length for padding. + int non_padding_len = 4 + 1 + buffer_->len(); + + int padding_block_len = 8; + if (is_encrypt_ && cipher_->blockSize() > padding_block_len) { + padding_block_len = cipher_->blockSize(); + } + + int padding_len = padding_block_len - (non_padding_len % padding_block_len); + if (padding_len < 4) { + padding_len += padding_block_len; + } + + // 2. renew the output buffer. + int total_len = non_padding_len + padding_len; + if (is_mac_) { + total_len += mac_->digestSize(); + } + + delete output_buffer_; + output_buffer_ = new FQTermSSHBuffer(total_len); + + // 3. Fill the output buffer. + int packet_len = 1 + buffer_->len() + padding_len; + + output_buffer_->putInt(packet_len); + output_buffer_->putByte(padding_len); + output_buffer_->putRawData((const char*)buffer_->data(), buffer_->len()); + + u_int32_t rand_val = 0; + for (int i = 0; i < padding_len; i++) { + if (i % 4 == 0) { + rand_val = rand(); // FIXME: rand() doesn't range from 0 to 2^32. + } + output_buffer_->putByte(rand_val & 0xff); + rand_val >>= 8; + } + + // 4. Add MAC on the entire unencrypted packet, + // including two length fields, 'payload' and 'random padding'. + if (is_mac_) { + const unsigned char *packet = output_buffer_->data(); + int len = output_buffer_->len(); + + FQTermSSHBuffer buffer(4 + len); + buffer.putInt(sequence_no_); + buffer.putRawData((const char *)packet, len); + + std::vector digest(mac_->digestSize()); + mac_->getDigest(buffer.data(), buffer.len(), &digest[0]); + + FQ_TRACE("ssh2packet", 9) << "Making packets..."; + FQ_TRACE("ssh2packet", 9) << "Append MAC with sequence_no_" << sequence_no_; + FQ_TRACE("ssh2packet", 9) << "Compute MAC with " + << buffer.len() << " bytes data:\n" + << dumpHexString << std::string((char *)buffer.data(), buffer.len()); + FQ_TRACE("ssh2packet", 9) << "MAC data " + << digest.size() << " bytes:\n" + << dumpHexString << std::string((const char *)&digest[0], digest.size()); + + output_buffer_->putRawData((const char *)&digest[0], digest.size()); + } + + if (is_compressed_) { + FQ_VERIFY(false); + } + + if (is_encrypt_) { + // as RFC 4253: + // When encryption is in effect, the packet length, padding + // length, payload, and padding fields of each packet MUST be encrypted + // with the given algorithm. + + u_char *data = output_buffer_->data(); + int len = output_buffer_->len() - mac_->digestSize(); + + FQ_TRACE("ssh2packet", 9) << "An packet (without MAC) to be encrypted:" + << len << " bytes:\n" + << dumpHexString << std::string((const char *)data, len); + + cipher_->encrypt(data, data, len); + + FQ_TRACE("ssh2packet", 9) << "An encrypted packet (without MAC) made:" + << len << " bytes:\n" + << dumpHexString << std::string((const char *)data, len); + } + + ++sequence_no_; +} + +void FQTermSSH2PacketSender::setEncryptionType(int cipherType) { + cipher_type_ = cipherType; + + delete cipher_; + cipher_ = NULL; + + switch (cipher_type_) { + case SSH_CIPHER_3DES: + cipher_ = new FQTermSSH2TripleDESCBC; + break; + } +} + + +//============================================================================== +//FQTermSSH2PacketReceiver +//============================================================================== +void FQTermSSH2PacketReceiver::parseData(FQTermSSHBuffer *input) { + FQ_TRACE("ssh2packet", 9) << "----------------------------Receive " + << (is_decrypt_ ? "Encrypted": "plain") + << " Packet----<<<<<<<"; + while (input->len() > 0) { + // 1. Check the ssh packet + if (input->len() < 16 + || (is_decrypt_ && input->len() < cipher_->blockSize()) + || input->len() < last_expected_input_length_ + ) { + FQ_TRACE("ssh2packet", 3) + << "Got an incomplete packet. Wait for more data."; + return ; + } + + if (last_expected_input_length_ == 0) { + if (is_decrypt_) { + // decrypte the first block to get the packet_length field. + cipher_->decrypt(input->data(), input->data(), cipher_->blockSize()); + } + } else { + // last_expected_input_length_ != 0 + // indicates an incomplete ssh2 packet received last time, + // the first block of data is already decrypted at that time, + // so it must not be decrypted again. + } + + int packet_len = ntohu32(input->data()); + + if (packet_len > SSH_BUFFER_MAX) { + emit packetError(tr("parseData: packet too big")); + return ; + } + + int expected_input_len = 4 + packet_len + (is_mac_ ? mac_->digestSize() : 0); + + if (input->len() < (long)expected_input_len) { + FQ_TRACE("ssh2packet", 3) + << "The packet is too small. Wait for more data."; + last_expected_input_length_ = expected_input_len; + return ; + } else { + last_expected_input_length_ = 0; + } + + // 2. decrypte data. + if (is_decrypt_) { + // decrypte blocks left. + unsigned char *tmp = input->data() + cipher_->blockSize(); + int left_len = expected_input_len - cipher_->blockSize() - mac_->digestSize(); + cipher_->decrypt(tmp, tmp, left_len); + } + + // 3. check MAC + if (is_mac_) { + int digest_len = mac_->digestSize(); + std::vector digest(digest_len); + mac_->getDigest(input->data(), expected_input_len - digest_len, &digest[0]); + + u_char *received_digest = input->data() + expected_input_len - digest_len; + + if (memcmp(&digest[0], received_digest, digest_len) == 0) { + FQ_TRACE("ssh2packet", 0) << "incorrect MAC."; + return ; + } + } + + // 4. get every field of the ssh packet. + packet_len = input->getInt(); + + std::vector data(packet_len); + + input->getRawData((char*)&data[0], packet_len); + if (is_mac_) { + input->consume(mac_->digestSize()); + } + + int padding_len = data[0]; + + real_data_len_ = packet_len - 1 - padding_len; + + buffer_->clear(); + buffer_->putRawData((char*)&data[0] + 1, real_data_len_); + + FQ_TRACE("ssh2packet", 9) << "Receive " << real_data_len_ << " bytes payload:\n" + << dumpHexString << std::string((char *)&data[0] + 1, real_data_len_); + + // 5. notify others a ssh packet is parsed successfully. + packet_type_ = buffer_->getByte(); + real_data_len_ -= 1; + emit packetAvaliable(packet_type_); + + ++sequence_no_; + } +} + +void FQTermSSH2PacketReceiver::setEncryptionType(int cipherType) { + cipher_type_ = cipherType; + + delete cipher_; + cipher_ = NULL; + + switch (cipher_type_) { + case SSH_CIPHER_3DES: + cipher_ = new FQTermSSH2TripleDESCBC; + break; + } +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh2_packet.h b/src/protocol/internal/fqterm_ssh2_packet.h new file mode 100644 index 0000000..c460984 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh2_packet.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH2_PACKET_H +#define FQTERM_SSH2_PACKET_H + +#include "fqterm_ssh_packet.h" + +namespace FQTerm { + +class FQTermSSH2PacketSender: public FQTermSSHPacketSender { + protected: + virtual void makePacket(); + + public: + virtual void setEncryptionType(int cipherType); +}; + +class FQTermSSH2PacketReceiver: public FQTermSSHPacketReceiver { + private: + // greater than 0 if last time an incomplete ssh2 packet received. + int last_expected_input_length_; + public: + FQTermSSH2PacketReceiver() + : last_expected_input_length_(0) { + } + + virtual void parseData(FQTermSSHBuffer *input); + virtual void setEncryptionType(int cipherType); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH2_PACKET diff --git a/src/protocol/internal/fqterm_ssh_auth.cpp b/src/protocol/internal/fqterm_ssh_auth.cpp new file mode 100644 index 0000000..d063d14 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_auth.cpp @@ -0,0 +1,223 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#include "fqterm_ssh_auth.h" +#include "fqterm_ssh_packet.h" +#include "fqterm_ssh_const.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +//============================================================================== +//FQTermSSH1PasswdAuth +//============================================================================== + +FQTermSSH1PasswdAuth::FQTermSSH1PasswdAuth(const char *sshuser, + const char *sshpasswd) + : FQTermSSHPasswdAuth(sshuser, sshpasswd) { + is_tried_ = false; + ssh_pw_auth_state_ = FQTermSSH1PasswdAuth::BEFORE_AUTH; +} + +void FQTermSSH1PasswdAuth::initAuth(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output) { + packet_receiver_ = packet; + packet_sender_ = output; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), + this, SLOT(handlePacket(int)))); + packet_sender_->startPacket(SSH1_CMSG_USER); + user_name_.clear(); + passwd_.clear(); + + if (!default_user_.isEmpty() && !default_passwd_.isEmpty()) { + user_name_ = default_user_; + passwd_ = default_passwd_; + } + + while (user_name_.isEmpty()) { + bool isOK = false; + emit requestUserPwd(&user_name_, &passwd_, &isOK); + // SSHLoginDialog login(&d_user, &d_passwd); + if (!isOK) { + emit authError(tr("UserCancel")); + return ; + } + } + + packet_sender_->putString(user_name_.toLatin1()); + packet_sender_->write(); + ssh_pw_auth_state_ = USER_SENT; + is_tried_ = false; +} + +void FQTermSSH1PasswdAuth::handlePacket(int type) { + switch (ssh_pw_auth_state_) { + case BEFORE_AUTH: + FQ_TRACE("sshauth", 0) << "Auth: We should not be here."; + break; + case USER_SENT: + if (type == SSH1_SMSG_SUCCESS) { + ssh_pw_auth_state_ = AUTH_OK; + emit authOK(); + break; + } + if (type != SSH1_SMSG_FAILURE) { + emit authError(tr("Strange response from server")); + break; + } + if (is_tried_) { + bool isOK = false; + emit requestUserPwd(&user_name_, &passwd_, &isOK); + // SSHLoginDialog login(&d_user, &d_passwd); + if (!isOK) { + emit authError(tr("User canceled")); + break; + } + is_tried_ = false; + } + packet_sender_->startPacket(SSH1_CMSG_AUTH_PASSWORD); + packet_sender_->putString(passwd_.toLatin1()); + packet_sender_->write(); + is_tried_ = true; + break; + case AUTH_OK: + break; + default: + return ; + } +} + +//============================================================================== +//FQTermSSH2PasswdAuth +//============================================================================== + +FQTermSSH2PasswdAuth::FQTermSSH2PasswdAuth(const char *sshuser, + const char *sshpasswd) + : FQTermSSHPasswdAuth(sshuser, sshpasswd) { + is_tried_ = false; + ssh_pw_auth_state_ = FQTermSSH2PasswdAuth::SERVICE_ACCEPTED; +} + +void FQTermSSH2PasswdAuth::initAuth(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output) { + packet_receiver_ = packet; + packet_sender_ = output; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), + this, SLOT(handlePacket(int)))); + + packet_sender_->startPacket(SSH2_MSG_SERVICE_REQUEST); + packet_sender_->putString("ssh-userauth"); + packet_sender_->write(); + + ssh_pw_auth_state_ = FQTermSSH2PasswdAuth::SERVICE_ACCEPTED; +} + +void FQTermSSH2PasswdAuth::handlePacket(int type) { + switch (ssh_pw_auth_state_) { + case FQTermSSH2PasswdAuth::SERVICE_ACCEPTED: + sendUserPasswd(); + ssh_pw_auth_state_ = FQTermSSH2PasswdAuth::USER_PASSWD_SENT; + break; + case FQTermSSH2PasswdAuth::USER_PASSWD_SENT: + if (check()) { + FQ_TRACE("ssh2passwdauth", 3) << "Auth OK."; + + emit authOK(); + ssh_pw_auth_state_ = FQTermSSH2PasswdAuth::AUTH_OK; + } + break; + case FQTermSSH2PasswdAuth::AUTH_OK: + break; + default: + return ; + } +} + +bool FQTermSSH2PasswdAuth::check() { + switch(packet_receiver_->packetType()) { + case SSH2_MSG_USERAUTH_SUCCESS: + return true; + break; + case SSH2_MSG_USERAUTH_BANNER: + // TODO: just ignore banner messages. + break; + case SSH2_MSG_USERAUTH_FAILURE: + emit authError(tr("Authentication failed!")); + break; + default: + emit authError(tr("Unexpected packet")); + } + + return false; +} + +void FQTermSSH2PasswdAuth::sendUserPasswd() { + if (packet_receiver_->packetType() != SSH2_MSG_SERVICE_ACCEPT) { + emit authError(tr("Expect a SSH2_MSG_SERVICE_ACCEPT packet")); + return; + } + + u_char *service_name = (u_char *)packet_receiver_->getString(); + + if (std::string((char *)service_name) != std::string("ssh-userauth")) { + emit authError(tr("Error when sending username and password.")); + return; + } + + delete[] service_name; + + // byte SSH_MSG_USERAUTH_REQUEST + // string user name in ISO-10646 UTF-8 encoding [RFC3629] + // string service name in US-ASCII + // string method name in US-ASCII + // .... method specific fields + user_name_.clear(); + passwd_.clear(); + + if (!default_user_.isEmpty() && !default_passwd_.isEmpty()) { + user_name_ = default_user_; + passwd_ = default_passwd_; + } + + while (user_name_.isEmpty()) { + bool isOK = false; + emit requestUserPwd(&user_name_, &passwd_, &isOK); + if (!isOK) { + emit authError(tr("UserCancel")); + return ; + } + } + + packet_sender_->startPacket(SSH2_MSG_USERAUTH_REQUEST); + packet_sender_->putString(user_name_.toLatin1()); + packet_sender_->putString("ssh-connection"); + packet_sender_->putString("password"); + packet_sender_->putByte(false); + packet_sender_->putString(passwd_.toLatin1()); + packet_sender_->write(); +} + +} // namespace FQTerm + +#include diff --git a/src/protocol/internal/fqterm_ssh_auth.h b/src/protocol/internal/fqterm_ssh_auth.h new file mode 100644 index 0000000..6152a71 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_auth.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_AUTH_H +#define FQTERM_SSH_AUTH_H + +#include + +class QString; + +namespace FQTerm { + +class FQTermSSHPacketReceiver; +class FQTermSSHPacketSender; + +class FQTermSSHAuth: public QObject { + + Q_OBJECT; +protected: + QString user_name_; + FQTermSSHPacketReceiver *packet_receiver_; + FQTermSSHPacketSender *packet_sender_; + +public: + FQTermSSHAuth(const char *sshuser = NULL) + : user_name_(sshuser) { + } + + ~FQTermSSHAuth() {} + + virtual void initAuth(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output) = 0; +public slots: + virtual void handlePacket(int type) = 0; + +signals: + void requestUserPwd(QString *user, QString *pwd, bool *isOK); + void authOK(); + void authError(QString); +}; + +class FQTermSSHPasswdAuth: public FQTermSSHAuth { + Q_OBJECT; +protected: + QString passwd_; + bool is_tried_; + + QString default_user_; + QString default_passwd_; + +public: + FQTermSSHPasswdAuth(const char *sshuser, const char *sshpasswd) + : FQTermSSHAuth(sshuser), + passwd_(sshpasswd), + default_user_(sshuser), + default_passwd_(sshpasswd) { + } +}; + +class FQTermSSH1PasswdAuth: public FQTermSSHPasswdAuth { + Q_OBJECT; +private: + enum FQTermSSH1PasswdAuthState { + BEFORE_AUTH, USER_SENT, PASS_SENT, AUTH_OK + } ssh_pw_auth_state_; + +public: + FQTermSSH1PasswdAuth(const char *sshuser, const char *sshpasswd); + +public slots: + void handlePacket(int type); + void initAuth(FQTermSSHPacketReceiver *packet, FQTermSSHPacketSender *output); +}; + +class FQTermSSH2PasswdAuth: public FQTermSSHPasswdAuth { + Q_OBJECT; +private: + enum FQTermSSH2PasswdAuthState { + SERVICE_ACCEPTED, USER_PASSWD_SENT, PASS_SENT, AUTH_OK + } ssh_pw_auth_state_; + + void sendUserPasswd(); + bool check(); + +public: + FQTermSSH2PasswdAuth(const char *sshuser, const char *sshpasswd); + +public slots: + void handlePacket(int type); + void initAuth(FQTermSSHPacketReceiver *packet, FQTermSSHPacketSender *output); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_AUTH_H diff --git a/src/protocol/internal/fqterm_ssh_buffer.cpp b/src/protocol/internal/fqterm_ssh_buffer.cpp new file mode 100644 index 0000000..d95497a --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_buffer.cpp @@ -0,0 +1,302 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include + +#include "fqterm_trace.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_serialization.h" + +namespace FQTerm { +//============================================================================== +// FQTermSSHBuffer +//============================================================================== + +FQTermSSHBuffer::FQTermSSHBuffer(int size) { + alloc_size_ = size; + buffer_size_ = 0; + offset_ = 0; + buffer_ = new u_char[alloc_size_]; +} + +FQTermSSHBuffer::~FQTermSSHBuffer() { + delete [] buffer_; + offset_ = 0; + buffer_size_ = 0; + alloc_size_ = 0; +} + +void FQTermSSHBuffer::ensure(int len) { + if (len <= (alloc_size_ - (offset_ + buffer_size_))) { + return ; + } else { + alloc_size_ = buffer_size_ + len; + rebuffer(); + } +} + +void FQTermSSHBuffer::rebuffer() { + u_char *newBuffer; + newBuffer = new u_char[alloc_size_]; + memset(newBuffer, 0, alloc_size_); + memcpy(newBuffer, buffer_ + offset_, buffer_size_); + delete [] buffer_; + buffer_ = newBuffer; + offset_ = 0; +} + +void FQTermSSHBuffer::clear() { + memset(buffer_, 0, alloc_size_); + offset_ = 0; + buffer_size_ = 0; +} + +void FQTermSSHBuffer::consume(int len) { + if (len > buffer_size_) { + len = buffer_size_; + } + + offset_ += len; + buffer_size_ -= len; +} + +void FQTermSSHBuffer::putRawData(const char *data, int len) { + if (len < 0) { + FQ_TRACE("sshbuffer", 0) << "Write data error."; + } + + ensure(len); + memcpy((buffer_ + offset_ + buffer_size_), data, len); + buffer_size_ += len; +} + +void FQTermSSHBuffer::getRawData(char *data, int len) { + if (len <= buffer_size_ && len >= 0) { + memcpy(data, buffer_ + offset_, len); + consume(len); + } else { + FQ_TRACE("sshbuffer", 0) << "Read too many data: " << len << " bytes."; + } +} + +//============================================================================== +// Store an BIGNUM in the buffer with a 2-byte msb first bit count, followed by +// (bits+7)/8 bytes of binary data, msb first. +//============================================================================== + +void FQTermSSHBuffer::putSSH1BN(BIGNUM *bignum) { + int bits = BN_num_bits(bignum); + int bin_size = (bits + 7) / 8; + u_char *buf = new u_char[bin_size]; + int oi; + u_char msg[2]; + + // Get the value of in binary + oi = BN_bn2bin(bignum, buf); + if (oi != bin_size) { + FQ_TRACE("sshbuffer", 0) << "BN_bn2bin() failed: oi = " << oi + << " != bin_size." << bin_size; + } + + // Store the number of bits in the buffer in two bytes, msb first + htonu16(msg, bits); + putRawData((char*)msg, 2); + // Store the binary data. + putRawData((char*)buf, oi); + + memset(buf, 0, bin_size); + delete [] buf; +} + + + +void FQTermSSHBuffer::putSSH2BN(BIGNUM *bignum) { + // FIXME: support negative number and add error handling. + + FQ_VERIFY(!bignum->neg); // currently we don't support negative big number. + + if (BN_is_zero(bignum)) { + this->putInt(0); + } else { + u_int bytes = BN_num_bytes(bignum) + 1; + + FQ_VERIFY(bytes >= 2); // currently we don't support big numbers so small + + std::vector buf(bytes); + buf[0] = 0; + + int bin_len = BN_bn2bin(bignum, &buf[0] + 1); + + FQ_VERIFY(bin_len == (int)bytes - 1); + + u_int no_high_bit = (buf[1] & 0x80) ? 0 : 1; + + this->putInt(bytes - no_high_bit); + this->putRawData((const char *)&buf[0] + no_high_bit, bytes - no_high_bit); + } +} + +//============================================================================== +// Retrieves a BIGNUM from the buffer. +//============================================================================== + +void FQTermSSHBuffer::getSSH1BN(BIGNUM *bignum) { + int bits, bytes; + u_char buf[2]; + u_char *bin; + + // Get the number for bits. + getRawData((char*)buf, 2); + bits = ntohu16(buf); + // Compute the number of binary bytes that follow. + bytes = (bits + 7) / 8; + if (bytes > 8 *1024) { + FQ_TRACE("sshbuffer", 0) << "Can't handle BN of size " << bytes; + return ; + } + if (len() < bytes) { + FQ_TRACE("sshbuffer", 0) << "The input buffer is too small."; + return ; + } + bin = data(); + BN_bin2bn(bin, bytes, bignum); + consume(bytes); +} + +void FQTermSSHBuffer::getSSH2BN(BIGNUM *bignum) { + // FIXME: support negative numbers and error handling + int len; + unsigned char *hex_data = (unsigned char *)getString(&len); + + FQ_VERIFY(!(len > 0 && (hex_data[0] & 0x80))); // don't support negative numbers. + + FQ_VERIFY(len < 10240); // don't support so large numbers. + + BIGNUM *res = BN_bin2bn(hex_data, len, bignum); + + FQ_VERIFY(res != NULL); + + delete hex_data; +} + +u_short FQTermSSHBuffer::getWord() { + u_char buf[2]; + u_short data; + + getRawData((char*)buf, 2); + data = ntohu16(buf); + return data; +} + +void FQTermSSHBuffer::putWord(u_short data) { + u_char buf[2]; + + htonu16(buf, data); + putRawData((char*)buf, 2); +} + +u_int FQTermSSHBuffer::getInt() { + u_char buf[4]; + u_int data; + getRawData((char*)buf, 4); + data = ntohu32(buf); + return data; +} + +void FQTermSSHBuffer::putInt(u_int data) { + u_char buf[4]; + + htonu32(buf, data); + putRawData((char*)buf, 4); +} + +//============================================================================== +// Return a character from the buffer (0-255). +//============================================================================== + +u_char FQTermSSHBuffer::getByte() { + u_char ch; + + getRawData((char*) &ch, 1); + return ch; +} + +//============================================================================== +// Stores a character in the buffer. +//============================================================================== + +void FQTermSSHBuffer::putByte(int data) { + u_char ch = data; + + putRawData((char*) &ch, 1); +} + +//============================================================================== +// Stores an arbitrary binary string in the buffer. +//============================================================================== + +void FQTermSSHBuffer::putString(const char *str, int len) { + if (str == NULL) { + FQ_TRACE("sshbuffer", 0) << "Can't put a null pointer string."; + return ; + } + + if (len < 0) { + len = strlen(str); + } + + putInt(len); + putRawData(str, len); +} + +//============================================================================== +// Return an arbitrary binary string from the buffer. The string cannot be +// longer than 256k. The returned value points to memory allocated with new; +// It is the responsibility of the calling function to free the data. +//============================================================================== + +void *FQTermSSHBuffer::getString(int *length) { + u_char *data; + u_int len; + + // Get the length. + len = getInt(); + if ((long)len > buffer_size_) { + FQ_TRACE("sshbuffer", 0) + << "String length " << len + << " is greater than buffer size " << buffer_size_; + return 0; + } + // Allocate space for the string. Add one byte for a null character. + data = new u_char[len + 1]; + // Get the string. + getRawData((char*)data, len); + // Append a null character to make processing easier. + data[len] = 0; + if (length != NULL) { + *length = len; + } + // return the length of the string. + return data; +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_buffer.h b/src/protocol/internal/fqterm_ssh_buffer.h new file mode 100644 index 0000000..e06872f --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_buffer.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_BUFFER_H +#define FQTERM_SSH_BUFFER_H + +#include +#include + +#include "fqterm_ssh_types.h" + +namespace FQTerm { + +#define SSH_BUFFER_MAX 10000000 + +class FQTermSSHBuffer { + private: + u_char *buffer_; + int offset_; + int buffer_size_; + int alloc_size_; + + void ensure(int len); + void rebuffer(); + + public: + FQTermSSHBuffer(int size); + ~FQTermSSHBuffer(); + + u_char *data() const { + return buffer_ + offset_; + } + + int len() const { + return buffer_size_; + } + + void consume(int len); + + void clear(); + + void putRawData(const char *data, int len); + void getRawData(char *data, int len); + + void putSSH1BN(BIGNUM *bignum); + void getSSH1BN(BIGNUM *bignum); + + void putSSH2BN(BIGNUM *bignum); + void getSSH2BN(BIGNUM *bignum); + + void putInt(u_int data); + u_int getInt(); + + void putWord(u_short data); + u_short getWord(); + + void putByte(int data); + u_char getByte(); + + void putString(const char *str, int len = -1); + void *getString(int *length = NULL); +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH_BUFFER diff --git a/src/protocol/internal/fqterm_ssh_channel.cpp b/src/protocol/internal/fqterm_ssh_channel.cpp new file mode 100644 index 0000000..38a755a --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_channel.cpp @@ -0,0 +1,439 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_ssh_channel.h" +#include "fqterm_ssh_const.h" +#include "fqterm_ssh_packet.h" +#include "fqterm_trace.h" +#include +namespace FQTerm { + +//============================================================================== +//FQTermSSH1Channel +//============================================================================== + +FQTermSSH1Channel::FQTermSSH1Channel() + : FQTermSSHChannel() { + service_state_ = FQTermSSH1Channel::BEGIN_SERVICE; +} + +void FQTermSSH1Channel::initChannel(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output, + int col, int row, const QString& termtype) { + packet_receiver_ = packet; + packet_sender_ = output; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), this, SLOT(handlePacket(int)))); + packet_sender_->startPacket(SSH1_CMSG_REQUEST_PTY); + // pty request is of no use in BBS, but we do this + packet_sender_->putString(termtype.toLatin1()); + packet_sender_->putInt(row); // FIXME: hardcoded term size. + packet_sender_->putInt(col); + packet_sender_->putInt(0); + packet_sender_->putInt(0); + packet_sender_->putByte(0); + packet_sender_->write(); + service_state_ = FQTermSSH1Channel::REQPTY_SENT; + + is_closed_ = false; +} + +void FQTermSSH1Channel::changeTermSize(int col, int row) { + packet_sender_->startPacket(SSH1_CMSG_WINDOW_SIZE); + packet_sender_->putInt(row); + packet_sender_->putInt(col); + packet_sender_->putInt(0); + packet_sender_->putInt(0); + packet_sender_->write(); +} + +void FQTermSSH1Channel::sendData(const char *data, int len) { + packet_sender_->startPacket(SSH1_CMSG_STDIN_DATA); + packet_sender_->putInt(len); + packet_sender_->putRawData(data, len); + packet_sender_->write(); +} + +void FQTermSSH1Channel::closeConnection(const char *reason) { + packet_sender_->startPacket(SSH1_MSG_DISCONNECT); + packet_sender_->putString(reason); + packet_sender_->write(); + is_closed_ = true; +} + +void FQTermSSH1Channel::handlePacket(int type) { + switch (service_state_) { + case BEGIN_SERVICE: + FQ_TRACE("sshchannel", 0) << "Channel: We should not be here"; + break; + case REQPTY_SENT: + if (type != SSH1_SMSG_SUCCESS) { + emit channelError(tr("Server refused pty allocation!")); + } + packet_sender_->startPacket(SSH1_CMSG_EXEC_SHELL); + packet_sender_->write(); + emit channelOK(); + service_state_ = FQTermSSH1Channel::SERVICE_OK; + //emit msg to tell window we could process input. + break; + case SERVICE_OK: + switch (type) { + case SSH1_SMSG_STDOUT_DATA: + case SSH1_SMSG_STDERR_DATA: + { + const char *data = (const char *)packet_receiver_->buffer_->data() + 4; + int len = packet_receiver_->packetDataLen() - 4; + emit channelReadyRead(data, len); + } + break; + case SSH1_SMSG_X11_OPEN: + case SSH1_SMSG_AGENT_OPEN: + case SSH1_MSG_PORT_OPEN: + { + int i = packet_receiver_->getInt(); + packet_sender_->startPacket(SSH1_MSG_CHANNEL_OPEN_FAILURE); + packet_sender_->putInt(i); + packet_sender_->write(); + } + break; + case SSH1_SMSG_EXIT_STATUS: + packet_sender_->startPacket(SSH1_CMSG_EXIT_CONFIRMATION); + packet_sender_->write(); + closeConnection("end"); + is_closed_ = true; + break; + case SSH1_SMSG_SUCCESS: + case SSH1_SMSG_FAILURE: + break; + default: + FQ_TRACE("sshchannel", 0) << "Unimplemented message: " + << service_state_; + } + } +} + + +//============================================================================== +//FQTermSSH2Channel +//============================================================================== +u_int32_t FQTermSSH2Channel::generateChannelID() { + static u_int32_t id = 0; + return id++; +} + +FQTermSSH2Channel::FQTermSSH2Channel() + : FQTermSSHChannel(), + col_(80), + row_(24), + termtype_("vt100") { + channel_id_ = generateChannelID(); + server_channel_id_ = 0xCCCCCCCC; + local_window_size_ = 0; + channel_state_ = FQTermSSH2Channel::BEGIN_CHANNEL; +} + +void FQTermSSH2Channel::initChannel(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output, + int col, int row, const QString& termtype) { + FQ_FUNC_TRACE("ssh2channel", 5); + col_ = col; + row_ = row; + termtype_ = termtype; + packet_receiver_ = packet; + packet_sender_ = output; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), this, SLOT(handlePacket(int)))); + + // byte SSH_MSG_CHANNEL_OPEN + // string channel type in US-ASCII only + // uint32 sender channel + // uint32 initial window size + // uint32 maximum packet size + // .... channel type specific data follows + + packet_sender_->startPacket(SSH2_MSG_CHANNEL_OPEN); + packet_sender_->putString("session"); + packet_sender_->putInt(channel_id_); + packet_sender_->putInt(MAX_LOCAL_WINDOW_SIZE); // TODO: what's the best window size? + packet_sender_->putInt(MAX_LOCAL_PACKET_SIZE); // TODO: what's the best maximum packet size? + packet_sender_->write(); + + server_window_size_ = 0; + server_max_packet_size_ = 0; + local_window_size_ = MAX_LOCAL_WINDOW_SIZE; + + is_closed_ = false; +} + +void FQTermSSH2Channel::changeTermSize(int col, int row) { + // byte SSH_MSG_CHANNEL_REQUEST + // uint32 recipient channel + // string "window-change" + // boolean FALSE + // uint32 terminal width, columns + // uint32 terminal height, rows + // uint32 terminal width, pixels + // uint32 terminal height, pixels + + packet_sender_->startPacket(SSH2_MSG_CHANNEL_REQUEST); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putString("window-change"); + packet_sender_->putByte(false); + packet_sender_->putInt(col); + packet_sender_->putInt(row); + packet_sender_->putInt(640); // FIXME: hard-coded screen pixels. + packet_sender_->putInt(480); + packet_sender_->write(); +} + +void FQTermSSH2Channel::sendData(const char *data, int len) { + if (len > (int)server_window_size_ || len > (int)server_max_packet_size_) { + FQ_TRACE("ssh2channel", 3) << "Data length is greater than server's capacity: " + << "data length: " << len << ", " + << "server window: " << server_window_size_ << ", " + << "server packet max size: " << server_max_packet_size_; + return; + } + + // byte SSH_MSG_CHANNEL_DATA + // uint32 recipient channel + // string data + packet_sender_->startPacket(SSH2_MSG_CHANNEL_DATA); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putString(data, len); + packet_sender_->write(); + + server_window_size_ -= len;; + + FQ_TRACE("ssh2channel", 5) << len + << " bytes data sent, server window size left: " + << server_window_size_;; +} + +void FQTermSSH2Channel::closeConnection(const char *reason) { + packet_sender_->startPacket(SSH1_MSG_DISCONNECT); + packet_sender_->putString(reason); + packet_sender_->write(); + is_closed_ = true; +} + +void FQTermSSH2Channel::requestPty() { + if (packet_receiver_->packetType() == SSH2_MSG_CHANNEL_OPEN_FAILURE) { + // TODO: Here the error reason in the packet is ignored. + emit channelError(tr("Server refuces to open a channel.")); + return; + } + + if (packet_receiver_->packetType() != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { + emit channelError(tr("Server error when opening a channel.")); + return; + } + + FQ_TRACE("ssh2channel", 5) << "Channel open. Try to request a pty."; + + // byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION + // uint32 recipient channel + // uint32 sender channel + // uint32 initial window size + // uint32 maximum packet size + // .... channel type specific data follows + packet_receiver_->consume(4); + server_channel_id_ = packet_receiver_->getInt(); + server_window_size_ = packet_receiver_->getInt(); + server_max_packet_size_ = packet_receiver_->getInt(); + + // byte SSH_MSG_CHANNEL_REQUEST + // uint32 recipient channel + // string "pty-req" + // boolean want_reply + // string TERM environment variable value (e.g., vt100) + // uint32 terminal width, characters (e.g., 80) + // uint32 terminal height, rows (e.g., 24) + // uint32 terminal width, pixels (e.g., 640) + // uint32 terminal height, pixels (e.g., 480) + // string encoded terminal modes + packet_sender_->startPacket(SSH2_MSG_CHANNEL_REQUEST); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putString("pty-req"); + packet_sender_->putByte(true); + packet_sender_->putString(termtype_.toLatin1()); // TODO: hardcoded term type. + packet_sender_->putInt(col_); // FIXME: hardcoded screen parameters. + packet_sender_->putInt(row_); + packet_sender_->putInt(640); + packet_sender_->putInt(480); + packet_sender_->putString(""); // TODO: no modes sent. + packet_sender_->write(); +} + + +void FQTermSSH2Channel::requestShell() { + if (packet_receiver_->packetType() != SSH2_MSG_CHANNEL_SUCCESS) { + emit channelError(tr("Server refused pty allocation!")); + } + FQ_TRACE("ssh2channel", 5) << "Pty allocated. Now try to request a shell."; + // byte SSH_MSG_CHANNEL_REQUEST + // uint32 recipient channel + // string "shell" + // boolean want reply + packet_sender_->startPacket(SSH2_MSG_CHANNEL_REQUEST); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putString("shell"); + packet_sender_->putByte(true); + packet_sender_->write(); +} + +void FQTermSSH2Channel::checkLocalWindowSize() { + if (local_window_size_ < MAX_LOCAL_WINDOW_SIZE/2) { + // byte SSH_MSG_CHANNEL_WINDOW_ADJUST + // uint32 recipient channel + // uint32 bytes to add + int inc = MAX_LOCAL_WINDOW_SIZE/2; + local_window_size_ += inc; + + packet_sender_->startPacket(SSH2_MSG_CHANNEL_WINDOW_ADJUST); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putInt(inc); + packet_sender_->write(); + } +} + +void FQTermSSH2Channel::processChannelPacket() { + switch (packet_receiver_->packetType()) { + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: + { + // byte SSH_MSG_CHANNEL_WINDOW_ADJUST + // uint32 recipient channel + // uint32 bytes to add + packet_receiver_->consume(4); // channel id is already checked. + int inc = packet_receiver_->getInt(); + server_window_size_ += inc; + FQ_TRACE("ssh2channel", 5) << "Server window size increased from " + << server_window_size_ - inc + << " to " << server_window_size_; + } + break; + case SSH2_MSG_CHANNEL_DATA: + { + // byte SSH_MSG_CHANNEL_DATA + // uint32 recipient channel + // string data + packet_receiver_->consume(4); + int len = packet_receiver_->getInt(); + const char *data = (const char *)packet_receiver_->buffer_->data(); + local_window_size_ -= len; + checkLocalWindowSize(); + emit channelReadyRead(data, len); + } + break; + case SSH2_MSG_CHANNEL_EXTENDED_DATA: + { + // byte SSH_MSG_CHANNEL_DATA + // uint32 recipient channel + // string data + packet_receiver_->consume(4); + int len = packet_receiver_->getInt(); + const char *data = (const char *)packet_receiver_->buffer_->data(); + local_window_size_ -= len; + checkLocalWindowSize(); + emit channelReadyRead(data, len); + } + break; + case SSH2_MSG_CHANNEL_EOF: + case SSH2_MSG_CHANNEL_CLOSE: + // byte SSH_MSG_CHANNEL_EOF + // uint32 recipient channel + // FIXME: this error would cause the connection closed, while only the channel need be closed in ssh2. + emit channelError(tr("Channel closed by the server.")); + break; + case SSH2_MSG_CHANNEL_REQUEST: + // byte SSH_MSG_CHANNEL_REQUEST + // uint32 recipient channel + // string "xon-xoff" + // boolean FALSE + // boolean client can do + + // TODO: just ignore this message currently. + break; + } +} + +void FQTermSSH2Channel::handlePacket(int type) { + // first check the channel id. + u_int32_t channel_id = ntohu32(packet_receiver_->buffer_->data()); + if (channel_id != channel_id_) { + return; + } + + switch (channel_state_) { + case FQTermSSH2Channel::BEGIN_CHANNEL: + requestPty(); + channel_state_ = FQTermSSH2Channel::REQUEST_PTY_SENT; + break; + case FQTermSSH2Channel::REQUEST_PTY_SENT: + requestShell(); + channel_state_ = FQTermSSH2Channel::REQUEST_SHELL_SENT; + break; + case FQTermSSH2Channel::REQUEST_SHELL_SENT: + switch (type) { + case SSH2_MSG_CHANNEL_REQUEST: + { + FQ_TRACE("ssh2channel", 8) << "SSH2_MSG_CHANNEL_REQUEST isn't supported, just send back a packet with SSH2_MSG_CHANNEL_SUCCESS if reply is needed."; + + packet_receiver_->consume(4); + u_int32_t len = ntohu32(packet_receiver_->buffer_->data()); + packet_receiver_->consume(4 + len); + bool replyNeeded = packet_receiver_->getByte(); + + if (replyNeeded) { + packet_sender_->startPacket(SSH2_MSG_CHANNEL_SUCCESS); + packet_sender_->putInt(server_channel_id_); + packet_sender_->write(); + } + } + break; + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: + { + packet_receiver_->consume(4); + u_int32_t inc = packet_receiver_->getInt(); + server_window_size_ += inc; + } + break; + case SSH2_MSG_CHANNEL_SUCCESS: + emit channelOK(); + channel_state_ = FQTermSSH2Channel::CHANNEL_OK; + //emit a msg to tell window we could process input. + break; + case SSH2_MSG_CHANNEL_FAILURE: + emit channelError(tr("Can't open a shell.")); + break; + default: + emit channelError(tr("Unsupported packet.")); + break; + } + break; + case FQTermSSH2Channel::CHANNEL_OK: + processChannelPacket(); + break; + } +} + +} // namespace FQTerm + +#include "fqterm_ssh_channel.moc" diff --git a/src/protocol/internal/fqterm_ssh_channel.h b/src/protocol/internal/fqterm_ssh_channel.h new file mode 100644 index 0000000..9922528 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_channel.h @@ -0,0 +1,130 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_CHANNEL_H +#define FQTERM_SSH_CHANNEL_H + +#include "fqterm_ssh_types.h" + +#include + +namespace FQTerm { + +class FQTermSSHPacketReceiver; +class FQTermSSHPacketSender; + +class FQTermSSHChannel: public QObject { + Q_OBJECT; +protected: + bool is_closed_; + + FQTermSSHPacketReceiver *packet_receiver_; + FQTermSSHPacketSender *packet_sender_; + +public: + FQTermSSHChannel(){} + virtual ~FQTermSSHChannel(){} + virtual void initChannel(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output, + int col, int row, const QString& termtype) = 0; + virtual void closeConnection(const char *reason) = 0; + + // TODO: it seems this function isn't used. + virtual void changeTermSize(int col, int row) = 0; + + virtual void sendData(const char *data, int len) = 0; + +public slots: + virtual void handlePacket(int type) = 0; +signals: + void channelOK(); + void channelReadyRead(const char *data, int len); + void channelError(QString); +}; + +class FQTermSSH1Channel: public FQTermSSHChannel { + Q_OBJECT; +private: + enum FQTermSSH1ChannelState { + BEGIN_SERVICE, REQPTY_SENT, + //REQCMD_SENT, + SERVICE_OK + } service_state_; + +public: + FQTermSSH1Channel(); + virtual void initChannel(FQTermSSHPacketReceiver *packet, FQTermSSHPacketSender *output, + int col, int row, const QString& termtype); + virtual void closeConnection(const char *reason); + virtual void changeTermSize(int col, int row); + virtual void sendData(const char *data, int len); + +public slots: + virtual void handlePacket(int type); +signals: + void channelReadyRead(const char *data, int len); +}; + + +class FQTermSSH2Channel: public FQTermSSHChannel { + Q_OBJECT; +private: + static u_int32_t generateChannelID(); + +private: + int col_; + int row_; + QString termtype_; + enum FQTermSSH2ChannelState { + BEGIN_CHANNEL, REQUEST_PTY_SENT, REQUEST_SHELL_SENT, CHANNEL_OK + } channel_state_; + + u_int32_t channel_id_; + + enum {MAX_LOCAL_WINDOW_SIZE = 0x100000, MAX_LOCAL_PACKET_SIZE = 0x4000}; + + u_int32_t local_window_size_; + + u_int32_t server_channel_id_; + u_int32_t server_window_size_; // connection packet window size; + u_int32_t server_max_packet_size_; // max size of each packet sent to server. + + void requestPty(); + void requestShell(); + void processChannelPacket(); + void checkLocalWindowSize(); + +public: + FQTermSSH2Channel(); + virtual void initChannel(FQTermSSHPacketReceiver *packet, FQTermSSHPacketSender *output, + int col, int row, const QString& termtype); + virtual void closeConnection(const char *reason); + virtual void changeTermSize(int col, int row); + virtual void sendData(const char *data, int len); + +public slots: + virtual void handlePacket(int type); +signals: + void channelReadyRead(const char *data, int len); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_CHANNEL_H diff --git a/src/protocol/internal/fqterm_ssh_cipher.h b/src/protocol/internal/fqterm_ssh_cipher.h new file mode 100644 index 0000000..13bc9f3 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_cipher.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_CIPHER_H +#define FQTERM_SSH_CIPHER_H + +#include + +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_const.h" + +namespace FQTerm { + +class FQTermSSHCipher { +protected: + const char *d_name; + +public: + FQTermSSHCipher() { + d_name = NULL; + } + + virtual ~FQTermSSHCipher(){} + + const char *name() const { + return d_name; + } + + virtual int blockSize() const = 0; + virtual int getKeySize() const = 0; + virtual int getIVSize() const = 0; + + virtual void setIV(const u_char *data) = 0; + virtual void setKey(const u_char *data) = 0; + virtual void encrypt(const u_char *source, u_char *dest, int len) = 0; + virtual void decrypt(const u_char *source, u_char *dest, int len) = 0; +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_CIPHER_H diff --git a/src/protocol/internal/fqterm_ssh_const.h b/src/protocol/internal/fqterm_ssh_const.h new file mode 100644 index 0000000..412760e --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_const.h @@ -0,0 +1,146 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERMCONST_H +#define FQTERMCONST_H + +namespace FQTerm { + +#define SSH_CIPHER_SSH2 -3 +#define SSH_CIPHER_ILLEGAL -2 +#define SSH_CIPHER_NOT_SET -1 +#define SSH_CIPHER_NONE 0 +#define SSH_CIPHER_IDEA 1 +#define SSH_CIPHER_DES 2 +#define SSH_CIPHER_3DES 3 +#define SSH_CIPHER_BROKEN_TSS 4 +#define SSH_CIPHER_BROKEN_RC4 5 +#define SSH_CIPHER_BLOWFISH 6 +#define SSH_CIPHER_RESERVED 7 +#define SSH_CIPHER_MAX 31 + +#define SSH1_MSG_DISCONNECT 1 +#define SSH1_SMSG_PUBLIC_KEY 2 +#define SSH1_CMSG_SESSION_KEY 3 +#define SSH1_CMSG_USER 4 +#define SSH1_CMSG_AUTH_RSA 6 +#define SSH1_SMSG_AUTH_RSA_CHALLENGE 7 +#define SSH1_CMSG_AUTH_RSA_RESPONSE 8 +#define SSH1_CMSG_AUTH_PASSWORD 9 +#define SSH1_CMSG_REQUEST_PTY 10 +#define SSH1_CMSG_WINDOW_SIZE 11 +#define SSH1_CMSG_EXEC_SHELL 12 +#define SSH1_CMSG_EXEC_CMD 13 +#define SSH1_SMSG_SUCCESS 14 +#define SSH1_SMSG_FAILURE 15 +#define SSH1_CMSG_STDIN_DATA 16 +#define SSH1_SMSG_STDOUT_DATA 17 +#define SSH1_SMSG_STDERR_DATA 18 +#define SSH1_CMSG_EOF 19 +#define SSH1_SMSG_EXIT_STATUS 20 +#define SSH1_MSG_CHANNEL_OPEN_CONFIRMATION 21 +#define SSH1_MSG_CHANNEL_OPEN_FAILURE 22 +#define SSH1_MSG_CHANNEL_DATA 23 +#define SSH1_MSG_CHANNEL_CLOSE 24 +#define SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION 25 +#define SSH1_SMSG_X11_OPEN 27 +#define SSH1_CMSG_PORT_FORWARD_REQUEST 28 +#define SSH1_MSG_PORT_OPEN 29 +#define SSH1_CMSG_AGENT_REQUEST_FORWARDING 30 +#define SSH1_SMSG_AGENT_OPEN 31 +#define SSH1_MSG_IGNORE 32 +#define SSH1_CMSG_EXIT_CONFIRMATION 33 +#define SSH1_CMSG_X11_REQUEST_FORWARDING 34 +#define SSH1_CMSG_AUTH_RHOSTS_RSA 35 +#define SSH1_MSG_DEBUG 36 +#define SSH1_CMSG_REQUEST_COMPRESSION 37 +#define SSH1_CMSG_AUTH_TIS 39 +#define SSH1_SMSG_AUTH_TIS_CHALLENGE 40 +#define SSH1_CMSG_AUTH_TIS_RESPONSE 41 +#define SSH1_CMSG_AUTH_CCARD 70 +#define SSH1_SMSG_AUTH_CCARD_CHALLENGE 71 +#define SSH1_CMSG_AUTH_CCARD_RESPONSE 72 +#define SSH1_AUTH_TIS 5 +#define SSH1_PROTOFLAG_SCREEN_NUMBER 1 +#define SSH1_PROTOFLAGS_SUPPORTED 0 + + +#define SSH2_MSG_DISCONNECT 1 +#define SSH2_MSG_IGNORE 2 +#define SSH2_MSG_UNIMPLEMENTED 3 +#define SSH2_MSG_DEBUG 4 +#define SSH2_MSG_SERVICE_REQUEST 5 +#define SSH2_MSG_SERVICE_ACCEPT 6 +#define SSH2_MSG_KEXINIT 20 +#define SSH2_MSG_NEWKEYS 21 +#define SSH2_MSG_KEXDH_INIT 30 +#define SSH2_MSG_KEXDH_REPLY 31 +#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30 +#define SSH2_MSG_KEX_DH_GEX_GROUP 31 +#define SSH2_MSG_KEX_DH_GEX_INIT 32 +#define SSH2_MSG_KEX_DH_GEX_REPLY 33 +#define SSH2_MSG_KEX_DH_GEX_REQUEST 34 +#define SSH2_MSG_USERAUTH_REQUEST 50 +#define SSH2_MSG_USERAUTH_FAILURE 51 +#define SSH2_MSG_USERAUTH_SUCCESS 52 +#define SSH2_MSG_USERAUTH_BANNER 53 +#define SSH2_MSG_USERAUTH_PK_OK 60 +#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 +#define SSH2_MSG_USERAUTH_INFO_REQUEST 60 +#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 +#define SSH2_MSG_GLOBAL_REQUEST 80 +#define SSH2_MSG_REQUEST_SUCCESS 81 +#define SSH2_MSG_REQUEST_FAILURE 82 +#define SSH2_MSG_CHANNEL_OPEN 90 +#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 +#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 +#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 +#define SSH2_MSG_CHANNEL_DATA 94 +#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 +#define SSH2_MSG_CHANNEL_EOF 96 +#define SSH2_MSG_CHANNEL_CLOSE 97 +#define SSH2_MSG_CHANNEL_REQUEST 98 +#define SSH2_MSG_CHANNEL_SUCCESS 99 +#define SSH2_MSG_CHANNEL_FAILURE 100 +#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 +#define SSH2_DISCONNECT_PROTOCOL_ERROR 2 +#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3 +#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4 +#define SSH2_DISCONNECT_RESERVED 4 +#define SSH2_DISCONNECT_MAC_ERROR 5 +#define SSH2_DISCONNECT_COMPRESSION_ERROR 6 +#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7 +#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 +#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 +#define SSH2_DISCONNECT_CONNECTION_LOST 10 +#define SSH2_DISCONNECT_BY_APPLICATION 11 +#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12 +#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13 +#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 +#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15 +#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1 +#define SSH2_OPEN_CONNECT_FAILED 2 +#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3 +#define SSH2_OPEN_RESOURCE_SHORTAGE 4 +#define SSH2_EXTENDED_DATA_STDERR 1 + +} // namespace FQTerm + +#endif // FQTERMCONST_H diff --git a/src/protocol/internal/fqterm_ssh_des.cpp b/src/protocol/internal/fqterm_ssh_des.cpp new file mode 100644 index 0000000..603b6fe --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_des.cpp @@ -0,0 +1,180 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "fqterm_ssh_const.h" +#include "fqterm_ssh_des.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +//============================================================================== +//FQTermSSH1DES3 +//============================================================================== + +FQTermSSH1DES3::FQTermSSH1DES3() { + d_name = "des3-cbc"; + + memset(d_IV1, 0, sizeof(d_IV1)); + memset(d_IV2, 0, sizeof(d_IV2)); + memset(d_IV3, 0, sizeof(d_IV3)); +} + +int FQTermSSH1DES3::blockSize() const { + return 8; +} + +void FQTermSSH1DES3::decrypt(const u_char *source, u_char *dest, int len) { + DES_ncbc_encrypt(source, dest, len, &d_key3, &d_IV3, DES_DECRYPT); + DES_ncbc_encrypt(dest, dest, len, &d_key2, &d_IV2, DES_ENCRYPT); + DES_ncbc_encrypt(dest, dest, len, &d_key1, &d_IV1, DES_DECRYPT); +} + +void FQTermSSH1DES3::encrypt(const u_char *source, u_char *dest, int len) { + DES_ncbc_encrypt(source, dest, len, &d_key1, &d_IV1, DES_ENCRYPT); + DES_ncbc_encrypt(dest, dest, len, &d_key2, &d_IV2, DES_DECRYPT); + DES_ncbc_encrypt(dest, dest, len, &d_key3, &d_IV3, DES_ENCRYPT); +} + +int FQTermSSH1DES3::getKeySize() const { + return 3*DES_KEY_SZ; +} + +int FQTermSSH1DES3::getIVSize() const { + return 0; +} + +void FQTermSSH1DES3::setIV(const u_char *data) { + memset(d_IV1, 0, sizeof(d_IV1)); + memset(d_IV2, 0, sizeof(d_IV2)); + memset(d_IV3, 0, sizeof(d_IV3)); +} + +void FQTermSSH1DES3::setKey(const u_char *data) { + DES_cblock key; + memset(key, 0, sizeof(key)); + memcpy(key, data, sizeof(key)); + DES_set_key(&key, &d_key1); + data += 8; + memset(key, 0, sizeof(key)); + memcpy(key, data, sizeof(key)); + DES_set_key(&key, &d_key2); + data += 8; + memset(key, 0, sizeof(key)); + memcpy(key, data, sizeof(key)); + DES_set_key(&key, &d_key3); +} + + +//================================================== +// TripleDES-CBC +//================================================== + +FQTermSSH2TripleDESCBC::FQTermSSH2TripleDESCBC() { + d_name = "des3-cbc"; + ctx_ = NULL; +} + +FQTermSSH2TripleDESCBC::~FQTermSSH2TripleDESCBC() { + if (ctx_ != NULL) { + EVP_CIPHER_CTX_cleanup(ctx_); + delete ctx_; + } +} + + +int FQTermSSH2TripleDESCBC::blockSize() const { + return 8; +} + +int FQTermSSH2TripleDESCBC::getKeySize() const { + return 24; +} + +int FQTermSSH2TripleDESCBC::getIVSize() const { + return 8; +} + +void FQTermSSH2TripleDESCBC::setIV(const u_char *data) { + memcpy(IV_, data, getIVSize()); +} + +void FQTermSSH2TripleDESCBC::setKey(const u_char *data) { + memcpy(key_, data, getKeySize()); +} + +void FQTermSSH2TripleDESCBC::encrypt(const u_char *source, u_char *dest, int len) { + FQ_TRACE("3DES_CBC", 9) << "Start encrypting"; + FQ_TRACE("3DES_CBC", 9) << "data len:" << len; + FQ_TRACE("3DES_CBC", 9) << "Source: \n" << dumpHexString << std::string((char *)source, len); + + int ret = 0; + if (ctx_ == NULL) { + // Lazy initialization. + ctx_ = new EVP_CIPHER_CTX; + EVP_CIPHER_CTX_init(ctx_); + ret = EVP_CipherInit(ctx_, EVP_des_ede3_cbc(), key_, IV_, 1); + FQ_VERIFY(ret == 1); + } + + ret = EVP_Cipher(ctx_, dest, source, len); + + FQ_VERIFY(ret == 1); + + FQ_TRACE("3DES_CBC", 9) << "Dest: \n" << dumpHexString << std::string((char *)dest, len); + + FQ_TRACE("3DES_CBC", 9) << "IV:\n" << dumpHexString << std::string((char *)IV_, getIVSize()); + FQ_TRACE("3DES_CBC", 9) << "key:\n" << dumpHexString << std::string((char *)key_, getKeySize()); + +} + +void FQTermSSH2TripleDESCBC::decrypt(const u_char *source, u_char *dest, int len) { + FQ_TRACE("3DES_CBC", 9) << "Start dencrypting"; + FQ_TRACE("3DES_CBC", 9) << "data len:" << len; + FQ_TRACE("3DES_CBC", 9) << "Source: \n" << dumpHexString << std::string((char *)source, len); + + int ret = 0; + if (ctx_ == NULL) { + // Lazy initialization. + ctx_ = new EVP_CIPHER_CTX; + EVP_CIPHER_CTX_init(ctx_); + ret = EVP_CipherInit(ctx_, EVP_des_ede3_cbc(), key_, IV_, 0); + FQ_VERIFY(ret == 1); + } + + ret = EVP_Cipher(ctx_, dest, source, len); + + FQ_VERIFY(ret == 1); + + FQ_TRACE("3DES_CBC", 9) << "Dest: \n" << dumpHexString << std::string((char *)dest, len); + + FQ_TRACE("3DES_CBC", 9) << "IV:\n" << dumpHexString << std::string((char *)IV_, getIVSize()); + FQ_TRACE("3DES_CBC", 9) << "key:\n" << dumpHexString << std::string((char *)key_, getKeySize()); +} + + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_des.h b/src/protocol/internal/fqterm_ssh_des.h new file mode 100644 index 0000000..ba153f2 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_des.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_DES_H +#define FQTERM_SSH_DES_H + +#include +#include + +#include "fqterm_ssh_cipher.h" +#include "fqterm_ssh_types.h" + +namespace FQTerm { + +class FQTermSSH1DES3: public FQTermSSHCipher { + private: + DES_cblock d_IV1; + DES_cblock d_IV2; + DES_cblock d_IV3; + DES_key_schedule d_key1; + DES_key_schedule d_key2; + DES_key_schedule d_key3; + public: + FQTermSSH1DES3(); + + virtual int blockSize() const; + virtual int getKeySize() const; + virtual int getIVSize() const; + virtual void setIV(const u_char *data); + virtual void setKey(const u_char *data); + virtual void encrypt(const u_char *source, u_char *dest, int len); + virtual void decrypt(const u_char *source, u_char *dest, int len); +}; + +class FQTermSSH2TripleDESCBC: public FQTermSSHCipher { + private: + unsigned char IV_[8]; + unsigned char key_[24]; + + EVP_CIPHER_CTX *ctx_; + + public: + FQTermSSH2TripleDESCBC(); + ~FQTermSSH2TripleDESCBC(); + + virtual int blockSize() const; + virtual int getKeySize() const; + virtual int getIVSize() const; + virtual void setIV(const u_char *data); + virtual void setKey(const u_char *data); + virtual void encrypt(const u_char *source, u_char *dest, int len); + virtual void decrypt(const u_char *source, u_char *dest, int len); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_DES_H diff --git a/src/protocol/internal/fqterm_ssh_hash.h b/src/protocol/internal/fqterm_ssh_hash.h new file mode 100644 index 0000000..b4679f4 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_hash.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_HASH_H +#define FQTERM_SSH_HASH_H + +#include "fqterm_ssh_types.h" + +namespace FQTerm { + +class FQTermSSHHash { +protected: + int d_digestLength; + int digestLength()const { + return d_digestLength; + } + +public: + FQTermSSHHash() { + d_digestLength = 0; + } + virtual ~FQTermSSHHash() {} + + virtual void update(u_char *data, int len) = 0; + virtual void final(u_char *data) = 0; +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH_HASH_H diff --git a/src/protocol/internal/fqterm_ssh_kex.cpp b/src/protocol/internal/fqterm_ssh_kex.cpp new file mode 100644 index 0000000..d27bf14 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_kex.cpp @@ -0,0 +1,210 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_ssh_kex.h" +#include "fqterm_ssh_md5.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +FQTermSSHKex::FQTermSSHKex(const char *V_C, const char *V_S) { + V_C_ = new char[strlen(V_C) + 1]; + V_S_ = new char[strlen(V_S) + 1]; + + strcpy(V_C_, V_C); + strcpy(V_S_, V_S); +} + +FQTermSSHKex::~FQTermSSHKex() { + delete[] V_C_; + delete[] V_S_; +} + + +//============================================================================== +//FQTermSSH1Kex +//============================================================================== + +FQTermSSH1Kex::FQTermSSH1Kex(const char *V_C, const char *V_S) + : FQTermSSHKex(V_C, V_S) { + is_first_kex_ = true; + kex_state_ = FQTermSSH1Kex::BEFORE_PUBLICKEY; +} + +FQTermSSH1Kex::~FQTermSSH1Kex(){} + +void FQTermSSH1Kex::initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *packetSender) { + packet_receiver_ = packetReceiver; + packet_sender_ = packetSender; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), + this, SLOT(handlePacket(int)))); + kex_state_ = FQTermSSH1Kex::BEFORE_PUBLICKEY; + emit reKex(); +} + +void FQTermSSH1Kex::handlePacket(int type) { + switch (kex_state_) { + case FQTermSSH1Kex::BEFORE_PUBLICKEY: + makeSessionKey(); + kex_state_ = FQTermSSH1Kex::SESSIONKEY_SENT; + break; + case FQTermSSH1Kex::SESSIONKEY_SENT: + if (type != SSH1_SMSG_SUCCESS) { + emit kexError(tr("Kex exchange failed!")); + break; + } + emit kexOK(); + kex_state_ = FQTermSSH1Kex::KEYEX_OK; + break; + case FQTermSSH1Kex::KEYEX_OK: + break; + } +} + +void FQTermSSH1Kex::makeSessionKey() { + int i; + BIGNUM *key; + u_int32_t rand_val; + int bits; + int rbits; + + if (packet_receiver_->packetType() != SSH1_SMSG_PUBLIC_KEY) { + emit kexError(tr("startKex: First packet is not public key")); + return ; + } + packet_receiver_->getRawData((char*)cookie_, 8); + + // Get the public key. + server_key_ = new FQTermSSHRSA; + bits = packet_receiver_->getInt(); + packet_receiver_->getBN(server_key_->d_rsa->e); + packet_receiver_->getBN(server_key_->d_rsa->n); + + rbits = BN_num_bits(server_key_->d_rsa->n); + if (bits != rbits) { + FQ_TRACE("sshkex", 0) << "Warning: Server lies about " + << "size of server public key: " + << "actual size: " << rbits + << " vs. anounced: " << bits; + FQ_TRACE("sshkex", 0) << "Warning: This may be due to " + << "an old implementation of ssh."; + } + + // Get the host key. + host_key_ = new FQTermSSHRSA; + bits = packet_receiver_->getInt(); + packet_receiver_->getBN(host_key_->d_rsa->e); + packet_receiver_->getBN(host_key_->d_rsa->n); + + rbits = BN_num_bits(host_key_->d_rsa->n); + if (bits != rbits) { + FQ_TRACE("sshkex", 0) << "Warning: Server lies about " + << "size of server public key: " + << "actual size: " << rbits + << " vs. anounced: " << bits; + FQ_TRACE("sshkex", 0) << "Warning: This may be due to " + << "an old implementation of ssh."; + } + + // Get protocol flags. + server_flag_ = packet_receiver_->getInt(); + ciphers_ = packet_receiver_->getInt(); + auth_ = packet_receiver_->getInt(); + + if ((ciphers_ &(1 << SSH_CIPHER_3DES)) == 0) { + FQ_VERIFY(false); // server do not support my cipher + } + + makeSessionId(); + + // Generate an encryption key for the session. The key is a 256 bit + // random number, interpreted as a 32-byte key, with the least + // significant 8 bits being the first byte of the key. + + for (i = 0; i < 32; i++) { + if (i % 4 == 0) { + rand_val = rand(); + } + + session_key_[i] = (rand_val &0xff); + rand_val >>= 8; + } + + key = BN_new(); + + BN_set_word(key, 0); + for (i = 0; i < 32; i++) { + BN_lshift(key, key, 8); + if (i < 16) { + BN_add_word(key, session_key_[i] ^ session_id_[i]); + } else { + BN_add_word(key, session_key_[i]); + } + } + + if (BN_cmp(server_key_->d_rsa->n, host_key_->d_rsa->n) < 0) { + server_key_->publicEncrypt(key, key); + host_key_->publicEncrypt(key, key); + } else { + host_key_->publicEncrypt(key, key); + server_key_->publicEncrypt(key, key); + } + + delete host_key_; + delete server_key_; + + packet_sender_->startPacket(SSH1_CMSG_SESSION_KEY); + packet_sender_->putByte(SSH_CIPHER_3DES); + packet_sender_->putRawData((const char*)cookie_, 8); + packet_sender_->putBN(key); + + BN_free(key); + + packet_sender_->putInt(1); + packet_sender_->write(); + + emit startEncryption(session_key_); +} + +void FQTermSSH1Kex::makeSessionId() { + u_char *p; + FQTermSSHMD5 *md5; + int servlen, hostlen; + + md5 = new FQTermSSHMD5; + servlen = BN_num_bytes(server_key_->d_rsa->n); + hostlen = BN_num_bytes(host_key_->d_rsa->n); + + p = new u_char[servlen + hostlen]; + + BN_bn2bin(host_key_->d_rsa->n, p); + BN_bn2bin(server_key_->d_rsa->n, p + hostlen); + md5->update(p, servlen + hostlen); + md5->update(cookie_, 8); + md5->final(session_id_); + delete md5; + delete [] p; +} + +} // namespace FQTerm + +#include "fqterm_ssh_kex.moc" diff --git a/src/protocol/internal/fqterm_ssh_kex.h b/src/protocol/internal/fqterm_ssh_kex.h new file mode 100644 index 0000000..b2f9c56 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_kex.h @@ -0,0 +1,100 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_KEX_H +#define FQTERM_SSH_KEX_H + +#include +#include + +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_rsa.h" +#include "fqterm_ssh_packet.h" +#include "fqterm_ssh_const.h" + +namespace FQTerm { + +class FQTermSSHPacketReceiver; +class FQTermSSHPacketSender; + +class FQTermSSHKex: public QObject { + Q_OBJECT; +protected: + FQTermSSHPacketReceiver *packet_receiver_; + FQTermSSHPacketSender *packet_sender_; + + char *V_C_; + char *V_S_; +public: + // Init with + // string V_C, the client's identification string (CR and LF + // excluded) + // string V_S, the server's identification string (CR and LF + // excluded) + FQTermSSHKex(const char *V_C, const char *V_S); + virtual ~FQTermSSHKex(); + + virtual void initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *outputSender) = 0; + +public slots: + virtual void handlePacket(int type) = 0; + +signals: + void kexOK(); + void reKex(); + void kexError(QString); + + void startEncryption(const u_char *sessionkey); + +}; + +class FQTermSSH1Kex: public FQTermSSHKex { + Q_OBJECT; +private: + enum FQTermSSH1KexState { + BEFORE_PUBLICKEY, SESSIONKEY_SENT, KEYEX_OK + } kex_state_; + + bool is_first_kex_; + + FQTermSSHRSA *host_key_; + FQTermSSHRSA *server_key_; + + u_char cookie_[8]; + int server_flag_, ciphers_, auth_; + u_char session_id_[16]; + u_char session_key_[32]; + + void makeSessionId(); + void makeSessionKey(); + +public: + FQTermSSH1Kex(const char *V_C, const char *V_S); + ~FQTermSSH1Kex(); + virtual void initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *outputSender); + + virtual void handlePacket(int type); +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH_KEX_H diff --git a/src/protocol/internal/fqterm_ssh_mac.cpp b/src/protocol/internal/fqterm_ssh_mac.cpp new file mode 100644 index 0000000..e2d345f --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_mac.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include + +#include "fqterm_trace.h" +#include "fqterm_ssh_mac.h" +#include "fqterm_ssh_packet.h" + +namespace FQTerm { + +void FQTermSSHSHA1::setKey(const unsigned char *key) { + memcpy(key_, key, keySize()); +} + +int FQTermSSHSHA1::keySize() const { + return SHA_DIGEST_LENGTH; +} + +int FQTermSSHSHA1::digestSize() const { + return SHA_DIGEST_LENGTH; +} + +void FQTermSSHSHA1::getDigest(const unsigned char *data, int len, unsigned char *digest) const { + unsigned int tmp; + HMAC(EVP_sha1(), key_, SHA_DIGEST_LENGTH, data, len, digest, &tmp); + + FQ_TRACE("SHA1", 9) << "Key: \n" << dumpHexString << std::string((char *)key_, SHA_DIGEST_LENGTH); + FQ_TRACE("SHA1", 9) << "data len:" << len; + FQ_TRACE("SHA1", 9) << "data:\n" << dumpHexString << std::string((char *)data, len); + FQ_TRACE("SHA1", 9) << "digest len:" << tmp; + FQ_TRACE("SHA1", 9) << "digest:\n" << dumpHexString << std::string((char *)digest, tmp); +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_mac.h b/src/protocol/internal/fqterm_ssh_mac.h new file mode 100644 index 0000000..545909c --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_mac.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_MAC_H +#define FQTERM_SSH_MAC_H + +#include + +namespace FQTerm { + +class FQTermSSHMac { +public: + FQTermSSHMac() {} + virtual ~FQTermSSHMac() {} + virtual void setKey(const unsigned char *key) = 0; + virtual int keySize() const = 0; + virtual int digestSize() const = 0; + virtual void getDigest(const unsigned char *data, int len, unsigned char *digest) const = 0; +}; + +const int FQTERM_SSH_MAC_NONE = 0; +const int FQTERM_SSH_HMAC_SHA1 = 1; + +class FQTermSSHSHA1: public FQTermSSHMac { + unsigned char key_[SHA_DIGEST_LENGTH]; + +public: + virtual void setKey(const unsigned char *key); + virtual int keySize() const; + virtual int digestSize() const; + virtual void getDigest(const unsigned char *data, int len, unsigned char *digest) const; +}; + + +} // namespace FQTerm + +#endif // FQTERM_SSH_MAC_H diff --git a/src/protocol/internal/fqterm_ssh_md5.cpp b/src/protocol/internal/fqterm_ssh_md5.cpp new file mode 100644 index 0000000..10713e9 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_md5.cpp @@ -0,0 +1,36 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_ssh_md5.h" + +namespace FQTerm { + +//============================================================================== +//FQTermSSHMD5 +//============================================================================== +void FQTermSSHMD5::final(u_char *digest) { + MD5_Final(digest, &d_md5); +} + +void FQTermSSHMD5::update(u_char *data, int len) { + MD5_Update(&d_md5, data, len); +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_md5.h b/src/protocol/internal/fqterm_ssh_md5.h new file mode 100644 index 0000000..abb8127 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_md5.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_MD5_H +#define FQTERM_SSH_MD5_H + +#include + +#include + +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_hash.h" + +namespace FQTerm { + +class FQTermSSHMD5: public FQTermSSHHash { +protected: + MD5_CTX d_md5; +public: + FQTermSSHMD5() + : FQTermSSHHash() { + d_digestLength = 16; + MD5_Init(&d_md5); + } + virtual ~FQTermSSHMD5() {} + + void update(u_char *data, int len); + void final(u_char *digest); +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH_MD5_H diff --git a/src/protocol/internal/fqterm_ssh_packet.cpp b/src/protocol/internal/fqterm_ssh_packet.cpp new file mode 100644 index 0000000..9c4ff6c --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_packet.cpp @@ -0,0 +1,242 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_trace.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_ssh_packet.h" +#include "fqterm_ssh_des.h" + +#include "fqterm_serialization.h" +#include "crc32.h" + +namespace FQTerm { + +//============================================================================== +//FQTermSSHPacketSender +//============================================================================== + +FQTermSSHPacketSender::FQTermSSHPacketSender() { + buffer_ = new FQTermSSHBuffer(1024); + output_buffer_ = new FQTermSSHBuffer(1024); + + is_encrypt_ = false; + cipher_type_ = SSH_CIPHER_NONE; + cipher_ = NULL; + setEncryptionType(SSH_CIPHER_3DES); + + is_mac_ = false; + mac_type_ = FQTERM_SSH_MAC_NONE; + mac_ = NULL; + + is_compressed_ = false; + + sequence_no_ = 0; +} + +FQTermSSHPacketSender::~FQTermSSHPacketSender() { + delete buffer_; + delete output_buffer_; + if (is_encrypt_) { + delete cipher_; + } +} + +void FQTermSSHPacketSender::putRawData(const char *data, int len) { + buffer_->putRawData(data, len); +} + +void FQTermSSHPacketSender::putByte(int data) { + buffer_->putByte(data); +} + +void FQTermSSHPacketSender::putInt(u_int data) { + buffer_->putInt(data); +} + +void FQTermSSHPacketSender::putString(const char *string, int len) { + buffer_->putString(string, len); +} + +void FQTermSSHPacketSender::putBN(BIGNUM *bn) { + buffer_->putSSH1BN(bn); +} + +void FQTermSSHPacketSender::putBN2(BIGNUM *bn) { + buffer_->putSSH2BN(bn); +} + +void FQTermSSHPacketSender::startPacket(int pkt_type) { + buffer_->clear(); + buffer_->putByte(pkt_type); +} + +void FQTermSSHPacketSender::write() { + makePacket(); + emit dataToWrite(); +} + +void FQTermSSHPacketSender::setEncryptionType(int cipherType) { + cipher_type_ = cipherType; + + delete cipher_; + cipher_ = NULL; + + switch (cipher_type_) { + case SSH_CIPHER_3DES: + cipher_ = new FQTermSSH1DES3; + break; + } +} + +void FQTermSSHPacketSender::startEncryption(const u_char *key, const u_char *IV) { + is_encrypt_ = true; + cipher_->setIV(IV); + cipher_->setKey(key); +} + +void FQTermSSHPacketSender::resetEncryption() { + is_encrypt_ = false; +} + +void FQTermSSHPacketSender::setMacType(int macType) { + mac_type_ = macType; + + delete mac_; + mac_ = NULL; + + switch (mac_type_) { + case FQTERM_SSH_HMAC_SHA1: + mac_ = new FQTermSSHSHA1; + break; + } +} + +void FQTermSSHPacketSender::startMac(const u_char *key) { + is_mac_ = true; + mac_->setKey(key); +} + +void FQTermSSHPacketSender::resetMac() { + is_mac_ = false; +} + +//============================================================================== +//FQTermSSHPacketReceiver +//============================================================================== + +FQTermSSHPacketReceiver::FQTermSSHPacketReceiver() { + buffer_ = new FQTermSSHBuffer(1024); + + is_decrypt_ = false; + cipher_type_ = SSH_CIPHER_NONE; + cipher_ = NULL; + setEncryptionType(SSH_CIPHER_3DES); + + is_mac_ = false; + mac_type_ = FQTERM_SSH_MAC_NONE; + mac_ = NULL; + + is_compressed_ = false; + + sequence_no_ = 0; +} + +FQTermSSHPacketReceiver::~FQTermSSHPacketReceiver() { + delete buffer_; + if (is_decrypt_) { + delete cipher_; + } +} + +void FQTermSSHPacketReceiver::getRawData(char *data, int length) { + buffer_->getRawData(data, length); +} + +u_char FQTermSSHPacketReceiver::getByte() { + return buffer_->getByte(); +} + +u_int FQTermSSHPacketReceiver::getInt() { + return buffer_->getInt(); +} + +void *FQTermSSHPacketReceiver::getString(int *length) { + return buffer_->getString(length); +} + +void FQTermSSHPacketReceiver::getBN(BIGNUM *bignum) { + buffer_->getSSH1BN(bignum); +} + +void FQTermSSHPacketReceiver::getBN2(BIGNUM *bignum) { + buffer_->getSSH2BN(bignum); +} + +void FQTermSSHPacketReceiver::consume(int len) { + buffer_->consume(len); +} + +void FQTermSSHPacketReceiver::setEncryptionType(int cipherType) { + cipher_type_ = cipherType; + + delete cipher_; + cipher_ = NULL; + + switch (cipher_type_) { + case SSH_CIPHER_3DES: + cipher_ = new FQTermSSH1DES3; + break; + } +} + +void FQTermSSHPacketReceiver::startEncryption(const u_char *key, const u_char *IV) { + is_decrypt_ = true; + cipher_->setIV(IV); + cipher_->setKey(key); +} + +void FQTermSSHPacketReceiver::resetEncryption() { + is_decrypt_ = false; +} + +void FQTermSSHPacketReceiver::setMacType(int macType) { + mac_type_ = macType; + delete mac_; + mac_ = NULL; + + switch (mac_type_) { + case FQTERM_SSH_HMAC_SHA1: + mac_ = new FQTermSSHSHA1; + break; + } +} + +void FQTermSSHPacketReceiver::startMac(const u_char *key) { + is_mac_ = true; + mac_->setKey(key); +} + +void FQTermSSHPacketReceiver::resetMac() { + is_mac_ = false; +} + +} // namespace FQTerm + +#include "fqterm_ssh_packet.moc" diff --git a/src/protocol/internal/fqterm_ssh_packet.h b/src/protocol/internal/fqterm_ssh_packet.h new file mode 100644 index 0000000..ed5a488 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_packet.h @@ -0,0 +1,148 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_PACKET_H +#define FQTERM_SSH_PACKET_H + +#include + +#include + +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_ssh_mac.h" +#include "fqterm_ssh_cipher.h" +#include "fqterm_serialization.h" + +namespace FQTerm { + +class FQTermSSHPacketSender: public QObject { + Q_OBJECT; + public: + FQTermSSHBuffer *output_buffer_; + FQTermSSHBuffer *buffer_; + + FQTermSSHPacketSender(); + virtual ~FQTermSSHPacketSender(); + + void startPacket(int pkt_type); + void putByte(int data); + void putInt(u_int data); + void putString(const char *string, int len = -1); + void putRawData(const char *data, int length); + void putBN(BIGNUM *bignum); + void putBN2(BIGNUM *bignum); + void write(); + + int getIVSize() const { return cipher_->getIVSize();} + int getKeySize() const { return cipher_->getKeySize();} + int getMacKeySize() const { return mac_->keySize();} + + public slots: + virtual void setEncryptionType(int cipherType); + void startEncryption(const u_char *key, const u_char *IV = NULL); + void resetEncryption(); + + void setMacType(int macType); + void startMac(const u_char *sessionkey); + void resetMac(); + + void enableCompress(int enable) {is_compressed_ = enable;}; + + signals: + void dataToWrite(); + + protected: + bool is_encrypt_; + int cipher_type_; + FQTermSSHCipher *cipher_; + + bool is_mac_; + int mac_type_; + FQTermSSHMac *mac_; + + bool is_compressed_; + + u_int32_t sequence_no_; + + virtual void makePacket() = 0; +}; + +class FQTermSSHPacketReceiver: public QObject { + Q_OBJECT; + public: + FQTermSSHBuffer *buffer_; + + FQTermSSHPacketReceiver(); + virtual ~FQTermSSHPacketReceiver(); + + int packetType()const { + return packet_type_; + } + + u_char getByte(); + u_int getInt(); + void *getString(int *length = NULL); + void getRawData(char *data, int length); + void getBN(BIGNUM *bignum); + void getBN2(BIGNUM *bignum); + void consume(int len); + + virtual int packetDataLen() const { return real_data_len_;} + int getIVSize() const { return cipher_->getIVSize();} + int getKeySize() const { return cipher_->getKeySize();} + int getMacKeySize() const { return mac_->keySize();} + + virtual void parseData(FQTermSSHBuffer *input) = 0; + public slots: + virtual void setEncryptionType(int cipherType); + void startEncryption(const u_char *key, const u_char *IV = NULL); + void resetEncryption(); + + void setMacType(int macType); + void startMac(const u_char *sessionkey); + void resetMac(); + + void enableCompress(int enable) {is_compressed_ = enable;}; + + signals: + void packetAvaliable(int type); + void packetError(QString); + + protected: + bool is_decrypt_; + int cipher_type_; + FQTermSSHCipher *cipher_; + + bool is_mac_; + int mac_type_; + FQTermSSHMac *mac_; + + bool is_compressed_; + + int packet_type_; + int real_data_len_; + + u_int32_t sequence_no_; +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_PACKET diff --git a/src/protocol/internal/fqterm_ssh_pubkey.h b/src/protocol/internal/fqterm_ssh_pubkey.h new file mode 100644 index 0000000..0de957c --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_pubkey.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_PUB_KEY_H +#define FQTERM_SSH_PUB_KEY_H + +#include + +namespace FQTerm { + +class FQTermSSHPubKey { +public: + FQTermSSHPubKey() {} + virtual ~FQTermSSHPubKey() {} + virtual void publicEncrypt(BIGNUM *, BIGNUM*) = 0; +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_PUB_KEY_H diff --git a/src/protocol/internal/fqterm_ssh_rsa.cpp b/src/protocol/internal/fqterm_ssh_rsa.cpp new file mode 100644 index 0000000..dd36898 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_rsa.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#include "fqterm_trace.h" +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_rsa.h" + +namespace FQTerm { + +FQTermSSHRSA::FQTermSSHRSA() { + d_rsa = RSA_new(); + d_rsa->n = BN_new(); + d_rsa->e = BN_new(); +} + +FQTermSSHRSA::~FQTermSSHRSA() { + if (d_rsa != NULL) { + RSA_free(d_rsa); + } +} + +void FQTermSSHRSA::publicEncrypt(BIGNUM *out, BIGNUM *in) { + u_char *inbuf, *outbuf; + int len, ilen, olen; + + if (BN_num_bits(d_rsa->e) < 2 || !BN_is_odd(d_rsa->e)) { + FQ_VERIFY(false); // public_encrypt() exponent too small or not odd. + } + + olen = BN_num_bytes(d_rsa->n); + outbuf = new u_char[olen]; + + ilen = BN_num_bytes(in); + inbuf = new u_char[ilen]; + BN_bn2bin(in, inbuf); + + if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, d_rsa, RSA_PKCS1_PADDING)) <= 0) { + //RSA_PKCS1_PADDING = 1 + FQ_VERIFY(false); // "rsa_public_encrypt() failed. + } + + BN_bin2bn(outbuf, len, out); + + delete [] outbuf; + delete [] inbuf; +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_rsa.h b/src/protocol/internal/fqterm_ssh_rsa.h new file mode 100644 index 0000000..bfe89ce --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_rsa.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_RSA_H +#define FQTERM_SSH_RSA_H + +#include + +#include "fqterm_ssh_pubkey.h" + +namespace FQTerm { + +class FQTermSSHRSA: public FQTermSSHPubKey { +public: + RSA *d_rsa; + FQTermSSHRSA(); + virtual ~FQTermSSHRSA(); + + virtual void publicEncrypt(BIGNUM *, BIGNUM*); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_RSA_H diff --git a/src/protocol/internal/fqterm_ssh_types.h b/src/protocol/internal/fqterm_ssh_types.h new file mode 100644 index 0000000..c10bfac --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_types.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_TYPES_H +#define FQTERM_SSH_TYPES_H + +#include +#if !defined(Q_OS_WIN32) && !defined(_OS_WIN32_) +#include +#else +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +#ifdef QT3_SUPPORT +typedef Q_UINT32 u_int32_t; +typedef Q_UINT64 u_int64_t; +#else +typedef quint32 u_int32_t; +typedef quint64 u_int64_t; +#endif // QT3_SUPPORT + +#endif // Q_OS_WIN32 + +#endif // FQTERM_SSH_TYPES_H diff --git a/src/terminal/CMakeLists.txt b/src/terminal/CMakeLists.txt new file mode 100644 index 0000000..c3cf3db --- /dev/null +++ b/src/terminal/CMakeLists.txt @@ -0,0 +1,46 @@ +set(export_SRCS + fqterm_buffer.h + fqterm_session.h + fqterm_text_line.h + fqterm_session.cpp + fqterm_buffer.cpp + fqterm_text_line.cpp +) + +set(internal_SRCS + internal/fqterm_decode.h + internal/fqterm_telnet.h + internal/fqterm_zmodem.h + internal/fqterm_decode.cpp + internal/fqterm_telnet.cpp + internal/fqterm_zmodem.cpp +) + +include_directories( + ${QT_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} + ${QT_QTGUI_INCLUDE_DIR} + ${QT_QTNETWORK_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/internal + ${CMAKE_CURRENT_SOURCE_DIR}/../common + ${CMAKE_CURRENT_SOURCE_DIR}/../utilities + ${CMAKE_CURRENT_SOURCE_DIR}/../protocol +) + +QT4_AUTOMOC( + ${export_SRCS} + ${internal_SRCS} +) + +add_library(fqterm_terminal + ${export_SRCS} + ${internal_SRCS} +) + +add_dependencies(fqterm_terminal + fqterm_common + fqterm_protocol + fqterm_utilities +) diff --git a/src/terminal/fqterm_buffer.cpp b/src/terminal/fqterm_buffer.cpp new file mode 100644 index 0000000..c00e079 --- /dev/null +++ b/src/terminal/fqterm_buffer.cpp @@ -0,0 +1,998 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include "fqterm.h" +#include "common.h" +#include "fqterm_buffer.h" +#include "fqterm_text_line.h" + +namespace FQTerm { + +typedef std::vector TabStops; + +/* staight from linux/drivers/char/consolemap.c, GNU GPL:ed */ +static const UTF16 VT_SPECIAL_GRAPHICS_TABLE[256]={ + /* VT100 graphics mapped to Unicode */ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0, + 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, + 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, + 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, + 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff +}; + +FQTermBuffer::FQTermBuffer(int column, int row, int max_hist_line, bool is_bbs) { + tab_stops_ = new TabStops; + num_rows_ = row; + num_columns_ = column; + max_num_hist_lines_ = max_hist_line; + is_bbs_ = is_bbs; + + num_hist_lines_ = 0; + + while (text_lines_.count() < num_rows_) { + text_lines_.append(new FQTermTextLine(num_columns_)); + } + + top_row_ = 0; + bottom_row_ = num_rows_ - 1; + + is_g0_used_ = true; + + is_insert_mode_ = false; + is_ansi_mode_ = true; + is_newline_mode_ = false; + is_cursor_mode_ = false; + is_numeric_mode_ = true; + is_origin_mode_ = false; + is_autowrap_mode_ = false; + is_autorepeat_mode_ = true; + is_lightbg_mode_ = false; + + selection_start_ = QPoint(-1, -1); + selection_end_ = QPoint(-1, -1); +} + +FQTermBuffer::~FQTermBuffer(){ + foreach(FQTermTextLine *line, text_lines_) { + delete line; + } + + delete (TabStops *)tab_stops_; +} + +FQTermBuffer::Caret::Caret() + : column_(0), + row_(0), + color_(NO_COLOR), + attr_(NO_ATTR), + G0_(ASCII_SET), + G1_(ASCII_SET) { +} + +void FQTermBuffer::setTermSize(int col, int row) { + FQ_TRACE("term", 3) << "Change term size to " + << col << "x" << row; + + if (num_columns_ == col && num_rows_ == row) { + return; + } + + clearSelect(); + + if (num_rows_ < row) { + for (int i = 0; i < row - num_rows_; i++) { + text_lines_.append(new FQTermTextLine(col)); + } + } else if (num_rows_ > row) { + for (int i = 0; i < num_rows_ - row; i++) { + delete text_lines_.takeLast(); + } + } + + num_columns_ = col; + num_rows_ = row; + + top_row_ = 0; + bottom_row_ = num_rows_ - 1; + + // TODO: how about saved caret column? + // TODO: why make last saved equal to current position? + last_saved_caret_.row_ = caret_.row_ = qMin(caret_.row_, row - 1); + + for (int i = 0; i < text_lines_.size(); ++i) { + text_lines_.at(i)->setMaxCellCount(num_columns_); + } + +// this->clearArea(0, 0, num_columns_, num_rows_, 0, 0); + // this->moveCaretTo(0, 0); + + moveCaretTo(qMin(caret_.column_, col - 1), qMin(caret_.row_, row - 1)); + + emit onSetTermSize(col, row); + emit termSizeChanged(num_columns_, num_rows_); +} + +int FQTermBuffer::getNumColumns() const { + return num_columns_; +} + +int FQTermBuffer::getNumRows() const { + return num_rows_; +} + +int FQTermBuffer::getNumLines() const { + return num_rows_ + num_hist_lines_; +} + +const FQTermTextLine *FQTermBuffer::getTextLineInBuffer(int line_index) const { + return text_lines_.value(line_index, NULL); +} + +const FQTermTextLine *FQTermBuffer::getTextLineInTerm(int line_index) const { + return text_lines_.value(line_index + num_hist_lines_, NULL); +} + +void FQTermBuffer::setCurrentAttr(unsigned char color, unsigned char attr) { + caret_.color_ = color; + caret_.attr_ = attr; +} + +void FQTermBuffer::writeText(const QString &str, int charstate) { + + QString cstr = str; + + FQ_TRACE("term", 8) << "Add text: \"" << cstr << "\""; + +#if 0 + if ((is_g0_used_ && caret_.G0_ == SPECIAL_GRAPHICS) || + (!is_g0_used_ && caret_.G1_ == SPECIAL_GRAPHICS)) { + + // FIXME: will this break the utf-16 sequence? + for (int i = 0; i < cstr.size(); ++i) { + if (cstr[i] >= 0137 && cstr[i] <= 0176) { + cstr[i] = VT_SPECIAL_GRAPHICS_TABLE[cstr.at(i).unicode()]; + } + } + } +#endif + + // Insert the str into the buffer. Different pieces of text might be + // written into different lines. + while (!cstr.isEmpty()) { + FQTermTextLine *line = text_lines_.value(num_hist_lines_ + caret_.row_, NULL); + + if (line == NULL) { + FQ_TRACE("error", 0) << "Error: setBuffer null line"; + return ; + } + + if (charstate & FQTermTextLine::SECONDPART) { + moveCaretOffset(-1, 0); + } + + if (caret_.column_ >= (int)line->getMaxCellCount()) { + // move the caret to the next line. + moveCaretTo(0, caret_.row_ + 1, true); + continue; + } + + if (caret_.column_ > (int)line->getWidth()) { + line->appendWhiteSpace(caret_.column_ - line->getWidth()); + } + + unsigned cell_begin = line->getCellBegin(caret_.column_); + int max_width = line->getMaxCellCount() - cell_begin; + int element_consumed = 0; + int width = get_str_width((const UTF16 *)cstr.data(), cstr.size(), + max_width, element_consumed); + + if (width < 0) { + break; + } + + if (is_insert_mode_) { + // FIXEME: How to move cursor if the entire line is wider than + // line->getMaxCellCount() after insertion? + line->insertText((UTF16 *)cstr.data(), element_consumed, cell_begin, + caret_.color_, caret_.attr_, charstate); + if ((int)line->getWidth() > num_columns_) { + line->deleteText(num_columns_, line->getWidth()); + } + } else { + line->replaceText((UTF16 *)cstr.data(), element_consumed, + cell_begin, qMin(cell_begin + width, line->getWidth()), + caret_.color_, caret_.attr_, charstate); + } + moveCaretOffset(width, 0); + + if (element_consumed == 0) + { + element_consumed = 1; + } + + if (element_consumed == cstr.size()) { + break; + } + + cstr.remove(0, element_consumed); + } +} + +void FQTermBuffer::lineFeed() { + FQ_TRACE("term", 8) << "add a new line"; + if (caret_.row_ == bottom_row_) + scrollLinesInTerm(top_row_, 1); + if (is_newline_mode_) { + moveCaretOffset(-caret_.column_, 1); + } else { + moveCaretOffset(0, 1); + } +} + +void FQTermBuffer::tab() { + FQ_TRACE("term", 8) << "add a tab"; + int x = getTabStop(caret_.column_); + + moveCaretTo(x, caret_.row_); +} + +int FQTermBuffer::getTabStop(int column) { + + std::vector &tabs = *(TabStops *)tab_stops_; + + if (tabs.size() == 0) { + int res = ((caret_.column_) / 8 + 1) * 8; + return (res < num_columns_) ? res : num_columns_ - 1; + } + + std::vector::iterator it = + std::upper_bound(tabs.begin(), tabs.end(), column); + + int res = num_columns_ - 1; + + if (it != tabs.end() && *it < res) { + res = *it; + } + + if (res > num_columns_ - 1) { + res = num_columns_ - 1; + } + + return res; +} + +void FQTermBuffer::addTabStop() { + // FIXME: what if the caret is located beyond the term temporarily. + int x = caret_.column_; + + std::vector &tabs = *(TabStops *)tab_stops_; + + std::vector::iterator it = + std::lower_bound(tabs.begin(), tabs.end(), x); + + if (it == tabs.end() || *it != x) { + tabs.insert(it, x); + } +} + +void FQTermBuffer::clearTabStop(bool clear_all) { + // FIXME: what if the caret is located beyond the term temporarily. + std::vector &tabs = *(TabStops *)tab_stops_; + + if (clear_all) { + tabs.clear(); + return; + } + + int x = caret_.column_; + + std::vector::iterator it = + std::lower_bound(tabs.begin(), tabs.end(), x); + + if (it != tabs.end() && *it == x) { + tabs.erase(it); + } +} + +void FQTermBuffer::setMargins(int top, int bottom) { + FQ_TRACE("term", 3) << "Set margins: [" << top << ", " << bottom << "]"; + + top_row_ = qMax(top, 0); + bottom_row_ = qMin(qMax(bottom, 0), num_rows_ - 1); + + if (is_origin_mode_) { + moveCaretTo(0, top_row_); + } else { + moveCaretTo(0, 0); + } +} + +void FQTermBuffer::moveCaretTo(int column, int row, bool scroll_if_necessary) { + if (row != caret_.row_) + emit caretChangeRow(); + + FQ_TRACE("term", 5) << "Move caret to (" << column << ", " << row << ")"; + + //If th + + // detect index boundary + if (column >= num_columns_) { + column = num_columns_; + } + if (column < 0) { + column = 0; + } + + int scroll_lines = 0; + + int stop = is_origin_mode_ ? top_row_ : 0; + if (row < stop) { + scroll_lines = row - stop; + row = stop; + } + + stop = is_origin_mode_ ? bottom_row_ : num_rows_ - 1; + if (row > stop) { + scroll_lines = row - stop; + row = stop; + } + + // Set dirty flag for cells of the last caret position. + FQTermTextLine *line = text_lines_.value(num_hist_lines_ + caret_.row_, NULL); + if (0 <= caret_.column_ && caret_.column_ < (int)line->getWidth()) { + unsigned cell_begin = line->getCellBegin(caret_.column_); + unsigned cell_end = line->getCellBegin(caret_.column_ + 1); + line->setDirtyFlag(cell_begin, cell_end); + } + + if (scroll_if_necessary) { + scrollLinesInTerm(top_row_, scroll_lines); + } + + caret_.column_ = column; + caret_.row_ = row; +} + +void FQTermBuffer::moveCaretOffset(int column_offset, int row_offset, bool scroll_if_necessary) { + if (caret_.column_ >= num_columns_) { + // it's only allowed that the caret_.column_ >= num_columns_ + // temporarily when a sequence of normal text is received. if we + // found caret_.column_ is out of bounds in other case, we should + // correct it first. + if (is_bbs_) { + // but the BBS (newsmth.net) assumes that the caret could be + // located out of the screen :( + } else { + caret_.column_ = num_columns_ - 1; + } + } + + if (caret_.column_ + column_offset < 0) { + column_offset = -caret_.column_; + } + + moveCaretTo(caret_.column_ + column_offset, caret_.row_ + row_offset, + scroll_if_necessary); +} + +void FQTermBuffer::changeCaretPosition(int coloumn, int row) { + if (is_origin_mode_) { + moveCaretTo(coloumn, row + top_row_); + } else { + moveCaretTo(coloumn, row); + } +} + +void FQTermBuffer::saveCaret() { + FQ_TRACE("term", 5) << "save the caret."; + last_saved_caret_ = caret_; +} + +void FQTermBuffer::restoreCaret() { + FQ_TRACE("term", 5) << "restore the caret."; + moveCaretTo(last_saved_caret_.column_, last_saved_caret_.row_); + caret_ = last_saved_caret_; +} + +void FQTermBuffer::SelectVtCharacterSet(VtCharSet charset, bool G0) { + if (G0) { + caret_.G0_ = charset; + } else { + caret_.G1_ = charset; + } +} + +void FQTermBuffer::invokeCharset(bool G0) { + if (G0) { + is_g0_used_ = true; + } else { + is_g0_used_ = false; + } +} + +void FQTermBuffer::carriageReturn() { + FQ_TRACE("term", 8) << "carrige return"; + moveCaretOffset(-caret_.column_, 0); +} + +int FQTermBuffer::getCaretColumn() const { + return caret_.column_; +} + +int FQTermBuffer::getCaretRow() const { + return caret_.row_; +} + +int FQTermBuffer::getCaretLine() const { + return caret_.row_ + num_hist_lines_; +} + +// erase functions +void FQTermBuffer::eraseText(int cell_count) { + FQ_TRACE("term", 8) << "erase " << cell_count << " cell(s) of text"; + + const FQTermTextLine *line = text_lines_.at(caret_.row_ + num_hist_lines_); + + int x = line->getWidth() - caret_.column_; + + clearArea(caret_.column_, caret_.row_, + qMin(cell_count, x), 1, + caret_.color_, caret_.attr_); +} + +void FQTermBuffer::deleteText(int cell_count) { + FQ_TRACE("term", 8) << "delete " << cell_count << " cell(s) of text"; + + FQTermTextLine *line = text_lines_.at(caret_.row_ + num_hist_lines_); + + int x = line->getWidth() - caret_.column_; + + if (cell_count >= x) { + line->deleteText(caret_.column_, line->getWidth()); + } else { + line->deleteText(caret_.column_, caret_.column_ + cell_count); + } +} + +void FQTermBuffer::fillScreenWith(char c) { + FQ_TRACE("term", 5) << "fill screen with '" << c << "'"; + for (int i = 0; i < num_rows_; i++) { + FQTermTextLine *line = text_lines_[i + num_hist_lines_]; + line->deleteAllText(); + line->appendWhiteSpace(num_columns_, NO_COLOR, NO_ATTR, c); + } +} + +void FQTermBuffer::insertSpaces(int count) { + FQ_TRACE("term", 8) << "insert " << count << " white space(s)"; + + FQTermTextLine *line = text_lines_.at(caret_.row_ + num_hist_lines_); + + int x = line->getWidth() - caret_.column_; + + if (count >= x) { + clearArea(caret_.column_, caret_.row_, x, caret_.row_, + caret_.color_, caret_.attr_); + } else { + line->insertWhiteSpace(count, caret_.column_, caret_.color_, caret_.attr_); + } +} + +void FQTermBuffer::deleteLines(int line_count) { + FQ_TRACE("term", 8) << "delete " << line_count << " line(s)"; + + int y = bottom_row_ - caret_.row_; + + if (line_count >= y) { + clearArea(0, caret_.row_, -1, y, caret_.color_, caret_.attr_); + } else { + scrollLinesInTerm(caret_.row_, line_count); + } +} + +void FQTermBuffer::insertLines(int count) { + FQ_TRACE("term", 8) << "insert " << count << " line(s)"; + + int y = bottom_row_ - caret_.row_; + + if (count >= y) { + clearArea(0, caret_.row_, -1, y, caret_.color_, caret_.attr_); + } else { + scrollLinesInTerm(caret_.row_, -count); + } +} + +void FQTermBuffer::eraseToLineEnd() { + FQ_TRACE("term", 8) << "erase to line end"; + + clearArea(caret_.column_, caret_.row_, -1, 1, caret_.color_, caret_.attr_); +} + +void FQTermBuffer::eraseToLineBegin() { + FQ_TRACE("term", 8) << "erase to line begin"; + clearArea(0, caret_.row_, caret_.column_ + 1, 1, caret_.color_, caret_.attr_); +} + +void FQTermBuffer::eraseEntireLine() { + FQ_TRACE("term", 8) << "erase entire line"; + clearArea(0, caret_.row_, -1, 1, caret_.color_, caret_.attr_); +} + +// Set a line of text on screen to have been changed from start to end. +void FQTermBuffer::setLineChanged(int index, int cell_begin, int cell_end) { + FQ_ASSERT(0 <= index && index < num_rows_ + num_hist_lines_); + text_lines_[index]->setDirtyFlag(cell_begin, cell_end); +} + +void FQTermBuffer::clearLineChanged(int index) { + FQ_ASSERT(0 <= index && index < num_rows_ + num_hist_lines_); + text_lines_[index]->clearDirtyFlag(); +} + +void FQTermBuffer::setLineAllChanged(int index) { + FQ_ASSERT(0 <= index && index < num_rows_ + num_hist_lines_); + text_lines_[index]->setAllDirty(); +} + +void FQTermBuffer::scrollLinesInTerm(int startRow, int numRows) { + if (numRows == 0 || startRow > bottom_row_) { + return ; + } + if (startRow < top_row_) { + startRow = top_row_; + } + + // TODO: performance issue here. Reuse the old text lines. + if (numRows > 0) { + //We are scrolling the whole screen. + if (startRow == 0 && caret_.row_ == num_rows_ - 1) { + addHistoryLine(numRows); + } else { + // delete lines from startRow, insert lines on the bottom_row_. + while (numRows) { + delete text_lines_.takeAt(num_hist_lines_ + startRow); + text_lines_.insert(num_hist_lines_ + bottom_row_, new FQTermTextLine(num_columns_)); + numRows--; + } + } + } + + // TODO: performance issue here. Reuse the old text lines. + if (numRows < 0) { + // delete lines from bottom_row_, insert lines in the startRow. + while (numRows) { + delete text_lines_.takeAt(num_hist_lines_ + bottom_row_); + text_lines_.insert(num_hist_lines_ + startRow, new FQTermTextLine(num_columns_)); + numRows++; + } + } + + for (int i = num_hist_lines_ + startRow; i <= num_hist_lines_ + bottom_row_; i++) { + text_lines_.at(i)->setAllDirty(); + } +} + +void FQTermBuffer::eraseToTermEnd() { + FQ_TRACE("term", 8) << "erase to term end"; + + if (caret_.column_ == 0 && caret_.row_ == 0) { + eraseEntireTerm(); + return ; + } + + clearArea(caret_.column_, caret_.row_, -1, 1, caret_.color_, caret_.attr_); + + if (caret_.row_ < bottom_row_) { + clearArea(0, caret_.row_ + 1, + -1, bottom_row_ - caret_.row_, + caret_.color_, caret_.attr_); + } +} + +void FQTermBuffer::eraseToTermBegin() { + FQ_TRACE("term", 8) << "erase to term begin"; + if (caret_.column_ == num_columns_ - 1 && caret_.row_ == num_rows_ - 1) { + eraseEntireTerm(); + return ; + } + + clearArea(0, caret_.row_, caret_.column_ + 1, 1, caret_.color_, caret_.attr_); + if (caret_.row_ > top_row_) { + clearArea(0, top_row_, -1, caret_.row_, caret_.color_, caret_.attr_); + } +} + +void FQTermBuffer::eraseEntireTerm() { + FQ_TRACE("term", 8) << "erase entire term"; + addHistoryLine(num_rows_); + clearArea(0, 0, num_columns_, num_rows_, caret_.color_, caret_.attr_); +} + +// width = -1 : clear to end +void FQTermBuffer::clearArea(int startColumn, int startRow, + int width, int height, + unsigned char color, unsigned char attr) { + QByteArray cstr; + + FQTermTextLine *line; + + if (startRow + height > num_rows_) { + height = num_rows_ - startRow; + } + + for (int i = startRow; i < height + startRow; i++) { + line = text_lines_[i + num_hist_lines_]; + + int w = width; + + if (startColumn < num_columns_) { + if (w == -1) { + w = num_columns_ - startColumn; + } + + int endX = startColumn + w; + if (endX > (int)line->getWidth()) { + endX = line->getWidth(); + } + + if(startColumn>=endX) + { + continue; + } + + line->replaceWithWhiteSpace(w, startColumn, endX, color, attr); + } + } +} + +void FQTermBuffer::addHistoryLine(int n) { + bool is_full = (num_hist_lines_ == max_num_hist_lines_); + + // TODO: performance issue. Reuse the old lines. + while (n) { + if (num_hist_lines_ == max_num_hist_lines_) { + delete text_lines_.takeFirst(); + } + + text_lines_.append(new FQTermTextLine(num_columns_)); + num_hist_lines_ = qMin(num_hist_lines_ + 1, max_num_hist_lines_); + n--; + } + + for (int i = num_hist_lines_ + 0; i < num_hist_lines_ + bottom_row_; i++) { + text_lines_.at(i)->setAllDirty(); + } + + if (!is_full) { + emit bufferSizeChanged(); + } +} + +void FQTermBuffer::startDecode() { + last_saved_caret_.column_ = caret_.column_; + last_saved_caret_.row_ = caret_.row_; +} + +void FQTermBuffer::endDecode() { + if (last_saved_caret_.row_ < num_rows_) { + FQTermTextLine *line = text_lines_[last_saved_caret_.row_ + num_hist_lines_]; + + line->safelySetDirtyFlag(last_saved_caret_.column_, + last_saved_caret_.column_ + 1); + } + + if (caret_.row_ < num_rows_) { + FQTermTextLine *line = text_lines_.at(caret_.row_ + num_hist_lines_); + + line->safelySetDirtyFlag(caret_.column_, caret_.column_ + 1); + } + + clearSelect(); +} + +void FQTermBuffer::setMode(TermMode mode) { + FQ_TRACE("term", 8) << "set mode " << mode; + + switch (mode) { + case INSERT_MODE: + is_insert_mode_ = true; + break; + case CURSOR_MODE: + is_cursor_mode_ = true; + break; + case ANSI_MODE: + is_ansi_mode_ = true; + case NUMERIC_MODE: + is_numeric_mode_ = true; + break; + case SMOOTH_MODE: + is_smoothscroll_mode_ = true; + break; + case NEWLINE_MODE: + is_newline_mode_ = true; + break; + case ORIGIN_MODE: + is_origin_mode_ = true; + this->moveCaretTo(0, top_row_); + break; + case AUTOWRAP_MODE: + is_autowrap_mode_ = true; + break; + case AUTOREPEAT_MODE: + is_autorepeat_mode_ = true; + break; + case LIGHTBG_MODE: + is_lightbg_mode_ = true; + break; + default: + break; + } +} + +void FQTermBuffer::resetMode(TermMode mode) { + FQ_TRACE("term", 8) << "reset mode " << mode; + + switch (mode) { + case INSERT_MODE: + is_insert_mode_ = false; + break; + case CURSOR_MODE: + is_cursor_mode_ = false; + break; + case ANSI_MODE: + is_ansi_mode_ = false; + case NUMERIC_MODE: + is_numeric_mode_ = false; + break; + case SMOOTH_MODE: + is_smoothscroll_mode_ = false; + break; + case NEWLINE_MODE: + is_newline_mode_ = false; + break; + case ORIGIN_MODE: + is_origin_mode_ = false; + this->moveCaretTo(0, 0); + break; + case AUTOWRAP_MODE: + is_autowrap_mode_ = false; + break; + case AUTOREPEAT_MODE: + is_autorepeat_mode_ = false; + break; + case LIGHTBG_MODE: + is_lightbg_mode_ = false; + break; + default: + break; + } +} + +void FQTermBuffer::setSelect(const QPoint &pt1, const QPoint &pt2) { + QPoint ptSelStart, ptSelEnd; + + if (pt1.y() == pt2.y()) { + ptSelStart = pt1.x() < pt2.x() ? pt1 : pt2; + ptSelEnd = pt1.x() > pt2.x() ? pt1 : pt2; + } else { + ptSelStart = pt1.y() < pt2.y() ? pt1 : pt2; + ptSelEnd = pt1.y() > pt2.y() ? pt1 : pt2; + } + + int y1 = ptSelStart.y(); + int y2 = ptSelEnd.y(); + + if (!(selection_start_ == QPoint(-1, -1) + && selection_end_ == QPoint(-1, -1))) { + y1 = qMin(y1, selection_start_.y()); + y2 = qMax(y2, selection_end_.y()); + } + + for (int i = y1; i <= y2; i++) { + text_lines_.value(i, NULL)->setAllDirty(); + } + + selection_start_ = ptSelStart; + selection_end_ = ptSelEnd; +} + +void FQTermBuffer::clearSelect() { + if (selection_start_ == QPoint(-1, -1) && selection_end_ == QPoint(-1, -1)) { + return; + } + + for (int i = selection_start_.y(); i <= selection_end_.y(); i++) { + text_lines_.value(i, NULL)->setAllDirty(); + } + + selection_start_ = selection_end_ = QPoint(-1, -1); +} + +bool FQTermBuffer::isSelected(int line_index) const { + if (selection_start_ == QPoint(-1, -1) && selection_end_ == QPoint(-1, -1)) { + return false; + } else { + return line_index >= selection_start_.y() && line_index <= selection_end_.y(); + } +} + +bool FQTermBuffer::isSelected(const QPoint &cell, bool is_rect_sel) const { + if (selection_start_ == QPoint(-1, -1) && selection_end_ == QPoint(-1, -1)) { + return false; + } + + if (cell.y() < 0 || cell.y() >= getNumLines()) { + return false; + } + + int x1 = selection_start_.x(); + int y1 = selection_start_.y(); + + int x2 = selection_end_.x(); + int y2 = selection_end_.y(); + + if (cell.y() < y1 || cell.y() > y2) + return false; + + const FQTermTextLine *line = this->getTextLineInBuffer(cell.y()); + + int cell_begin = 0; + int cell_end = cell.x() + 1; + + if (is_rect_sel) { + int minx = qMin(x1, x2); + int maxx = qMax(x1, x2); + cell_begin = line->getCellBegin(qMin(minx, (int)line->getWidth())); + cell_end = line->getCellEnd(qMin(maxx + 1, (int)line->getWidth())); + } else { + if (cell.y() == y1) { + cell_begin = line->getCellBegin(qMin(x1, (int)line->getWidth())); + } + if (cell.y() == y2) { + cell_end = line->getCellEnd(qMin(x2 + 1, (int)line->getWidth())); + } + } + + return cell_begin <= cell.x() && cell.x() < cell_end; +} + +static void removeTrailSpace(QString &line) { + for (int last_non_space = line.size() - 1; + last_non_space >= 0; --last_non_space) { + QChar a = line.at(last_non_space); + if (!a.isSpace()) { + line.resize(last_non_space + 1); + break; + } + + if (last_non_space == 0) { + line.resize(0); + } + } +} + + +QString FQTermBuffer::getTextSelected(bool is_rect_sel, bool is_color_copy, + const QByteArray &escape) const { + QString cstrSelect; + QString strTemp; + + if (selection_start_ == QPoint(-1, -1) && selection_end_ == QPoint(-1, -1)) { + return cstrSelect; + } + + QRect rc; + + for (int i = selection_start_.y(); i <= selection_end_.y(); i++) { + strTemp.clear(); + rc = getSelectRect(i, is_rect_sel); + + FQTermTextLine *line = text_lines_.at(i); + unsigned cell_begin = qMax(rc.left(), 0); + unsigned cell_end = qMin(rc.right() + 1, (int)line->getWidth()); + FQ_ASSERT(rc.left() + rc.width() == rc.right() + 1); + + if (cell_begin < cell_end) { + cell_begin = line->getCellBegin(cell_begin); + cell_end = line->getCellEnd(cell_end); + + if (is_color_copy) { + line->getAnsiText(cell_begin, cell_end, strTemp, escape); + } else { + line->getPlainText(cell_begin, cell_end, strTemp); + } + } + + removeTrailSpace(strTemp); + + cstrSelect += strTemp; + + // add newline except the last line + if (i != selection_end_.y()) { + cstrSelect += OS_NEW_LINE; + } + } + + return cstrSelect; +} + +QRect FQTermBuffer::getSelectRect(int line_index, bool is_rect_sel) const { + FQ_ASSERT(isSelected(line_index)); + + if (is_rect_sel) { + return QRect(qMin(selection_start_.x(), selection_end_.x()), line_index, + abs(selection_end_.x() - selection_start_.x()) + 1, 1); + } else if (selection_start_.y() == selection_end_.y()) { + return QRect(selection_start_.x(), line_index, + qMin(selection_end_.x(), num_columns_) - selection_start_.x() + 1, 1); + } else if (line_index == selection_start_.y()) { + return QRect(selection_start_.x(), line_index, + qMax(0, num_columns_ - selection_start_.x()), 1); + } else if (line_index == selection_end_.y()) { + return QRect(0, line_index, qMin(num_columns_, selection_end_.x() + 1), 1); + } else { + return QRect(0, line_index, num_columns_, 1); + } +} + +void FQTermBuffer::scrollTerm(int numRows) { + scrollLinesInTerm(caret_.row_, numRows); + moveCaretOffset(0, numRows); +} + + +} // namespace FQTerm + +#include "fqterm_buffer.moc" diff --git a/src/terminal/fqterm_buffer.h b/src/terminal/fqterm_buffer.h new file mode 100644 index 0000000..3e0ef6a --- /dev/null +++ b/src/terminal/fqterm_buffer.h @@ -0,0 +1,297 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_BUFFER_H +#define FQTERM_BUFFER_H + +#include +#include +#include + +#include "fqterm_text_line.h" +class QString; +class QByteArray; +class QRect; + +namespace FQTerm { + +class FQTermTextLine; + +/* Text buffer consists of characters in a matrix of cells. + * + * Buffer + * +--------------------------------+ + * ||----> | + * || x | + * || | + * |V Y | + * | | + * . . + * . . + * . histroical lines . + * . . + * . . + * | | + * | | + * | | + * | | + * |+------------------------------+| + * |||----> || + * ||| x || + * ||| terminal || + * ||V Y || + * || || + * || || + * || | (caret) || + * || || + * || || + * |+------------------------------+| + * +--------------------------------+ + * + * Text buffer, to manage lines of characters with colors and + * attributes, caret positions, terminal size/margins, selection + * region, historical text lines, buffer write mode (insert or + * replace), and etc. + * + * Note: There are two coordinates, relative to terminal or entire + * buffer. When we use (column, row) it indicates terminal coordinate, + * while when we use (column, line) it indicates buffer coordinate. + * This rule applies both in variable names and function names. + **/ +class FQTermBuffer: public QObject { + Q_OBJECT; + public: + enum TermMode { + INSERT_MODE, /* otherwise replace mode */ + ANSI_MODE, /* otherwise VT52 mode */ + SMOOTH_MODE, /* otherwse jump mode */ + NEWLINE_MODE, /* otherwise line feed mode */ + CURSOR_MODE, /* otherwise reset cursor mode */ + NUMERIC_MODE, /* otherwise application mode */ + ORIGIN_MODE, /* otherwise absolute mode */ + AUTOWRAP_MODE, /* otherwise non-autowrap mode */ + AUTOREPEAT_MODE, /* otherwise non-autorepeat mode */ + LIGHTBG_MODE, /* otherwise dark background mode */ + }; + + enum VtCharSet { + UNITED_KINGDOM_SET, + ASCII_SET, + SPECIAL_GRAPHICS, + ALTERNATE_CHARACTER_ROM_STANDARD_CHARACTER_SET, + ALTERNATE_CHARACTER_ROM_SPECIAL_GRAPHICS + }; + + FQTermBuffer(int column, int row, int max_hist_line, bool is_bbs); + ~FQTermBuffer(); + + // Get text lines. + // Return null if the line_index is out of bound, return NULL. + const FQTermTextLine *getTextLineInBuffer(int line_index) const; + const FQTermTextLine *getTextLineInTerm(int line_index) const; + + // Get number of columns and rows of the term, or lines of the + // entire buffer. + int getNumColumns() const; + int getNumRows() const; + int getNumLines() const; + + // Set the size of the screen. + void setTermSize(int col, int row); + // set margins in term. (Generally speaking, most operations are + // restrictied in [top_row_, bottom_row_] of terminal.) + void setMargins(int top_row, int bottom_row); + + // the caret's coordinate in term or buffer. + int getCaretColumn() const; + int getCaretRow() const; + int getCaretLine() const; + + // Set current attribute. + void setCurrentAttr(unsigned char color, unsigned char attr); + + // Below are a series of functions to modify the content of buffer. + // These functions will work from the current caret position. + // All the behaviours of these functions may be influenced by the + // mode of this buffer (is_insert_mode_, is_newline_mode_, and + // etc.). + + void writeText(const QString &cstr, int charstate = FQTermTextLine::NORMAL); + + void fillScreenWith(char c); + + void insertSpaces(int count); + void insertLines(int count); + + void deleteText(int cell_count); + void deleteLines(int line_count); + + void eraseText(int cell_count); + + void eraseToLineBegin(); + void eraseToLineEnd(); + void eraseEntireLine(); + + void eraseToTermBegin(); + void eraseToTermEnd(); + void eraseEntireTerm(); + + // Set a line of buffer to have been changed from start to end. + void setLineChanged(int index, int cell_begin, int cell_end); + void clearLineChanged(int index); + void setLineAllChanged(int index); + + // Functions about caret. + // If the caret is moved, the cells of the position of the last caret will + // be marked as changed. + void moveCaretOffset(int coloumn_offset, int row_offset, + bool scroll_if_necessary = false); + void moveCaretTo(int coloumn, int row, bool scroll_if_necessary = false); + void changeCaretPosition(int coloumn, int row); + void saveCaret(); + void restoreCaret(); + + void SelectVtCharacterSet(VtCharSet charset, bool G0); + void invokeCharset(bool G0); + + // non-printing characters + void tab(); + void carriageReturn(); + void lineFeed(); + + void addTabStop(); + void clearTabStop(bool clear_all); + + // Select Mode (SM) and Reset Mode (RM) functions. + // See ANSI X3.64 Mode-Changing Parameters. + void setMode(TermMode); + void resetMode(TermMode); + + bool isCursorMode() const { return is_cursor_mode_; } + bool isAnsiMode() const { return is_ansi_mode_; } + bool isNumericMode() const { return is_numeric_mode_; } + bool isAutoRepeatMode() const { return is_autorepeat_mode_; } + bool isLightBackgroundMode() const { return is_lightbg_mode_; } + bool isNewLineMode() const {return is_newline_mode_;} + + // for test + void startDecode(); + void endDecode(); + + // Functions about selection in buffer. + void setSelect(const QPoint &start_point, const QPoint &end_point); + void clearSelect(); + bool isSelected(const QPoint &cell, bool isRectSel) const; + bool isSelected(int line_index) const; + + QString getTextSelected(bool is_rect_sel, bool is_color_copy, + const QByteArray &escape) const; + + // Get the rectangle of selected text of a certain line in buffer. + // Note: please ensure there exits any cell of the line line_index + // is selected. + QRect getSelectRect(int line_index, bool is_rect_sel) const; + + //Scroll line && adjust caret pos. + //Scroll must occur at the line where caret is + void scrollTerm(int numRows); + + signals: + void bufferSizeChanged(); + void termSizeChanged(int column, int row); + void onSetTermSize(int col, int row); + void caretChangeRow(); + private: + // Scroll lines between startRow and bottom_row_ (see setMargin()). + // num > 0 scroll up. + // num < 0 scroll down. + void scrollLinesInTerm(int startRow, int numRows); + + // Replace a area of cells with spaces. + void clearArea(int startColumn, int startRow, + int width, int height, + unsigned char color, unsigned char attr); + + // Append n empty lines to the buffer and make the first n lines of + // term historical. + void addHistoryLine(int n); + + int getTabStop(int column); + + struct Caret { + int column_, row_; + int color_, attr_; + VtCharSet G0_, G1_; + + Caret(); + }; + + // terminal size. + int num_columns_, num_rows_; + + // term margins. (Generally speaking, most operations are + // restrictied in [top_row_, bottom_row_] of terminal.) + int top_row_, bottom_row_; + + // Historical data length and max length. + int num_hist_lines_, max_num_hist_lines_; + + // All lines of text, including both historical lines and lines in + // current terminal. + // + // Note: the number of historical lines, num_hist_lines, may + // increase from 0 to max_num_hist_lines_. + QList text_lines_; + + void *tab_stops_; + + // The caret in terminal + Caret caret_; + Caret last_saved_caret_; + + bool is_g0_used_; // is G0 or G1 charset used; + + bool is_insert_mode_; // Is insert or replace mode. + bool is_ansi_mode_; // Is ansi or vt52 mode. + bool is_smoothscroll_mode_; // Is smooth or jump scrolling mode. + bool is_newline_mode_; // Is newline or linefeed mode. + bool is_cursor_mode_; // Is cursor key mode. + bool is_numeric_mode_; // Is numeric or application mode. + bool is_origin_mode_; // Is origin or absolute mode. + bool is_autowrap_mode_; // Is auto-wrap mode enabled. + bool is_autorepeat_mode_; // Is auto-repeat mode enabled. + bool is_lightbg_mode_; // Is ligth background or dark backgrond mode. + + // Selection in buffer. If section start and end are in the same + // line, start.x should be equal to or less than end.x. Otherwise + // start.y should be less than end.y. + // + // If selection_start_ = selection_start_ = (-1, -1), the selection + // is empty. + QPoint selection_start_; + QPoint selection_end_; + + // whether this buffer is used for a bbs session. + bool is_bbs_; +}; + +} // namespace FQTerm + +#endif // FQTERM_BUFFER_H diff --git a/src/terminal/fqterm_session.cpp b/src/terminal/fqterm_session.cpp new file mode 100644 index 0000000..6c5b513 --- /dev/null +++ b/src/terminal/fqterm_session.cpp @@ -0,0 +1,1648 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm.h" +#include "common.h" +#include "fqterm_trace.h" +#include "fqterm_session.h" +#include "fqterm_buffer.h" +#include "fqterm_text_line.h" +#include "fqterm_telnet.h" +#include "fqterm_decode.h" +#include "fqterm_zmodem.h" + +#ifdef HAVE_PYTHON +#include +#endif //HAVE_PYTHON + +#ifndef WIN32 +#include +#else +#include +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace FQTerm { + +const QString FQTermSession::endOfUrl[] = { + "ac","ad","ae","af","ag","ai","al","am","an","ao","aq","ar","as","at", + "au","aw","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bm","bn","bo","br", + "bs","bt","bv","bw","by","bz","ca","cc","cd","cf","cg","ch","ci","ck","cl","cm", + "cn","co","uk","com","cr","cs","cu","cv","cx","cy","cz","de","dj","dk","dm", + "do","dz","ec","edu","ee","eg","eh","er","es","et","fi","fj","fk","fm","fo", + "fr","ga","gd","ge","gf","gg","gh","gi","gl","gm","gn","gov","gp","gq","aero", + "asia","biz","coop","eu","info","museum","name","pro","travel","gr","gs","gt", + "gu","gw","gy","hk","hm","hn","hr","ht","hu","id","ie","il","im","in","int", + "io","iq","ir","is","it","je","jm","jo","jp","ke","kg","kh","ki","km","kn","kp", + "kr","kw","ky","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma", + "mc","md","mg","mh","mil","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt", + "mu","mv","mw","mx","my","mz","na","nc","ne","net","nf","ng","ni","nl","no", + "np","nr","nt","nu","nz","om","org","pa","pe","pf","pg","ph","pk","pl","pm", + "pn","pr","ps","pt","pw","py","qa","re","ro","ru","rw","sa","sb","sc","sd","se", + "sg","sh","si","sj","sk","sl","sm","sn","so","sr","sv","st","sy","sz","tc","td", + "tf","tg","th","tj","tk","tm","tn","to","tp","tr","tt","tv","tw","tz","ua","ug", + "uk","um","us","uy","uz","va","vc","ve","vg","vi","vn","vu","wf","ws","ye","yt", + "yu","za","zm","zw" +}; + +FQTermSession::FQTermSession(FQTermConfig *config, FQTermParam param) { + reconnectRetry_ = 0; + scriptListener_ = NULL; + param_ = param; + termBuffer_ = new FQTermBuffer(param_.numColumns_, + param_.numRows_, + param_.numScrollLines_, + param_.hostType_ == 0); + + if (param.protocolType_ == 0) { + telnet_ = new FQTermTelnet(param_.virtualTermType_.toLatin1(), + param_.numRows_, param_.numColumns_, param.protocolType_, param.hostType_ ); + } else if (param.protocolType_ == 3) { + telnet_ = new FQTermTelnet(param_.virtualTermType_.toLatin1(), + param_.numRows_, param_.numColumns_, param.protocolType_, param.hostType_ ); + } else { +#if defined(_NO_SSH_COMPILED) + QMessageBox::warning(this, "sorry", + "SSH support is not compiled, " + "FQTerm can only use Telnet!"); + telnet_ = new FQTermTelnet(param_.virtualTermType_.toUtf8(), + param_.numRows_, param_.numColumns_, param.protocolType_, param.hostType_ ); +#else + telnet_ = new FQTermTelnet(param_.virtualTermType_.toUtf8(), + param_.numRows_, param_.numColumns_, param.protocolType_ , param.hostType_ , + param_.sshUserName_.toUtf8(), + param_.sshPassword_.toUtf8()); +#endif + } + + zmodem_ = new FQTermZmodem(config, telnet_, param.protocolType_, param.serverEncodingID_); + decoder_ = new FQTermDecode(termBuffer_, param.serverEncodingID_); + FQ_VERIFY(connect(decoder_, SIGNAL(enqReceived()), this, SLOT(onEnqReceived()))); + FQ_VERIFY(connect(decoder_, SIGNAL(onTitleSet(const QString&)), this, SIGNAL(onTitleSet(const QString&)))); + + isConnected_ = false; +#ifndef _NO_SSH_COMPILED + if (param.protocolType_ != 0) { + isSSHLogining_ = true; + } else { + isSSHLogining_ = false; + } +#else + isSSHLogining_ = false; +#endif + isTelnetLogining_ = false; + isIdling_ = false; + isSendingMessage_ = false; + isMouseX11_ = false; + + idleTimer_ = new QTimer; + autoReplyTimer_ = new QTimer; + + acThread_ = new ArticleCopyThread(*this, waitCondition_, bufferWriteLock_); + + FQ_VERIFY(connect(decoder_, SIGNAL(mouseMode(bool)), + this, SLOT(setMouseMode(bool)))); + FQ_VERIFY(connect(telnet_, SIGNAL(readyRead(int, int)), + this, SLOT(readReady(int, int)))); + FQ_VERIFY(connect(telnet_, SIGNAL(TelnetState(int)), + this, SLOT(changeTelnetState(int)))); + FQ_VERIFY(connect(telnet_, SIGNAL(errorMessage(QString)), + this, SIGNAL(errorMessage(QString)))); + FQ_VERIFY(connect(telnet_, SIGNAL(requestUserPwd(QString*, QString*, bool*)), + this, SIGNAL(requestUserPwd(QString*, QString*, bool*)))); + + FQ_VERIFY(connect(telnet_, SIGNAL(onSSHAuthOK()), + this, SLOT(onSSHAuthOK()))); + + + + FQ_VERIFY(connect(termBuffer_, SIGNAL(onSetTermSize(int, int)), + telnet_, SLOT(windowSizeChanged(int, int)))); + + FQ_VERIFY(connect(zmodem_, SIGNAL(ZmodemState(int, int, const char *)), + this, SIGNAL(zmodemStateChanged(int, int, const char *)))); + + FQ_VERIFY(connect(idleTimer_, SIGNAL(timeout()), this, SLOT(onIdle()))); + FQ_VERIFY(connect(autoReplyTimer_, SIGNAL(timeout()), + this, SLOT(onAutoReply()))); + + FQ_VERIFY(connect(acThread_, SIGNAL(articleCopied(int, const QString)), + this, SIGNAL(articleCopied(int, const QString)))); + + setAntiIdle(param_.isAntiIdle_); +} + +FQTermSession::~FQTermSession() { + delete idleTimer_; + delete autoReplyTimer_; + delete acThread_; + delete termBuffer_; + delete telnet_; + delete zmodem_; + delete decoder_; +} + +const QString FQTermSession::protocolPrefix[] = { + "http://", "https://", "mms://", "rstp://", "ftp://", "mailto:", "telnet://" +}; + +void FQTermSession::setScreenStart(int nStart) { + screenStartLineNumber_ = nStart; +} + +bool FQTermSession::setCursorPos(const QPoint &pt, QRect &rc) { + QRect rectOld = getMenuRect(); + + cursorPoint_ = pt; + + detectMenuRect(); + QRect rectNew = getMenuRect(); + + rc = rectOld | rectNew; + + return rectOld != rectNew; +} + +QString FQTermSession::getMessage() { + const FQTermTextLine *line; + LineColorInfo colorInfo; + QString message; + + getLineColorInfo(termBuffer_->getTextLineInTerm(0), &colorInfo); + if (!colorInfo.uniBackgroundColor) { + return message; + } + + int i = 1; + termBuffer_->getTextLineInTerm(0)->getAllPlainText(message); + + line = termBuffer_->getTextLineInTerm(i); + getLineColorInfo(line, &colorInfo); + while (colorInfo.uniBackgroundColor && colorInfo.hasBackgroundColor) { + message += "\n"; + line->getAllPlainText(message); + i++; + line = termBuffer_->getTextLineInTerm(i); + getLineColorInfo(line, &colorInfo); + } + return message; +} + + +void FQTermSession::detectPageState() { + //for smth type bbs. + pageState_ = Undefined; + if (param_.hostType_ != 0) { + return; + } + + const FQTermTextLine *line[4]; + LineColorInfo colorInfo[4]; + int lineIndex[4] = {0, 1, 2}; + lineIndex[3] = termBuffer_->getNumRows() - 1; + for (int i = 0; i < 4; ++i) { + line[i] = termBuffer_->getTextLineInTerm(lineIndex[i]); + getLineColorInfo(line[i], colorInfo + i); + } + + //TODO: Detect PageState in a clearer way. + if (!colorInfo[0].hasBackgroundColor) { + if (colorInfo[3].foregroundColorIndex.count() != 0 && + colorInfo[3].hasBackgroundColor){ + if (colorInfo[3].uniBackgroundColor) { + QString text; + line[3]->getAllPlainText(text); + if (text[0] != L'\x3010') { + pageState_ = Read; + } else { + pageState_ = Edit; + } + } else if (colorInfo[3].backgroundColorIndex.count() == 2 && + colorInfo[3].backgroundColorIndex.at(0) == 4 && + colorInfo[3].backgroundColorIndex.at(1) == 0){ + pageState_ = Read; + } + } + return; + } + + if (colorInfo[0].backgroundColorIndex.at(0) != 4 + || !(colorInfo[3].hasBackgroundColor && colorInfo[3].backgroundColorIndex.at(0) == 4)) { + if (!colorInfo[3].hasBackgroundColor && + colorInfo[0].foregroundColorIndex.count() == 4 && + colorInfo[0].foregroundColorIndex.at(1) == 4 && + colorInfo[0].foregroundColorIndex.at(2) == 7 && + colorInfo[0].foregroundColorIndex.at(3) == 4){ + pageState_ = TOP10; + } + return; + } + + if (colorInfo[1].hasBackgroundColor && colorInfo[1].uniBackgroundColor) { + pageState_ = Message; + return; + } + + if (colorInfo[0].uniBackgroundColor) { + if (!colorInfo[2].hasBackgroundColor || + colorInfo[2].backgroundColorIndex.at(0) != 4 || + colorInfo[2].backgroundColorIndex.count() > 3) { + pageState_ = Menu; + return; + } + } + + if (!colorInfo[0].uniBackgroundColor && + colorInfo[0].backgroundColorIndex.at(0) == 4 && + !colorInfo[3].uniBackgroundColor) { + //announce, elite root + pageState_ = EliteArticleList; + return; + } + + if (colorInfo[2].hasBackgroundColor && + !colorInfo[2].uniBackgroundColor && + colorInfo[2].backgroundColorIndex.at(0) == 4 && + !colorInfo[3].uniBackgroundColor) { + pageState_ = EliteArticleList; + return; + } + + if (colorInfo[0].foregroundColorIndex.indexOf(14) != -1) { + pageState_ = ArticleList; + return; + } + + if (colorInfo[2].foregroundColorIndex.indexOf(7) != -1) { + QString text; + line[2]->getAllPlainText(text); + if (text[0] == ' ') { + pageState_ = BoardList; + } else { + pageState_ = MailMenu; + } + } + +} + +FQTermSession::CursorType FQTermSession::getCursorType(const QPoint &pt) { + if (screenStartLineNumber_ != + (termBuffer_->getNumLines() - termBuffer_->getNumRows())) { + return kNormal; + } + + QRect rc = getMenuRect(); + CursorType nCursorType = kNormal; + switch (pageState_) { + case Undefined: // not recognized + if (rc.contains(pt)) { + //HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case Menu: + case MailMenu: + // menu + if (pt.x() < 5) { + // LEFT + nCursorType = kLeft; + } else if (rc.contains(pt)) { + // HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case ArticleList: + case BoardList: + case EliteArticleList: + case FriendMailList: + // list + if (pt.x() < 12) { + // LEFT + nCursorType = kLeft; + } else if (pt.y() - screenStartLineNumber_ < 3) { + // HOME + nCursorType = kHome; + } else if (pt.y() == termBuffer_->getNumLines() - 1) { + // END + nCursorType = kEnd; + } else if (pt.x() > termBuffer_->getNumColumns() - 16 && + pt.y() - screenStartLineNumber_ <= termBuffer_->getNumRows() / 2) { + //PAGEUP + nCursorType = kPageUp; + } else if (pt.x() > termBuffer_->getNumColumns() - 16 + && pt.y() - screenStartLineNumber_ > + termBuffer_->getNumRows() / 2) { + // PAGEDOWN + nCursorType = kPageDown; + } else if (rc.contains(pt)) { + // HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case Read: + // read + if (pt.x() < 12) { + // LEFT + nCursorType = kLeft; + } else if (pt.x() > (termBuffer_->getNumColumns() - 16) && + (pt.y() - screenStartLineNumber_) + <= termBuffer_->getNumRows() / 2) { + // PAGEUP + nCursorType = kPageUp; + } else if (pt.x() > (termBuffer_->getNumColumns() - 16) && + (pt.y() - screenStartLineNumber_) + > termBuffer_->getNumRows() / 2) { + // PAGEDOWN + nCursorType = kPageDown; + } else if (rc.contains(pt)) { + //HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case Edit: + // TODO: add action for kEdit state. + if (rc.contains(pt)) { + //HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case TOP10: + if (pt.x() < 12) { + nCursorType = kLeft; + } else if (rc.contains(pt)){ + nCursorType = kRight; + } + break; + default: + FQ_TRACE("error", 2) << "Error, wrong PageState."; + break; + } + + return nCursorType; +} + +bool FQTermSession::isSelectedMenu(int line) { + // TODO: possible performance issue + QRect rect = getMenuRect(); + + // nothing selected + if (rect.isNull()) { + return false; + } + + return line >= rect.bottom() && line <= rect.top(); +} + +bool FQTermSession::isSelectedMenu(const QPoint &pt) { + // TODO: possible performance issue + QRect rect = getMenuRect(); + + // nothing selected + if (rect.isNull()) { + return false; + } + + return rect.contains(pt); +} + +FQTermSession::PageState FQTermSession::getPageState() { + return pageState_; +} + +char FQTermSession::getMenuChar() { + return menuChar_; +} + +void FQTermSession::setMenuRect(int row, int col, int len) { + menuRect_ = QRect(col, row, len, 1); +} + +QRect FQTermSession::detectMenuRect() { + QRect rect(0, 0, 0, 0); + menuRect_ = rect; + if (scriptListener_) + { + bool res = scriptListener_->postScriptCallback(SFN_DETECT_MENU +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + if (res) return menuRect_; + } + // current screen scrolled + if (screenStartLineNumber_ != + (termBuffer_->getNumLines() - termBuffer_->getNumRows())) { + return rect; + } + + const FQTermTextLine *line; + int menuStartLine = 8; + switch (pageState_) { + case Undefined: break; + case MailMenu: + menuStartLine = 7; + case Menu: + if (cursorPoint_.y() - screenStartLineNumber_ >= menuStartLine && + cursorPoint_.x() > 5) { + line = termBuffer_->getTextLineInBuffer(cursorPoint_.y()); + QString cstr; + int cell_end = line->getCellEnd(qMin(cursorPoint_.x(), + (int)line->getWidth())); + line->getPlainText(0, cell_end, cstr); + + int base = cstr.lastIndexOf(" "); + if (base == -1) { + base = 0; + } + + QRegExp reg("[a-zA-Z0-9][).\\]]"); + char indexChar = cstr.indexOf(reg, base); + if (indexChar != -1) { + menuChar_ = cstr.at(indexChar).toLatin1(); + + QString strTmp = cstr.left(cstr.indexOf(reg, base)); + int nMenuStart = get_str_width((const UTF16 *)strTmp.data(), + strTmp.size()); + if (cstr[indexChar - 1] == '(' || cstr[indexChar - 1] == '[') { + nMenuStart--; + } + + cstr.clear(); + line->getAllPlainText(cstr); + + + reg = QRegExp("[^ ]"); + + int nMenuBaseLength = 20; + int cell_begin = + line->getCellBegin( + qMin(nMenuStart + nMenuBaseLength, (int)line->getWidth() - 1)); + int char_begin = line->getCharBegin(cell_begin); + //last [^ ] until char_begin + strTmp = cstr.left(cstr.lastIndexOf(reg, char_begin) + 1); + + int nMenuLength = + get_str_width((const UTF16 *)strTmp.data(), strTmp.size()) + - nMenuStart; + if (nMenuLength == nMenuBaseLength + 1) { + strTmp = cstr.left(cstr.indexOf(" ", char_begin) + 1); + nMenuLength = + get_str_width((const UTF16 *)strTmp.data(), strTmp.size()) + - nMenuStart; //base length is not enough + } + + if (cursorPoint_.x() >= nMenuStart && cursorPoint_.x() <= + nMenuStart + nMenuLength) { + rect.setX(nMenuStart); + rect.setY(cursorPoint_.y()); + rect.setWidth(nMenuLength); + rect.setHeight(1); + } + } + } + break; + case ArticleList: + case BoardList: + case FriendMailList: + case EliteArticleList: + if ((cursorPoint_.y() - screenStartLineNumber_) >= 3 + && (cursorPoint_.y() - screenStartLineNumber_) + < termBuffer_->getNumRows() -1 + && cursorPoint_.x() >= 12 + && cursorPoint_.x() <= termBuffer_->getNumColumns() - 16) { + line = termBuffer_->getTextLineInBuffer(cursorPoint_.y()); + //QString str = line->getText(); + QString str; + line->getAllPlainText(str); + + if (str.count(" ") != (int)str.length()) { + rect.setX(0); + rect.setY(cursorPoint_.y()); + rect.setWidth(line->getWidth()); + rect.setHeight(1); + } + } + break; + case Read: + + break; + case Edit: + break; + case TOP10: + { + int ln = cursorPoint_.y() - screenStartLineNumber_; + if (ln >= 3 && (ln & 1) && ln <= 21 && + cursorPoint_.x() >= 12 && + cursorPoint_.x() <= termBuffer_->getNumColumns() - 8){ + line = termBuffer_->getTextLineInBuffer(cursorPoint_.y()); + + QString str; + line->getAllPlainText(str); + + if (str.count(" ") != (int)str.length()) { + if (ln == 21){ + menuChar_ = '0'; + } else { + menuChar_ = ((ln - 1) >> 1) + '0'; + } + + rect.setX(12); + rect.setY(cursorPoint_.y()); + rect.setWidth(line->getWidth() - 20); + rect.setHeight(1); + } + } + } + break; + default: + break; + } + menuRect_ = rect; + return rect; +} + +bool FQTermSession::isIllChar(char ch) { + static char illChars[] = ";'\"[]<>^"; + return ch > '~' || ch < '!' || strchr(illChars, ch) != NULL; +} + +bool FQTermSession::isUrl(QRect &rcUrl, QRect &rcOld) { + return checkUrl(rcUrl, rcOld, false); +} + +bool FQTermSession::isIP(QRect &rcUrl, QRect &rcOld) { + return checkUrl(rcUrl, rcOld, true); +} + +QString FQTermSession::expandUrl(const QPoint& pt, QPair& range) +{ + // int at = pt.x(); + range.first = -1; + range.second = -2; + const FQTermTextLine *textLine = termBuffer_->getTextLineInBuffer(pt.y()); + if (textLine == NULL || pt.x() > (int)textLine->getWidth()) { + return ""; + } + + QString text; + textLine->getAllPlainText(text); + + int cell_begin = textLine->getCellBegin(pt.x()); + int at = textLine->getCharBegin(cell_begin); + if (at >= text.length()) { + return ""; + } + + int start; + int end; + for (start = at; start >= 0 && !isIllChar(text.at(start).toLatin1()); + start--) { + } + start++; + for (end = at; end < text.length() && !isIllChar(text.at(end).toLatin1()); + end++) { + } + range.first = get_str_width((const UTF16 *)text.data(), start); + range.second = get_str_width((const UTF16 *)text.data(), end); + return text.mid(start, end - start); +} + + +bool FQTermSession::checkUrl(QRect &rcUrl, QRect &rcOld, bool checkIP) { + + + + QPoint pt = cursorPoint_; + int at = pt.x(); + rcOld = urlRect_; + + if (at > urlRect_.left() && at < urlRect_.right() && urlRect_.y() == pt.y()) { + if ( (checkIP && !ip_.isEmpty()) || + (!checkIP && !url_.isEmpty()) ) { + rcUrl = urlRect_; + return true; + } + + } + + QPoint urlStartPoint; + QPoint urlEndPoint; + urlStartPoint_ = QPoint(); + urlEndPoint_ = QPoint(); + urlRect_ = QRect(0, 0, -1, -1); + if (!checkIP) { + url_.clear(); + } else { + ip_.clear(); + } + + QString urlText; + //phase 1: find all consecutive legal chars + QPair range; + urlText = expandUrl(pt, range); + if (range.first < 0 || range.first >= range.second) { + return false; + } + + + QRect urlRect = QRect(range.first, pt.y(), range.second - range.first, 1); + urlStartPoint = QPoint(range.first, pt.y()); + urlEndPoint = QPoint(range.second, pt.y()); + + if (range.second == termBuffer_->getNumColumns()) { + for (int i = pt.y() + 1; i < termBuffer_->getNumLines(); ++i) { + QString lineText = expandUrl(QPoint(0, i), range); + if (range.first == 0) { + urlText += lineText; + urlEndPoint.setY(urlEndPoint.y() + 1); + urlEndPoint.setX(range.second); + if (range.second == termBuffer_->getNumColumns()) { + continue; + } + } + break; + } + } + + //phase 2: find protocol prefix for url + //if none, prefix to add is set to "mailto:" if '@' is found + //otherwise, the prefix is "http://" by default. + QString prefixToAdd; + int protocolIndex; + for (protocolIndex = 0; protocolIndex < ProtocolSupported; ++protocolIndex) { + int begin = urlText.indexOf(protocolPrefix[protocolIndex], + Qt::CaseInsensitive); + if (begin != -1 && begin <= at) { + prefixToAdd = protocolPrefix[protocolIndex]; + urlText = urlText.mid(begin + protocolPrefix[protocolIndex].length()); + urlStartPoint.setX(urlStartPoint.x() + begin); + break; + } + } + if (protocolIndex == ProtocolSupported) { + int begin = urlText.indexOf("://"); + if (begin != -1) { + return false; + } + if (urlText.indexOf('@') != -1) { + prefixToAdd = protocolPrefix[Mailto]; + } else { + prefixToAdd = protocolPrefix[Http]; + } + } + + //no point or duplicated points + if (urlText.indexOf("..") != -1 || urlText.indexOf('.') == -1) { + return false; + } + + //phase 3: (for check ip) if there is a ':' before ip, there must be a '@' + int host_begin = qMax(urlText.lastIndexOf('@') + 1, 0); + int host_end = urlText.indexOf(':', host_begin); + if (host_end == -1) { + host_end = urlText.indexOf('/', host_begin); + } + if (host_end == -1) { + host_end = urlText.length(); + } + if (host_begin >= host_end) { + return false; + } + if (checkIP && urlText[host_end - 1] == '*') { + urlText[host_end - 1] = '1'; + } + + for (int index = 0; index < urlText.length() && urlText.at(index) != '/'; + index++) { + QChar cur(urlText.at(index)); + if (!cur.isLetterOrNumber() && !QString("-_~:@.").contains(cur)) { + return false; + } + } + + QString newIP; + newIP = urlText.mid(host_begin, host_end - host_begin); + QStringList ipv4 = newIP.split(QLatin1String(".")); + bool isIPv4 = true; + if (ipv4.count() != 4){ + isIPv4 = false; + } + foreach(QString domain, ipv4) { + bool ok; + int num = domain.toInt(&ok); + //won't tolerant spaces. + if (!ok || num < 0 || num > 255 || domain.length() > 3) { + isIPv4 = false; + break; + } + } + + if (!checkIP){ + QString lastName = ipv4.back(); + + int lastCharIndex = lastName.lastIndexOf(QRegExp("[a-zA-Z]")); + if (lastCharIndex == -1) { + if (!isIPv4) { + return false; + } else if (urlText == newIP) { + return false; + } + } else { + const QString *begin = endOfUrl; + const QString *end = endOfUrl + sizeof(endOfUrl) / sizeof(QString *); + if (qFind(begin, end, lastName) == end) { + return false; + } + } + url_ = prefixToAdd + urlText; + } else { + if (!isIPv4) { + return false; + } + ip_ = newIP; + } + + urlRect_ = urlRect; + rcUrl = urlRect; + urlStartPoint_ = urlStartPoint; + urlEndPoint_ = urlEndPoint; + return true; +} + +QString FQTermSession::getUrl() { + return url_; +} + +QString FQTermSession::getIP() { + return ip_; +} + +bool FQTermSession::isPageComplete() { + return termBuffer_->getCaretRow() == (termBuffer_->getNumRows() - 1) + && termBuffer_->getCaretColumn() == (termBuffer_->getNumColumns() - 1); +} + +bool FQTermSession::isAntiIdle() { + return param_.isAntiIdle_; +} + +void FQTermSession::setAntiIdle(bool antiIdle) { + param_.isAntiIdle_ = antiIdle; + + // disabled + if (!param_.isAntiIdle_ && idleTimer_->isActive()) { + idleTimer_->stop(); + } + + // enabled + if (param_.isAntiIdle_) { + if (idleTimer_->isActive()) { + idleTimer_->stop(); + } + idleTimer_->start(param_.maxIdleSeconds_ *1000); + } +} + +void FQTermSession::setAutoReconnect(bool autoReconnect) { + param_.isAutoReconnect_ = autoReconnect; + reconnectRetry_ = 0; + if (autoReconnect && !isConnected_) { + reconnectProcess(); + } +} + + +void FQTermSession::autoReplyMessage() { + if (autoReplyTimer_->isActive()) { + autoReplyTimer_->stop(); + } + if (pageState_ != Message) { + return; + } + if (scriptListener_) + { + bool res = scriptListener_->postScriptCallback(SFN_AUTO_REPLY +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + if (res) return; + } + QByteArray cstrTmp = param_.replyKeyCombination_.toLocal8Bit(); + QByteArray cstr = parseString(cstrTmp.isEmpty() ? QByteArray("^Z"): cstrTmp); + //cstr += m_param.m_strAutoReply.toLocal8Bit(); + cstr += unicode2bbs(param_.autoReplyMessage_); + cstr += '\n'; + telnet_->write(cstr, cstr.length()); + + emit messageAutoReplied(); +} + +QByteArray FQTermSession::parseString(const QByteArray &cstr, int *len) { + QByteArray parsed = ""; + + if (len != 0) { + *len = 0; + } + + for (uint i = 0; (long)i < cstr.length(); i++) { + if (cstr.at(i) == '^') { + i++; + if ((long)i < cstr.length()) { + parsed += FQTERM_CTRL(cstr.at(i)); + if (len != 0) { + *len = *len + 1; + } + } + } else if (cstr.at(i) == '\\') { + i++; + if ((long)i < cstr.length()) { + if (cstr.at(i) == 'n') { + parsed += CHAR_CR; + } else if (cstr.at(i) == 'r') { + parsed += CHAR_LF; + } else if (cstr.at(i) == 't') { + parsed += CHAR_TAB; + } + if (len != 0) { + *len = *len + 1; + } + } + } else { + parsed += cstr.at(i); + if (len != 0) { + *len = *len + 1; + } + } + } + + return parsed; +} + +void FQTermSession::reconnect() { + if (!isConnected_) { + telnet_->connectHost(param_.hostAddress_, param_.port_); + reconnectRetry_++; + } +} + +void FQTermSession::reconnectProcess() { + if (!isConnected_ && param_.isAutoReconnect_ && (reconnectRetry_ < param_.retryTimes_ || param_.retryTimes_ == -1)) { + int interval = param_.reconnectInterval_ <= 0 ? 0 : param_.reconnectInterval_ * 1000; + QTimer::singleShot(interval, this, SLOT(reconnect())); + } +} + +void FQTermSession::setMouseMode(bool on) { + isMouseX11_ = on; +} + +void FQTermSession::doAutoLogin() { + if (!param_.preLoginCommand_.isEmpty()) { + QByteArray temp = parseString(param_.preLoginCommand_.toLatin1()); + telnet_->write((const char*)(temp), temp.length()); + } + if (!param_.userName_.isEmpty()) { + QByteArray temp = param_.userName_.toLocal8Bit(); + telnet_->write((const char*)(temp), temp.length()); + char ch = CHAR_CR; + telnet_->write(&ch, 1); + } + if (!param_.password_.isEmpty()) { + QByteArray temp = param_.password_.toLocal8Bit(); + telnet_->write((const char*)(temp), temp.length()); + char ch = CHAR_CR; + telnet_->write(&ch, 1); + } + + // smth ignore continous input, so sleep 1 sec :) +#if defined(_OS_WIN32_) || defined(Q_OS_WIN32) + Sleep(1000); +#else + sleep(1); +#endif + + if (!param_.postLoginCommand_.isEmpty()) { + QByteArray temp = parseString(param_.postLoginCommand_.toLatin1()); + telnet_->write((const char*)(temp), temp.length()); + } + isTelnetLogining_ = false; +} + +//read slot +void FQTermSession::readReady(int size, int raw_size) { + FQ_ASSERT(size > 0 || raw_size > 0); // maybe raw_size is greater than 0. + + raw_data_.resize(raw_size); + telnet_->read_raw(&raw_data_[0], raw_size); + + // read raw buffer + int zmodem_consumed; + if (param_.enableZmodem_) + zmodem_->ZmodemRcv((uchar*)&raw_data_[0], raw_data_.size(), &(zmodem_->info), + zmodem_consumed); + + if (zmodem_->transferstate == notransfer) { + //decode + if (size > 0) { + int last_size = telnet_data_.size(); + telnet_data_.resize(last_size + size); + telnet_->read(&telnet_data_[0] + last_size, size); + int processed = 0; + { + while (!bufferWriteLock_.tryLockForWrite()) {} + //QWriteLocker locker(&bufferWriteLock_); + processed = decoder_->decode(&telnet_data_[0], telnet_data_.size()); + bufferWriteLock_.unlock(); + } + telnet_data_.erase(telnet_data_.begin(), telnet_data_.begin() + processed); + } + + if (isTelnetLogining_) { + int n = termBuffer_->getCaretRow(); + for (int y = n - 5; y < n + 5; y++) { + y = qMax(0, y); + const FQTermTextLine *pTextLine = termBuffer_->getTextLineInTerm(y); + if (pTextLine == NULL) { + continue; + } + + // QString str = pTextLine->getText(); + QString str; + pTextLine->getAllPlainText(str); + + if (str.indexOf("guest") != -1 /*&& str.indexOf("new") != -1*/) { + doAutoLogin(); + break; + } + } + } + // page complete when caret at the right corner + // this works for most but not for all + const FQTermTextLine *pTextLine = + termBuffer_->getTextLineInTerm(termBuffer_->getNumRows() - 1); + + //QString strText = stripWhitespace(pTextLine->getText()); + // TODO_UTF16: fixme! performance issue! + QString strText; + pTextLine->getAllPlainText(strText); + + // TODO_UTF16: shall we disable trim? + strText = strText.trimmed(); + + if (termBuffer_->getCaretRow() == termBuffer_->getNumRows() - 1 + && termBuffer_->getCaretColumn() >= (strText.length() - 1) / 2) { + waitCondition_.wakeAll(); + } + + //QToolTip::remove(this, screen_->mapToRect(m_rcUrl)); + + // message received + // 03/19/2003. the caret posion removed as a message judgement + // because smth.org changed + if (decoder_->bellReceive()) { + emit startAlert(); + emit bellReceived(); + + bool bellConsumed = false; + if (scriptListener_) { + bellConsumed = scriptListener_->postScriptCallback(SFN_ON_BELL +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + } + + if (isAutoReply() && !bellConsumed) { + // TODO: save messages + if (isIdling_) { + autoReplyMessage(); + } else { + autoReplyTimer_->start(param_.maxIdleSeconds_ *1000 / 2); + } + } + } + + // set page state + detectPageState(); + if (scriptListener_) { + scriptListener_->postScriptCallback(SFN_DATA_EVENT +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + } + emit sessionUpdated(); + } + + if (zmodem_->transferstate == transferstop) { + zmodem_->transferstate = notransfer; + } +} + +/* 0-left 1-middle 2-right 3-relsase 4/5-wheel + * + */ +//void FQTermWindow::sendMouseState( int num, +// Qt::ButtonState btnstate, Qt::ButtonState keystate, const QPoint& pt ) +void FQTermSession::sendMouseState(int num, Qt::KeyboardModifier btnstate, + Qt::KeyboardModifier keystate, const QPoint &pt) { + /* + if(!m_bMouseX11) + return; + + QPoint ptc = screen_->mapToChar(pt); + + if(btnstate&Qt::LeftButton) + num = num==0?0:num; + else if(btnstate&Qt::MidButton) + num = num==0?1:num; + else if(btnstate&Qt::RightButton) + num = num==0?2:num; + + int state = 0; + if(keystate&Qt::ShiftModifier) + state |= 0x04; + if(keystate&Qt::MetaModifier) + state |= 0x08; + if(keystate&Qt::ControlModifier) + state |= 0x10; + + // normal buttons are passed as 0x20 + button, + // mouse wheel (buttons 4,5) as 0x5c + button + if(num>3) num += 0x3c; + + char mouse[10]; + sprintf(mouse, "\033[M%c%c%c", + num+state+0x20, + ptc.x()+1+0x20, + ptc.y()+1+0x20); + telnet_->write( mouse, strlen(mouse) ); + */ +} + +void FQTermSession::cancelZmodem() { + zmodem_->zmodemCancel(); +} + +void FQTermSession::disconnect() { + telnet_->close(); + finalizeConnection(); +} + +void FQTermSession::finalizeConnection() { + if (isConnected_) { + QString strMsg = ""; + strMsg += "\n\n\n\r\n\r"; + strMsg += "\x1b[17C\x1b[0m===========================================\n\r"; + strMsg += + "\x1b[17C Connection Closed, Press \x1b[1m\x1b[31;40mEnter\x1b[m\x1b[0m To Connect\n\r"; + strMsg += "\x1b[17C===========================================\n"; + decoder_->decode(strMsg.toLatin1(), strMsg.length()); + } + isConnected_ = false; + + if (autoReplyTimer_->isActive()) { + autoReplyTimer_->stop(); + } + + if (idleTimer_->isActive()) { + idleTimer_->stop(); + } + + emit connectionClosed(); +} + +// telnet state slot +void FQTermSession::changeTelnetState(int state) { + switch (state) { + case TSRESOLVING: + break; + case TSHOSTFOUND: + break; + case TSHOSTNOTFOUND: + finalizeConnection(); + break; + case TSCONNECTING: + break; + case TSHOSTCONNECTED: + isConnected_ = true; + reconnectRetry_ = 0; + if (param_.isAutoLogin_ && param_.protocolType_==0) { + isTelnetLogining_ = true; + } + + break; + case TSPROXYCONNECTED: + break; + case TSPROXYAUTH: + break; + case TSPROXYFAIL: + disconnect(); + break; + case TSREFUSED: + finalizeConnection(); + break; + case TSREADERROR: + disconnect(); + break; + case TSCLOSED: + finalizeConnection(); + if (param_.isAutoReconnect_) { + reconnectProcess(); + } + break; + case TSCLOSEFINISH: + finalizeConnection(); + break; + case TSCONNECTVIAPROXY: + break; + case TSEGETHOSTBYNAME: + finalizeConnection(); + break; + case TSEINIWINSOCK: + finalizeConnection(); + break; + case TSERROR: + disconnect(); + break; + case TSPROXYERROR: + disconnect(); + break; + case TSWRITED: + // restart the idle timer + if (idleTimer_->isActive()) { + idleTimer_->stop(); + } + if (param_.isAntiIdle_) { + idleTimer_->start(param_.maxIdleSeconds_ *1000); + } + isIdling_ = false; + break; + default: + break; + } + + emit telnetStateChanged(state); +} + +void FQTermSession::handleInput(const QString &text) { + if (text.length() > 0) { + QByteArray cstrTmp = unicode2bbs_smart(text); + telnet_->write(cstrTmp, cstrTmp.length()); + } +} + +QString FQTermSession::bbs2unicode(const QByteArray &text) +{ + return encoding2unicode(text, param_.serverEncodingID_); +} + +QByteArray FQTermSession::unicode2bbs(const QString &text) { + return unicode2encoding(text, param_.serverEncodingID_); +} + + +QByteArray FQTermSession::unicode2bbs_smart(const QString &text) { + QByteArray strTmp; + + switch(param_.serverEncodingID_) + { + case FQTERM_ENCODING_GBK: + if (FQTermPref::getInstance()->imeEncodingID_ == FQTERM_ENCODING_BIG5) + { + strTmp = U2B(text); + char* tmp = encodingConverter_.B2G(strTmp, strTmp.length()); + strTmp = tmp; + delete []tmp; + } + else + { + strTmp = U2G(text); + } + break; + case FQTERM_ENCODING_BIG5: + if (FQTermPref::getInstance()->imeEncodingID_ == FQTERM_ENCODING_GBK) + { + strTmp = U2G(text); + char* tmp = encodingConverter_.G2B(strTmp, strTmp.length()); + strTmp = tmp; + delete []tmp; + } + else + { + strTmp = U2B(text); + } + break; + case FQTERM_ENCODING_HKSCS: + if (FQTermPref::getInstance()->imeEncodingID_ == FQTERM_ENCODING_GBK) + { + strTmp = U2G(text); + char* tmp = encodingConverter_.G2B(strTmp, strTmp.length()); + strTmp = tmp; + delete []tmp; + } + else + { + strTmp = U2H(text); + } + break; + case FQTERM_ENCODING_UTF8: + strTmp = U2U8(text); + break; + case FQTERM_ENCODING_UAO: + if (FQTermPref::getInstance()->imeEncodingID_ == FQTERM_ENCODING_GBK) + { + strTmp = U2G(text); + char* tmp = encodingConverter_.G2B(strTmp, strTmp.length()); + strTmp = tmp; + delete []tmp; + } + else + { + strTmp = U2A(text); + } + break; + } + + return strTmp; +} + + +void FQTermSession::onIdle() { + // do as autoreply when it is enabled + if (autoReplyTimer_->isActive() && param_.isAutoReply_) { + autoReplyMessage(); + stopAlert(); + return ; + } + + isIdling_ = true; + // system script can handle that + if (scriptListener_) { + bool res = scriptListener_->postScriptCallback(SFN_ANTI_IDLE +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + if (res) + return; + } + // the default function + int length; + QByteArray cstr = parseString(param_.antiIdleMessage_.toLocal8Bit(), &length); + telnet_->write(cstr, length); +} + +void FQTermSession::onAutoReply() { + // if AutoReply still enabled, then autoreply + if (param_.isAutoReply_) { + autoReplyMessage(); + } else { + // else just stop the timer + autoReplyTimer_->stop(); + } + + stopAlert(); +} +bool FQTermSession::isAutoReply() { + return param_.isAutoReply_; +} + +void FQTermSession::setAutoReply(bool on) { + param_.isAutoReply_ = on; + if (!param_.isAutoReply_ && autoReplyTimer_->isActive()) { + autoReplyTimer_->stop(); + } +} + +int FQTermSession::write(const char *data, int len) { + return telnet_->write(data, len); +} + +int FQTermSession::writeStr(const char *str) { + return write(str, strlen(str)); +} + +void FQTermSession::setProxy(int type, bool needAuth, + const QString &hostName, quint16 portNumber, + const QString &userName, const QString &password) { + telnet_->setProxy(type, needAuth, hostName, portNumber, userName, password); +} + +void FQTermSession::connectHost(const QString &hostName, quint16 portNumber) { + telnet_->connectHost(hostName, portNumber); +} + +void FQTermSession::close() { + telnet_->close(); + finalizeConnection(); +} + +void FQTermSession::clearLineChanged(int index) { + termBuffer_->clearLineChanged(index); +} + +void FQTermSession::setLineAllChanged(int index) { + termBuffer_->setLineAllChanged(index); +} + +void FQTermSession::setTermSize(int col, int row) { + termBuffer_->setTermSize(col, row); + param_.numColumns_ = col; + param_.numRows_ = row; +} + +FQTermBuffer *FQTermSession::getBuffer() const { + return termBuffer_; +} + +void FQTermSession::setSelect(const QPoint &pt1, const QPoint &pt2) { + termBuffer_->setSelect(pt1, pt2); +} + +void FQTermSession::clearSelect() { + termBuffer_->clearSelect(); +} + +void FQTermSession::leaveIdle() { + if (autoReplyTimer_->isActive()) { + autoReplyTimer_->stop(); + } + + if (idleTimer_->isActive()) { + idleTimer_->stop(); + } + + if (param_.isAntiIdle_) { + idleTimer_->start(param_.maxIdleSeconds_ * 1000); + } +} + +void FQTermSession::copyArticle() { + if (!acThread_->isRunning()) { + acThread_->start(); + } +} + +void FQTermSession::getLineColorInfo(const FQTermTextLine * line, + LineColorInfo * colorInfo) +{ + colorInfo->backgroundColorIndex.clear(); + colorInfo->foregroundColorIndex.clear(); + colorInfo->hasBackgroundColor = false; + colorInfo->uniBackgroundColor = true; + colorInfo->uniForegroundColor = true; + colorInfo->hasForegroundColor = false; + + if (!line || line->getWidth() == 0) { + return; + } + + const unsigned char *color = line->getColors(); + unsigned char background = GETBG(color[0]); + unsigned char foreground = GETFG(color[0]); + colorInfo->backgroundColorIndex.append(background); + colorInfo->foregroundColorIndex.append(foreground); + //for (int i = 0; i < color.length() / 2; i++) { + // TODO_UTF16: why use color.length()/2 formerly? + for (int i = 0; i < (int)line->getWidth(); i++) { + if (GETBG(color[i]) != background) { + colorInfo->uniBackgroundColor = false; + background = GETBG(color[i]); + colorInfo->backgroundColorIndex.append(background); + } + if (GETBG(color[i]) != GETBG(NO_COLOR)) { + colorInfo->hasBackgroundColor = true; + } + if (GETFG(color[i]) != foreground) { + colorInfo->uniForegroundColor = false; + foreground = GETFG(color[i]); + colorInfo->foregroundColorIndex.append(foreground); + } + if (GETFG(color[i]) != GETFG(NO_COLOR)) { + colorInfo->hasForegroundColor = true; + } + } +} + +bool FQTermSession::readyForInput() +{ + return telnet_->readyForInput(); +} + +void FQTermSession::onEnqReceived() { + if (FQTermPref::getInstance()->replyENQ_) + telnet_->write(ANSWERBACK_MESSAGE, sizeof(ANSWERBACK_MESSAGE)); +} + +void FQTermSession::onSSHAuthOK() { + isSSHLogining_ = false; + //setTermSize(80, 24); + //setTermSize(param_.numColumns_, param_.numRows_); + telnet_->windowSizeChanged(param_.numColumns_, param_.numRows_); +} + +void FQTermSession::updateSetting( const FQTermParam& p ) { + bool toggleAutoReconnect = (p.isAutoReconnect_ != param_.isAutoReconnect_); + param_ = p; + setTermSize(p.numColumns_, p.numRows_); + setAntiIdle(isAntiIdle()); + if (toggleAutoReconnect) + setAutoReconnect(param_.isAutoReconnect_); +} + +ArticleCopyThread::ArticleCopyThread( + FQTermSession &bbs, QWaitCondition &waitCondition, QReadWriteLock &bufferLock) + : session_(bbs), + waitCondition_(waitCondition), + lock_(bufferLock) { + FQ_VERIFY(connect(this, SIGNAL(writeSession(const QString&)), + &session_, SLOT(handleInput(const QString&)), + Qt::QueuedConnection)); +} + +ArticleCopyThread::~ArticleCopyThread() { +} + +static void removeTrailSpace(QString &line) { + for (int last_non_space = line.size() - 1; + last_non_space >= 0; --last_non_space) { + QChar a = line.at(last_non_space); + if (!a.isSpace()) { + line.resize(last_non_space + 1); + break; + } + + if (last_non_space == 0) { + line.resize(0); + } + } +} + + +/////////////////////////////////////// +//analyze last line when copy article +static std::pair ParseLastLine(QString str) { + int startLine = -1; + int endLine = -1; + int infoStart = str.indexOf('(', str.indexOf('(') + 1); + int infoEnd = str.indexOf(')', infoStart); + int infoSplit = str.indexOf('-', infoStart); + if (infoStart == -1 || infoEnd == -1 || infoSplit == -1) { + return std::make_pair(-1, -1); + } + bool ok = true; + startLine = str.mid(infoStart + 1, infoSplit - infoStart - 1).toInt(&ok); + if (!ok) { + return std::make_pair(-1, -1); + } + endLine = str.mid(infoSplit + 1, infoEnd - infoSplit - 1).toInt(&ok); + if (!ok) { + return std::make_pair(-1, -1); + } + return std::make_pair(startLine, endLine); +} +/////////////////////////////////////// + + +void ArticleCopyThread::run() { + QReadLocker locker(&lock_); + + typedef std::vector Page; + const FQTermBuffer *buffer = session_.getBuffer();; + Page page; + + QString firstPageLastLine; + buffer->getTextLineInTerm(buffer->getNumRows() - 1)->getAllPlainText(firstPageLastLine); + bool MultiPage = (firstPageLastLine.indexOf("%") != -1); + if (!MultiPage) { + emit writeSession("q"); + emit writeSession("\n"); + if (!waitCondition_.wait(&lock_, 10000)) { + emit articleCopied(DAE_TIMEOUT, ""); + return; + } + buffer->getTextLineInTerm(buffer->getNumRows() - 1)->getAllPlainText(firstPageLastLine); + MultiPage = (firstPageLastLine.indexOf("%") != -1); + } + + if (MultiPage) { + //session_.write("e", 1); + emit writeSession("e"); + if (!waitCondition_.wait(&lock_, 10000)) { + emit articleCopied(DAE_TIMEOUT, ""); + return; + } + QString LastPageLastLine; + buffer->getTextLineInTerm(buffer->getNumRows() - 1)->getAllPlainText(LastPageLastLine); + std::pair range = ParseLastLine(LastPageLastLine); + if (range.first == -1 || range.second == -1) { + return; + } + page.resize(range.second); + for (int i = range.first; i <= range.second; ++i) { + QString strTemp; + buffer->getTextLineInTerm(i - range.first)->getAllPlainText(strTemp); + page[i - 1] = strTemp; + } + //session_.write("s", 1); + emit writeSession("s"); + if (!waitCondition_.wait(&lock_, 10000)) { + emit articleCopied(DAE_TIMEOUT, ""); + return; + } + } + else { + for (int i = 0; i < buffer->getNumRows() - 1; ++i) { + QString strTemp; + buffer->getTextLineInTerm(i)->getAllPlainText(strTemp); + page.push_back(strTemp); + } + } + + while (MultiPage) { + // the end of article + int lineIndex = buffer->getNumRows() - 1; + //QByteArray lastLine = buffer->getLineInScreen(lineIndex)->getText(); + QString lastLine; + buffer->getTextLineInTerm(lineIndex)->getAllPlainText(lastLine); + + std::pair range = ParseLastLine(lastLine); + if (range.first == -1 || range.second == -1) { + page.push_back(lastLine); + break; + } + + // copy a page of lines exclude the last line. + for (int i = range.first; i <= range.second; ++i) { + QString strTemp; + buffer->getTextLineInTerm(i - range.first)->getAllPlainText(strTemp); + page[i - 1] = strTemp; + } + + + // wait for next page. + //session_.write(" ", 1); + emit writeSession(" "); + if (!waitCondition_.wait(&lock_, 10000)) { + emit articleCopied(DAE_TIMEOUT, ""); + break; + } + } + + + + QString articleText; + + for (Page::iterator line = page.begin(); line != page.end(); ++line) { + removeTrailSpace(*line); + articleText += (*line); + articleText += (OS_NEW_LINE); + } + + //qApp->postEvent(pWin, new QCustomEvent(DAE_FINISH)); + emit articleCopied(DAE_FINISH, articleText); +} + +} // namespace FQTerm + +#include "fqterm_session.moc" diff --git a/src/terminal/fqterm_session.h b/src/terminal/fqterm_session.h new file mode 100644 index 0000000..78aaa31 --- /dev/null +++ b/src/terminal/fqterm_session.h @@ -0,0 +1,344 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SESSION_H +#define FQTERM_SESSION_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fqterm_param.h" +#include "fqterm_config.h" +#include "fqterm_convert.h" +#ifdef HAVE_PYTHON +#include +#endif //HAVE_PYTHON + +class QRect; +class QTimer; + +namespace FQTerm { + +class FQTermScriptEventListener { +public: + bool postScriptCallback(const QString& func, +#ifdef HAVE_PYTHON + PyObject* pArgs, +#endif //HAVE_PYTHON + const QScriptValueList & args = QScriptValueList()) + { + bool res = postQtScriptCallback(func, args); +#ifdef HAVE_PYTHON + res = postPythonCallback(func, pArgs) || res; +#endif //HAVE_PYTHON + return res; + } + virtual long windowID() = 0; + virtual ~FQTermScriptEventListener() {} +private: + virtual bool postQtScriptCallback(const QString& func, const QScriptValueList & args = QScriptValueList()) = 0; +#ifdef HAVE_PYTHON + virtual bool postPythonCallback(const QString& func, PyObject* pArgs) = 0; +#endif //HAVE_PYTHON +}; + +struct LineColorInfo { + bool hasBackgroundColor; + bool hasForegroundColor; + bool uniBackgroundColor; + bool uniForegroundColor; + QList backgroundColorIndex; + QList foregroundColorIndex; +}; + +class FQTermConfig; +class FQTermBuffer; +class FQTermTextLine; +class FQTermTelnet; +class FQTermDecode; +class FQTermZmodem; +class ArticleCopyThread; + +class FQTermSession: public QObject { + Q_OBJECT; + public: + enum CursorType { + kHome = 0, + kEnd = 1, + kPageUp = 2, + kPageDown = 3, + kUp = 4, + kDown = 5, + kLeft = 6, + kRight = 7, + kNormal = 8 + }; + + FQTermSession(FQTermConfig *, FQTermParam); + ~FQTermSession(); + + enum PageState { + Undefined = -1, + Menu = 0, + MailMenu = 1, + ArticleList = 2, + EliteArticleList = 3, + BoardList = 4, + FriendMailList = 5, + Message = 6, + Read = 7, + Edit = 8, + TOP10 = 9, + }; + + enum ProtocolIndex { + Http = 0, + Https = 1, + Mms = 2, + Rstp = 3, + Ftp = 4, + Mailto = 5, + Telnet = 6, + ProtocolSupported = 7 + }; + + static const QString endOfUrl[]; + + static const QString protocolPrefix[]; + PageState getPageState(); + + // Set current cursor postion to pt, + // return whether the selection rectangle is changed. + // the output parameter rc be a rectangle including both + // the new and the old selection region. + bool setCursorPos(const QPoint &pt, QRect &rc); + CursorType getCursorType(const QPoint &); + + // Get the menu char detected in getSelectRect(). + char getMenuChar(); + + // Get current selection rectangle. + // also detect the menu char if in kMenu page state. + QRect detectMenuRect(); + QRect getMenuRect() {return menuRect_;} + void setMenuRect(int row, int col, int len); + // detect whether the given line or point is contained by current selection rectangle. + bool isSelectedMenu(int line); + bool isSelectedMenu(const QPoint &); + //selection. + void setSelect(const QPoint &pt1, const QPoint &pt2); + void clearSelect(); + + bool isUrl(QRect &, QRect &); + bool isIP(QRect &, QRect &); + QString getUrl(); + QString getIP(); + + + + // Set current screen start line to help detect cursor type + // and select rectangle corresponding to current cursor postion. + void setScreenStart(int); + + + + // Set a line of buffer to have been changed from start to end. + void clearLineChanged(int index); + void setLineAllChanged(int index); + + bool isAntiIdle(); + void setAntiIdle(bool antiIdle); + void leaveIdle(); + + bool isAutoReply(); + void setAutoReply(bool autoReply); + QString getMessage(); + + void setAutoReconnect(bool autoReconnect); + + + bool readyForInput(); + void setTermSize(int col, int row); + + QWaitCondition& getWaitCondition() {return waitCondition_;}; + //this function will do + //1. convert unicode to bbs encoding + //2. if there are some chars express same meaning in simplify/traditional + //Chinese, auto covert them by considering ime/bbs encoding. + QByteArray unicode2bbs_smart(const QString &); + QString bbs2unicode(const QByteArray &text); + QByteArray unicode2bbs(const QString &text); + + // Write data raw data + int write(const char *data, int len); + int writeStr(const char *str); + + // type: 0-no proxy; 1-wingate; 2-sock4; 3-socks5 + // needAuth: if authentation needed + void setProxy(int type, bool needAuth, + const QString &hostname, quint16 portNumber, + const QString &username, const QString &password); + // User close the connection + void close(); + + bool isConnected() {return isConnected_;} + void setSendingMessage(bool sending = true) {isSendingMessage_ = sending;} + const QPoint& urlStartPoint() {return urlStartPoint_;} + const QPoint& urlEndPoint() {return urlEndPoint_;} + + FQTermParam& param() {return param_;} + void updateSetting(const FQTermParam& p); + QReadWriteLock& getBufferLock() {return bufferWriteLock_;} + + public: + + + public slots: + FQTermBuffer *getBuffer() const; + void connectHost(const QString &hostname, quint16 portnumber); + void reconnect(); + void disconnect(); + + void cancelZmodem(); + void changeTelnetState(int state); + + void handleInput(const QString &text); + + void copyArticle(); + + signals: + void messageAutoReplied(); + void articleCopied(int state, const QString content); + void sessionUpdated(); + void connectionClosed(); + void bellReceived(); + void onTitleSet(const QString&); + void startAlert(); + void stopAlert(); + + void requestUserPwd(QString *user, QString *pwd, bool *isOK); + + void telnetStateChanged(int state); + void zmodemStateChanged(int type, int value, const char *status); + + void errorMessage(QString); + +private slots: + void readReady(int size, int raw_size); + void onIdle(); + void onAutoReply(); + void onEnqReceived(); + void onSSHAuthOK(); + void setMouseMode(bool on); + +private: + void sendMouseState(int, Qt::KeyboardModifier, Qt::KeyboardModifier, const QPoint &); + void getLineColorInfo(const FQTermTextLine * line, LineColorInfo * colorInfo); + bool isIllChar(char); + void detectPageState(); + QString expandUrl(const QPoint& pt, QPair& range); + bool checkUrl(QRect &, QRect &, bool); + QByteArray parseString(const QByteArray &cstr, int *len = 0); + void finalizeConnection(); + bool isPageComplete(); + void autoReplyMessage(); + void reconnectProcess(); + void doAutoLogin(); + +private: + //this read-write lock will be locked as a writer's lock if the buffer is being changed + //so for a reader who wants to ensure thread-safe, he should lock + //this lock as a reader's lock. + mutable QReadWriteLock bufferWriteLock_; + + FQTermParam param_; + FQTermConvert encodingConverter_; + bool isTelnetLogining_; + bool isSSHLogining_; + + bool isIdling_; + bool isMouseX11_; + bool isConnected_; + bool isSendingMessage_; + + QRect urlRect_; + QPoint urlStartPoint_; + QPoint urlEndPoint_; + QString url_; + QString ip_; + char menuChar_; + QRect menuRect_; + PageState pageState_; + QPoint cursorPoint_; + int screenStartLineNumber_; + + FQTermZmodem *zmodem_; + FQTermDecode *decoder_; + FQTermTelnet *telnet_; + FQTermBuffer *termBuffer_; + + QTimer *idleTimer_; + QTimer *autoReplyTimer_; + + QWaitCondition waitCondition_; + ArticleCopyThread *acThread_; + + std::vector telnet_data_; + std::vector raw_data_; + + int reconnectRetry_; +public: + void setScriptListener(FQTermScriptEventListener* pythonListener) { + scriptListener_ = pythonListener; + } +private: + FQTermScriptEventListener* scriptListener_; +}; + +class ArticleCopyThread: public QThread { + Q_OBJECT; + public: + ArticleCopyThread(FQTermSession &bbs, QWaitCondition &waitCondition, QReadWriteLock &bufferLock); + + ~ArticleCopyThread(); + + signals: + void articleCopied(int state, const QString content); + void writeSession(const QString&); + protected: + virtual void run(); + private: + FQTermSession &session_; + QWaitCondition &waitCondition_; + + QReadWriteLock &lock_; +}; + +} // namespace FQTerm + +#endif // FQTERM_SESSION_H diff --git a/src/terminal/fqterm_text_line.cpp b/src/terminal/fqterm_text_line.cpp new file mode 100644 index 0000000..ed6d164 --- /dev/null +++ b/src/terminal/fqterm_text_line.cpp @@ -0,0 +1,541 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include + +#include "fqterm.h" +#include "fqterm_text_line.h" + +namespace FQTerm { + +#ifndef NDEBUG +//#define TEXT_LINE_CHECK +#else +//#define TEXT_LINE_CHECK +#endif + +#ifndef TEXT_LINE_CHECK +void FQTermTextLine::verifyTextLine() const {} +void FQTermTextLine::verifyCellRange(unsigned, unsigned) const {} +#else +void FQTermTextLine::verifyTextLine() const { + unsigned last_cell = 0; + unsigned cur_cell = last_cell; + + if (cells_.size() == 0 + || cell_colors_.size() == 0 + || cell_attrs_.size() == 0 + || chars_.size() == 0 + ) { + FQ_VERIFY(cells_.size() == 0); + FQ_VERIFY(cell_colors_.size() == 0); + FQ_VERIFY(cell_attrs_.size() == 0); + FQ_VERIFY(chars_.size() == 0); + return; + } + + FQ_VERIFY(max_cell_count_ < 65536); + FQ_VERIFY(chars_.size() < 65536); + FQ_VERIFY(cells_.size() <= max_cell_count_); + FQ_VERIFY(cells_.size() == cell_colors_.size()); + FQ_VERIFY(cells_.size() == cell_attrs_.size()); + + const UTF16 *start = &chars_[0]; + const UTF16 *end = start + chars_.size(); + + for (const UTF16 *p = start; p < end;) { + int w = mk_advace_at_least_one_cell(&p, end); + + FQ_VERIFY(w >= 0); // should be valid unicode string. + + cur_cell += w; + + for (unsigned i = last_cell; i < cur_cell; ++i) { + unsigned char_end = p - start; + FQ_VERIFY(cells_[i] == char_end); + } + + last_cell = cur_cell; + } + + FQ_VERIFY(cur_cell == getWidth()); + FQ_VERIFY(cells_.back() == chars_.size()); +} + +void FQTermTextLine::verifyCellRange(unsigned cell_begin, unsigned cell_end) const { + FQ_VERIFY(cell_begin <= cell_end); + FQ_VERIFY(cell_end <= getWidth()); + + unsigned real_cell_begin = getCellBegin(cell_begin); + FQ_VERIFY(real_cell_begin == cell_begin); + + unsigned real_cell_end = getCellBegin(cell_end); + FQ_VERIFY(real_cell_end == cell_end); + + unsigned char_begin = getCharBegin(cell_begin); + FQ_VERIFY(char_begin <= chars_.size()); + + unsigned char_end = getCharEnd(cell_end); + FQ_VERIFY(char_begin <= char_end); + FQ_VERIFY(char_end <= chars_.size()); + +} + +#endif + +FQTermTextLine::FQTermTextLine(unsigned max_cell_count) + : max_cell_count_(max_cell_count), + dirty_cell_begin_(0), + dirty_cell_end_(max_cell_count), + stored_color_(0), + stored_attr_(0){ + cells_.reserve(max_cell_count_); + cell_colors_.reserve(max_cell_count_); + cell_attrs_.reserve(max_cell_count_); + chars_.reserve(max_cell_count_); +} + +FQTermTextLine::~FQTermTextLine() { +} + +void FQTermTextLine::setMaxCellCount(unsigned max_cell_count) { + // FIXME: how about dirty flag? + max_cell_count_ = max_cell_count; + + if (cells_.size() > max_cell_count_) { + // TODO_UTF16: what if an incomplete utf-16 byte left. + cells_.resize(max_cell_count_); + cell_colors_.resize(max_cell_count_); + cell_attrs_.resize(max_cell_count_); + chars_.resize(cells_.back()); + } +} + +// Whether this line of text contains blink characters. +bool FQTermTextLine::hasBlink() const { + bool blink = false; + + char tempea; + for (unsigned i = 0; i < cells_.size(); i++) { + tempea = cell_attrs_[i]; + if (GETBLINK(tempea)) { + blink = true; + break; + } + } + + return blink; +} + +void FQTermTextLine::setDirtyFlag(unsigned cell_begin, unsigned cell_end) { +#ifdef TEXT_LINE_CHECK + FQ_VERIFY(cell_begin <= cell_end); + FQ_VERIFY(cell_end <= max_cell_count_); +#endif + if (dirty_cell_begin_ > cell_begin) { + dirty_cell_begin_ = cell_begin; + } + + if (dirty_cell_end_ < cell_end) { + dirty_cell_end_ = cell_end; + } +} + +void FQTermTextLine::safelySetDirtyFlag(unsigned cell_begin, unsigned cell_end) { + if (cell_end > max_cell_count_) cell_end = max_cell_count_; + + if (cell_begin >= cell_end) + return; + + setDirtyFlag(cell_begin, cell_end); +} + +void FQTermTextLine::clearDirtyFlag() { + dirty_cell_begin_ = 0; + dirty_cell_end_ = 0; +} + +bool FQTermTextLine::getDirtyCells(unsigned &cell_begin, unsigned &cell_end) const { + cell_begin = dirty_cell_begin_; + cell_end = dirty_cell_end_; + return dirty_cell_begin_ < dirty_cell_end_; +} + +void FQTermTextLine::getPlainText(unsigned cell_begin, unsigned cell_end, + QString &result) const { + verifyCellRange(cell_begin, cell_end); + + if (cells_.size() == 0 || cell_begin == cell_end) return; + + unsigned char_begin = getCharBegin(cell_begin); + unsigned char_end = getCharEnd(cell_end); + + result.insert(result.size(), + (QChar *) &chars_[char_begin], + char_end - char_begin); + + typedef char Verify_QChar_Is_Two_Bytes[ + (sizeof(QChar) == 2)? 1 : -1]; +} + +void FQTermTextLine::getAnsiText(unsigned cell_begin, unsigned cell_end, + QString &result, + const char *escape) const { + verifyCellRange(cell_begin, cell_end); + + if (cells_.size() == 0 || cell_begin == cell_end) return; + + unsigned cur_cell = cell_begin; + unsigned next_cell = cell_begin; + + while (cur_cell < cell_end) { + unsigned char color = cell_colors_[cur_cell]; + unsigned char attr = cell_attrs_[cur_cell]; + + for (next_cell = cur_cell; + next_cell < cell_end; + ++next_cell) { + if (!(cell_colors_[next_cell] == color + && cell_attrs_[next_cell] == attr)) { + if (next_cell > getCellBegin(next_cell)) { + continue; + } else { + break; + } + } + + } + + getAnsiCtrlSeq(color, attr, escape, result); + getPlainText(cur_cell, next_cell, result); + result += escape; + result += "0m"; + + cur_cell = next_cell; + } +} + + +void FQTermTextLine::appendWhiteSpace( + unsigned count, unsigned char color, unsigned char attr, UTF16 space) { + FQ_ASSERT(get_str_width(space) == 1); + + cells_.reserve(getWidth() + count); + max_cell_count_ = qMax(max_cell_count_, getWidth() + count); + + cell_colors_.reserve(getWidth() + count); + cell_attrs_.reserve(getWidth() + count); + + setDirtyFlag(getWidth(), getWidth() + count); + + chars_.insert(chars_.end(), count, space); + cell_colors_.insert(cell_colors_.end(), count, color); + cell_attrs_.insert(cell_attrs_.end(), count, attr); + + int c = getCharEnd(getWidth()); + for (unsigned i = 0; i < count; ++i) { + cells_.push_back(c + i + 1); + } + + verifyTextLine(); +} + +void FQTermTextLine::insertWhiteSpace(unsigned count, unsigned cell_begin, + unsigned char color, unsigned char attr, + UTF16 space) { + FQ_ASSERT(get_str_width(space) == 1); + + breakCell(cell_begin); + + verifyCellRange(cell_begin, getWidth()); + + unsigned char_begin = getCharBegin(cell_begin); + + max_cell_count_ = qMax(max_cell_count_, getWidth() + count); + + chars_.insert(chars_.begin() + char_begin, count, space); + cell_colors_.insert(cell_colors_.begin() + cell_begin, count, color); + cell_attrs_.insert(cell_attrs_.begin() + cell_begin, count, attr); + + cells_.insert(cells_.begin() + cell_begin, count, 0); + for (unsigned i = cell_begin; i < cell_begin + count; ++i) { + cells_[i] = char_begin + (i - cell_begin) + 1; + } + for (unsigned i = cell_begin + count; i < getWidth(); ++i) { + cells_[i] += count; + } + + setDirtyFlag(cell_begin, this->getWidth()); + + verifyTextLine(); +} + +void FQTermTextLine::replaceWithWhiteSpace( + unsigned count, unsigned cell_begin, unsigned cell_end, + unsigned char color, unsigned char attr, UTF16 space) { + if(cell_end>cells_.size() || cell_begin>=cell_end) + return; + deleteText(cell_begin, cell_end); + insertWhiteSpace(count, cell_begin, color, attr, space); +} + + + +void FQTermTextLine::insertText(const UTF16 *str, unsigned count, + unsigned cell_begin, + unsigned char color, unsigned char attr, int charstate) { + if (count == 0) return; + + // Calculate how many cells should be occupied for str. + // TODO: avoid compute the width of str twice. + int width = get_str_width(str, count); + + if (width == 0) { +#ifdef TEXT_LINE_CHECK + //FQ_VERIFY(false); + //TODO: enable utf8 decoding +#endif + return; + } + + if (charstate & FQTermTextLine::FIRSTPART) { + stored_color_ = color; + stored_attr_ = attr; + width--; + count--; + if (width == 0 || count == 0) { + return; + } + } + + breakCell(cell_begin); + + verifyCellRange(cell_begin, getWidth()); + + unsigned char_begin = getCharBegin(cell_begin); + + chars_.insert(chars_.begin() + char_begin, str, str + count); + + // Insert colors. + cell_colors_.insert(cell_colors_.begin() + cell_begin, width, color); + + // Insert attrs. + cell_attrs_.insert(cell_attrs_.begin() + cell_begin, width, attr); + + if (charstate & FQTermTextLine::SECONDPART){ + cell_colors_[cell_begin] = stored_color_; + cell_attrs_[cell_begin] = stored_attr_; + } + + + // Change the cells_ mapping to chars_. + cells_.insert(cells_.begin() + cell_begin, width, 0); + max_cell_count_ = qMax(max_cell_count_, getWidth()); + + unsigned last_cell = cell_begin; + unsigned cur_cell = last_cell; + for (const UTF16 *p = str; p < str +count;) { + int w = mk_advace_at_least_one_cell(&p, str + count); + +#ifdef TEXT_LINE_CHECK + // TODO_UTF16: FIXME: deal with decoding error. + FQ_VERIFY(w >= 0); +#endif + + cur_cell += w; + + for (unsigned i = last_cell; i < cur_cell; ++i) { + cells_[i] = char_begin + (p - str); + } + + last_cell = cur_cell; + } + +#ifdef TEXT_LINE_CHECK + FQ_VERIFY(cur_cell == cell_begin + width); +#endif + + for (unsigned i = cell_begin + width; i < cells_.size(); ++i) { + cells_[i] += count; + } + + + + setDirtyFlag(cell_begin, cells_.size()); + + verifyTextLine(); +} + +void FQTermTextLine::deleteText(unsigned cell_begin, unsigned cell_end) { + if (cells_.size() == 0 || cell_begin == cell_end) return; + + breakCell(cell_begin); + breakCell(cell_end); + + verifyCellRange(cell_begin, cell_end); + + setDirtyFlag(cell_begin, cells_.size()); + + unsigned char_begin = getCharBegin(cell_begin); + unsigned char_end = getCharEnd(cell_end); + + chars_.erase(chars_.begin() + char_begin, chars_.begin() + char_end); + + cells_.erase(cells_.begin() + cell_begin, cells_.begin() + cell_end); + cell_colors_.erase(cell_colors_.begin() + cell_begin, + cell_colors_.begin() + cell_end); + cell_attrs_.erase(cell_attrs_.begin() + cell_begin, + cell_attrs_.begin() + cell_end); + + for (unsigned i = cell_begin; i < cells_.size(); ++i) { + cells_[i] -= (char_end - char_begin); + } + + verifyTextLine(); +} + +void FQTermTextLine::deleteAllText() { + deleteText(0, getWidth()); +} + +void FQTermTextLine::replaceText(const UTF16 *str, unsigned count, + unsigned cell_begin, unsigned cell_end, + unsigned char color, unsigned char attr, int charstate) { + if (charstate & FQTermTextLine::FIRSTPART) { + stored_color_ = color; + stored_attr_ = attr; + count--; + if (count == 0) + { + return; + } + charstate &= ~FQTermTextLine::FIRSTPART; + } + + deleteText(cell_begin, cell_end); + insertText(str, count, cell_begin, color, attr, charstate); + + setDirtyFlag(cell_begin, cells_.size()); +} + + +unsigned FQTermTextLine::getCellBegin(unsigned cell_begin) const { +#ifdef TEXT_LINE_CHECK + FQ_VERIFY(cell_begin <= getWidth()); +#endif + + if (cell_begin == cells_.size()) return cell_begin; + + while(cell_begin > 0 && cells_[cell_begin - 1] == cells_[cell_begin]) { + --cell_begin; + } + + return cell_begin; +} + +unsigned FQTermTextLine::getCellEnd(unsigned cell_end) const { +#ifdef TEXT_LINE_CHECK + FQ_VERIFY(cell_end <= getWidth()); +#endif + + if (cell_end == 0) return cell_end; + + while (cell_end < cells_.size() && cells_[cell_end - 1] == cells_[cell_end]) { + ++cell_end; + } + + return cell_end; +} + +unsigned FQTermTextLine::getCharBegin(unsigned cell_begin) const { +#ifdef TEXT_LINE_CHECK + FQ_VERIFY(cell_begin == getCellBegin(cell_begin)); +#endif + + if (cell_begin == 0) return 0; + + return cells_[cell_begin - 1]; +} + +unsigned FQTermTextLine::getCharEnd(unsigned cell_end) const { +#ifdef TEXT_LINE_CHECK + FQ_VERIFY(cell_end == getCellEnd(cell_end)); +#endif + + if (cell_end == 0) return 0; + + return cells_[cell_end - 1]; +} + +bool FQTermTextLine::breakCell(unsigned cell_begin) { + unsigned real_cell_begin = getCellBegin(cell_begin); + if (real_cell_begin == cell_begin) return false; + + unsigned real_cell_end = getCellEnd(cell_begin); + + verifyCellRange(real_cell_begin, real_cell_end); + + unsigned cell_count = real_cell_end - real_cell_begin; + + replaceWithWhiteSpace(cell_count, real_cell_begin, real_cell_end, + cell_colors_[cell_begin], cell_attrs_[cell_begin], URC); + + return true; +} + +void FQTermTextLine::getAnsiCtrlSeq( + unsigned char color, unsigned char attr, + const char *escape, QString &result) const { + + int fg = GETFG(color) + 30; + int bg = GETBG(color) + 40; + + result += escape; + result += QString("%1;%2").arg(fg).arg(bg); + + if (GETBRIGHT(attr)) { + result += ";1"; + } + if (GETDIM(attr)) { + result += ";2"; + } + if (GETUNDERLINE(attr)) { + result += ";4"; + } + if (GETBLINK(attr)) { + result += ";5"; + } + if (GETRAPIDBLINK(attr)) { + result += ";6"; + } + if (GETREVERSE(attr)) { + result += ";7"; + } + if (GETINVISIBLE(attr)) { + result += ";8"; + } + + result += "m"; +} + + +} // namespace FQTerm diff --git a/src/terminal/fqterm_text_line.h b/src/terminal/fqterm_text_line.h new file mode 100644 index 0000000..72ff4c0 --- /dev/null +++ b/src/terminal/fqterm_text_line.h @@ -0,0 +1,159 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_TEXTLINE_H +#define FQTERM_TEXTLINE_H + +#include + +#include "fqwcwidth.h" +#include "fqterm.h" +class QString; + +namespace FQTerm { +/* + A text line consists of several characters in a sequence of cells. A + character may occupy some cells, e.g. each English letter occupies + one cell, while a CJK character needs two. + + This class is used to manipolate a text line, delete/replace + characters in a given cell range, insert characters before a cell, + and retrieve characters/colors/attributs of a gaven cell range. +*/ +class FQTermTextLine { + public: + FQTermTextLine(unsigned max_cell_count); + ~FQTermTextLine(); + + enum CHARSTATE{NORMAL = 0x00, FIRSTPART = 0x01, SECONDPART = 0x02}; + // Get the number of used cells. + unsigned getWidth() const {return cells_.size();} + + void setMaxCellCount(unsigned max_cell_count); + unsigned getMaxCellCount() const { return max_cell_count_; } + + // Whether this line of text contains blink characters. + bool hasBlink() const; + + // Set/get the dirty flag, that indicates which cells have been + // modified. + void setDirtyFlag(unsigned cell_begin, unsigned cell_end); + void safelySetDirtyFlag(unsigned cell_begin, unsigned cell_end); + bool getDirtyCells(unsigned &cell_begin, unsigned &cell_end) const; + void clearDirtyFlag(); + void setAllDirty() {setDirtyFlag(0, max_cell_count_);} + + const unsigned char *getColors() const { + return cells_.size() == 0 ? NULL : &cell_colors_[0]; + } + + const unsigned char *getAttributes() const { + return cells_.size() == 0 ? NULL : &cell_attrs_[0]; + } + + // Get plain text in [cell_begin, cell_end). + void getPlainText(unsigned cell_begin, unsigned cell_end, + QString &result) const; + + void getAllPlainText(QString &result) const { + getPlainText(0, getWidth(), result); + } + + // Get text in cells [cell_begin, cell_end), with color and + // attribute in ANSI format. + void getAnsiText(unsigned cell_begin, unsigned cell_end, + QString &result, + const char *escape = "\x1b\x1b") const; + + void getAllAnsiText(QString &result, const char* escape = "\x1b\x1b") const { + getAnsiText(0, getWidth(), result, escape); + } + + void appendWhiteSpace(unsigned count, + unsigned char color = NO_COLOR, + unsigned char attr = NO_ATTR, + UTF16 space = ' '); + + void insertWhiteSpace(unsigned count, unsigned cell_begin, + unsigned char color = NO_COLOR, + unsigned char attr = NO_ATTR, + UTF16 space = ' '); + + void replaceWithWhiteSpace(unsigned count, + unsigned cell_begin, unsigned cell_end, + unsigned char color = NO_COLOR, + unsigned char attr = NO_ATTR, + UTF16 space = ' '); + + // insert string at specified cell, + void insertText(const UTF16 *str, unsigned count, + unsigned cell_begin, + unsigned char color, unsigned char attr, int charstate = FQTermTextLine::NORMAL); + void replaceText(const UTF16 *str, unsigned count, + unsigned cell_begin, unsigned cell_end, + unsigned char color, unsigned char attr, int charstate = FQTermTextLine::NORMAL); + void deleteText(unsigned cell_begin, unsigned cell_end); + void deleteAllText(); + + // If cell_begin is a begining of a readable character, return + // cell_begin itself, otherwise return the previous cell which starts a + // readable character. + unsigned getCellBegin(unsigned cell_begin) const; + + // If cell_end is a ending of a readable character, return cell_end + // itself, otherwise return the next cell which finishes a + // readable character. + unsigned getCellEnd(unsigned cell_end) const; + + unsigned getCharBegin(unsigned cell_begin) const; + unsigned getCharEnd(unsigned cell_end) const; + + private: + unsigned max_cell_count_; // max number of cells allowed. + + std::vector cells_; // store the index of character in this->chars_ for each cell. + std::vector cell_colors_; // store the color for each cell. + std::vector cell_attrs_; // store the attribute for each cell. + std::vector chars_; // store all the character. + + unsigned char stored_color_; + unsigned char stored_attr_; + + // range of changed text. + unsigned dirty_cell_begin_, dirty_cell_end_; + + // if the given cell isn't a beginning of characters, + // i.e is in the middle of a wide character, + // break the character into several unicode replacement characters (URC) + // to make the given cell be a beginning of character. + bool breakCell(unsigned cell_begin); + + // calculate ANSI escape sequence with given color, attribute and escape strings. + void getAnsiCtrlSeq(unsigned char color, unsigned char attr, + const char *escape, QString &result) const; + + // Two functions for debugging/testing. + void verifyTextLine() const; + void verifyCellRange(unsigned cell_begin, unsigned cell_end) const; +}; + +} // namespace FQTerm + +#endif // FQTERM_TEXTLINE_H diff --git a/src/terminal/internal/fqterm_decode.cpp b/src/terminal/internal/fqterm_decode.cpp new file mode 100644 index 0000000..cb7bc9a --- /dev/null +++ b/src/terminal/internal/fqterm_decode.cpp @@ -0,0 +1,1279 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#include "fqterm.h" +#include "fqterm_telnet.h" +#include "fqterm_decode.h" +#include "fqterm_buffer.h" +#include "fqwcwidth.h" + +namespace FQTerm { + +#define MODE_MouseX11 0 + +/************************************************************************/ +// state for FSM +// please read ANSI decoding +StateOption FQTermDecode::VT100StateMachine::normal_state_[] = { + { + CHAR_CR, &FQTermDecode::cr, normal_state_ + }, { + CHAR_LF, &FQTermDecode::lf, normal_state_ + }, { + CHAR_VT, &FQTermDecode::lf, normal_state_ + }, { + CHAR_ESC, 0, esc_state_ + }, { + CHAR_FF, &FQTermDecode::ff, normal_state_ + }, { + CHAR_TAB, &FQTermDecode::tab, normal_state_ + }, { + CHAR_BS, &FQTermDecode::bs, normal_state_ + }, { + CHAR_BELL, &FQTermDecode::bell, normal_state_ + }, { + CHAR_SO, &FQTermDecode::g1, normal_state_ + }, { + CHAR_SI, &FQTermDecode::g0, normal_state_ + }, { + CHAR_CAN, 0, normal_state_ // should be ignored + }, { + CHAR_DEL, &FQTermDecode::del, normal_state_ + }, { + CHAR_NUL, 0, normal_state_ // should be ignored + }, { + CHAR_ENQ, &FQTermDecode::enq, normal_state_ + }, { + CHAR_NORMAL, &FQTermDecode::normalInput, normal_state_ + } +}; + +// state after a ESC_CHAR +StateOption FQTermDecode::VT100StateMachine::esc_state_[] = { + { + '7', &FQTermDecode::saveCursor, normal_state_ + }, { + '8', &FQTermDecode::restoreCursor, normal_state_ + }, { + '[', &FQTermDecode::clearParam, bracket_state_ + }, { + ']', &FQTermDecode::clearParam, title_state_ + }, { + '(', 0, select_g0_charset_state_ + }, { + ')', 0, select_g1_charset_state_ + }, { + 'D', &FQTermDecode::moveCursorDown, normal_state_ + }, { + 'E', &FQTermDecode::nextLine, normal_state_ + }, { + 'H', &FQTermDecode::addTabStop, normal_state_ + }, { + 'M', &FQTermDecode::moveCursorUp, normal_state_ + }, { + '>', &FQTermDecode::setNumericKeypad, normal_state_ + }, { + '=', &FQTermDecode::setAppKeypad, normal_state_ + }, { + '<', &FQTermDecode::test, normal_state_ + }, { + '#', 0, sharp_state_ + }, { + CHAR_NORMAL, 0, normal_state_ + } +}; + +// state after ESC [ +StateOption FQTermDecode::VT100StateMachine::bracket_state_[] = { + { + '0', &FQTermDecode::paramDigit, bracket_state_ + }, { + '1', &FQTermDecode::paramDigit, bracket_state_ + }, { + '2', &FQTermDecode::paramDigit, bracket_state_ + }, { + '3', &FQTermDecode::paramDigit, bracket_state_ + }, { + '4', &FQTermDecode::paramDigit, bracket_state_ + }, { + '5', &FQTermDecode::paramDigit, bracket_state_ + }, { + '6', &FQTermDecode::paramDigit, bracket_state_ + }, { + '7', &FQTermDecode::paramDigit, bracket_state_ + }, { + '8', &FQTermDecode::paramDigit, bracket_state_ + }, { + '9', &FQTermDecode::paramDigit, bracket_state_ + }, { + ';', &FQTermDecode::nextParam, bracket_state_ + }, { + '?', &FQTermDecode::clearParam, private_state_ + }, { + 'A', &FQTermDecode::cursorUp, normal_state_ + }, { + 'B', &FQTermDecode::cursorDown, normal_state_ + }, { + 'C', &FQTermDecode::cursorRight, normal_state_ + }, { + 'D', &FQTermDecode::cursorLeft, normal_state_ + }, { + 'H', &FQTermDecode::cursorPosition, normal_state_ + }, { + 'J', &FQTermDecode::eraseScreen, normal_state_ + }, { + 'K', &FQTermDecode::eraseLine, normal_state_ + }, { + 'L', &FQTermDecode::insertLine, normal_state_ + }, { + 'M', &FQTermDecode::deleteLine, normal_state_ + }, { + 'P', &FQTermDecode::deleteStr, normal_state_ + }, { + 'X', &FQTermDecode::eraseStr, normal_state_ + }, { + 'f', &FQTermDecode::cursorPosition, normal_state_ + }, { + 'g', &FQTermDecode::clearTabStop, normal_state_ + }, { + 'h', &FQTermDecode::setMode, normal_state_ + }, { + 'l', &FQTermDecode::resetMode, normal_state_ + }, { + 'm', &FQTermDecode::setAttr, normal_state_ + }, { + 'q', 0, normal_state_ // ignore LED-related commands. + }, { + 'r', &FQTermDecode::setMargins, normal_state_ + }, { + 's', &FQTermDecode::saveCursor, normal_state_ + }, { + 'u', &FQTermDecode::restoreCursor, normal_state_ + }, { + '@', &FQTermDecode::insertStr, normal_state_ + }, { + CHAR_CR, &FQTermDecode::cr, bracket_state_ + }, { + CHAR_LF, &FQTermDecode::lf, bracket_state_ + }, { + CHAR_VT, &FQTermDecode::lf, bracket_state_ + }, { + CHAR_FF, &FQTermDecode::ff, bracket_state_ + }, { + CHAR_TAB, &FQTermDecode::tab, bracket_state_ + }, { + CHAR_BS, &FQTermDecode::bs, bracket_state_ + }, { + CHAR_BELL, &FQTermDecode::bell, bracket_state_ + }, { + CHAR_NORMAL, 0, normal_state_ + } +}; + +// state after ESC ( +StateOption FQTermDecode::VT100StateMachine::select_g0_charset_state_[] = { + { + 'A', &FQTermDecode::selectG0A, normal_state_ + }, { + 'B', &FQTermDecode::selectG0B, normal_state_ + }, { + '0', &FQTermDecode::selectG00, normal_state_ + }, { + '1', &FQTermDecode::selectG01, normal_state_ + }, { + '2', &FQTermDecode::selectG02, normal_state_ + }, { + CHAR_NORMAL, 0, normal_state_ + } +}; + +// state after ESC ) +StateOption FQTermDecode::VT100StateMachine::select_g1_charset_state_[] = { + { + 'A', &FQTermDecode::selectG1A, normal_state_ + }, { + 'B', &FQTermDecode::selectG1B, normal_state_ + }, { + '0', &FQTermDecode::selectG10, normal_state_ + }, { + '1', &FQTermDecode::selectG11, normal_state_ + }, { + '2', &FQTermDecode::selectG12, normal_state_ + }, { + CHAR_NORMAL, 0, normal_state_ + } +}; + +// state after ESC [ ? +StateOption FQTermDecode::VT100StateMachine::private_state_[] = { + { + '0', &FQTermDecode::paramDigit, private_state_ + }, { + '1', &FQTermDecode::paramDigit, private_state_ + }, { + '2', &FQTermDecode::paramDigit, private_state_ + }, { + '3', &FQTermDecode::paramDigit, private_state_ + }, { + '4', &FQTermDecode::paramDigit, private_state_ + }, { + '5', &FQTermDecode::paramDigit, private_state_ + }, { + '6', &FQTermDecode::paramDigit, private_state_ + }, { + '7', &FQTermDecode::paramDigit, private_state_ + }, { + '8', &FQTermDecode::paramDigit, private_state_ + }, { + '9', &FQTermDecode::paramDigit, private_state_ + }, { + ';', &FQTermDecode::nextParam, private_state_ + }, { + 'h', &FQTermDecode::setDecPrivateMode, normal_state_ + }, { + 'l', &FQTermDecode::resetDecPrivateMode, normal_state_ + }, { + 's', &FQTermDecode::saveMode, normal_state_ + }, { + 'r', &FQTermDecode::restoreMode, normal_state_ + }, { + CHAR_NORMAL, 0, normal_state_ + } +}; + +// state after ESC # +StateOption FQTermDecode::VT100StateMachine::sharp_state_[] = { + { + '8', &FQTermDecode::fillScreen, normal_state_ + }, { + CHAR_NORMAL, 0, normal_state_ + } +}; + +// state after ESC ] +// to change the terminal title dynamically. +// Dynamic titles +// Many people find it useful to set the title of a terminal to reflect dynamic information, +// such as the name of the host the user is logged into, the current working directory, etc. +// This may be done by using XTerm escape sequences. The following sequences are useful in this respect: +// ESC]0;stringBEL Set icon name and window title to string +// ESC]1;stringBEL Set icon name to string +// ESC]2;stringBEL Set window title to string +// where ESC is the escape character (\033), and BEL is the bell character (\007). +// Currently we just ignore this. +StateOption FQTermDecode::VT100StateMachine::title_state_[] = { + { + '0', &FQTermDecode::paramDigit, title_state_ + }, { + '1', &FQTermDecode::paramDigit, title_state_ + }, { + '2', &FQTermDecode::paramDigit, title_state_ + }, { + '4', &FQTermDecode::paramDigit, title_state_ + }, { + '5', &FQTermDecode::paramDigit, title_state_ + }, { + '6', &FQTermDecode::paramDigit, title_state_ + }, { + ';', &FQTermDecode::clearText, title_text_state_ + }, { + CHAR_NORMAL, 0, normal_state_ + } +}; + +StateOption FQTermDecode::VT100StateMachine::title_text_state_[] = { + { + CHAR_ESC, 0, esc_state_ + }, { + CHAR_BELL, &FQTermDecode::setTitle, normal_state_ + }, { + CHAR_NORMAL, &FQTermDecode::collectText, title_state_ + } +}; + +const char *FQTermDecode::getStateName(const StateOption *state) { + if (state == VT100StateMachine::normal_state_) { + return "VT100StateMachine::normal_state_"; + } else if (state == VT100StateMachine::esc_state_) { + return "VT100StateMachine::esc_state_"; + } else if (state == VT100StateMachine::bracket_state_) { + return "VT100StateMachine::bracket_state_"; + } else if (state == VT100StateMachine::private_state_) { + return "VT100StateMachine::private_state_"; + } else if (state == VT100StateMachine::title_state_) { + return "VT100StateMachine::title_state_"; + } else { + return "Unknow"; + } +} + + +FQTermDecode::FQTermDecode(FQTermBuffer *buffer, int server_encoding) { + leftToDecode_.clear(); + termBuffer_ = buffer; + + interrupt_decode_ = false; + + current_state_ = VT100StateMachine::normal_state_; + + default_color_ = NO_COLOR; + default_attr_ = NO_ATTR; + + current_color_ = default_color_; + current_attr_ = default_attr_; + + isBell_ = false; + + termBuffer_->setCurrentAttr(current_color_, current_attr_); + + // TODO_UTF16: please create a encoding enum. + server_encoding_ = server_encoding; + + currentMode_[MODE_MouseX11] = savedMode_[MODE_MouseX11] = false; + FQ_VERIFY(connect(termBuffer_, SIGNAL(caretChangeRow()), this, SLOT(onCaretChangeRow()))); +} + +FQTermDecode::~FQTermDecode() { + +} + +// precess input string from telnet socket +//void FQTermDecode::ansiDecode( const QCString &cstr, int length ) +int FQTermDecode::decode(const char *cstr, int length) { + inputData_ = cstr; + inputLength_ = length; //inputData.length(); + + dataIndex_ = 0; + isBell_ = false; + + interrupt_decode_ = false; + + int i; + StateOption *lastState; + + termBuffer_->startDecode(); + + // here we use FSM to ANSI decoding + // use switch case is ok too + // but i think use function pointer array can make this clear + // you can see the defination at the beginning + while (dataIndex_ < inputLength_) { + // current state always be initialized to point to the deginning of three structures + // ( normalState, escState, bracketState ) + i = 0; + while (current_state_[i].byte != CHAR_NORMAL && current_state_[i].byte != + inputData_[dataIndex_]) { + i++; + } + + // action must be allowed to redirect state change + // get current state with input character i ( hehe, current now become last one ) + lastState = current_state_ + i; // good !! + + bool trace_state = true; + if (current_state_ == VT100StateMachine::normal_state_ + && lastState->nextState == VT100StateMachine::normal_state_) { + trace_state = false; + } + + if (trace_state) { + FQ_TRACE("ansi", 10) << "Current state: " << getStateName(current_state_); + FQ_TRACE("ansi", 10) << dumpHexString << std::string("") + inputData_[dataIndex_] + << dumpNormalString << " " << inputData_[dataIndex_]; + } + + if (lastState->action != 0) { + (this->*(lastState->action))(); + } else { + if (trace_state) FQ_TRACE("ansi", 10) << "No action"; + } + if (trace_state) FQ_TRACE("ansi", 10) << "Next state: " << getStateName(lastState->nextState); + + // reinit current state + current_state_ = lastState->nextState; + + dataIndex_++; + + if (interrupt_decode_) { + break; + } + } + termBuffer_->endDecode(); + + return dataIndex_; +} + + +QString FQTermDecode::bbs2unicode(const QByteArray &text) { + return encoding2unicode(text, server_encoding_); +} + +/////////////////////////////////// +//helper function to decode utf8// +////////////////////////////////// +static int utf8_expected_byte_count(char first_byte) +{ + char expected = 0; + if (!(first_byte & 0x80)) + return 0; //1 byte ascii + else + expected++; + if (!(first_byte & 0x40)) + { + return -1; //not a leading byte. + } + if (!(first_byte & 0x20)) + return expected; + else + expected++; + if (!(first_byte & 0x10)) + return expected; + else + expected++; + if (!(first_byte & 0x08)) + return expected; + return -1; +} + +/////////////////////////////////// +//helper function to decode utf8// +////////////////////////////////// +static int gdbnbig5_expected_byte_count(char first_byte) +{ + char expected = 0; + if (!(first_byte & 0x80)) + return 0; //1 byte ascii + else + expected++; + return expected; +} + +int FQTermDecode::processInput(QByteArray& result) +{ + int charstate = FQTermTextLine::NORMAL; + int expect_bytes = 0; + if (leftToDecode_.size()) + { + switch(server_encoding_) + { + case FQTERM_ENCODING_GBK: + case FQTERM_ENCODING_BIG5: + case FQTERM_ENCODING_HKSCS: + case FQTERM_ENCODING_UAO: + expect_bytes = gdbnbig5_expected_byte_count(leftToDecode_[0]); + break; + case FQTERM_ENCODING_UTF8: + expect_bytes = utf8_expected_byte_count(leftToDecode_[0]); + break; + } + } + + //TODO: error. + if (expect_bytes < 0) { + expect_bytes = 0; + } + + + int n = 0; + int last_char_index = n; + while (((dataIndex_ + n) < inputLength_) && (signed(inputData_[dataIndex_ + n]) >= 0x20 + || signed(inputData_[dataIndex_ + n]) < 0x00)) { + + if (expect_bytes != 0) { + expect_bytes--; + } else { + last_char_index = n; + switch(server_encoding_) + { + case FQTERM_ENCODING_GBK: + case FQTERM_ENCODING_BIG5: + case FQTERM_ENCODING_HKSCS: + case FQTERM_ENCODING_UAO: + expect_bytes = gdbnbig5_expected_byte_count(inputData_[dataIndex_ + n]); + break; + case FQTERM_ENCODING_UTF8: + expect_bytes = utf8_expected_byte_count(inputData_[dataIndex_ + n]); + break; + } + //TODO: error. + if (expect_bytes < 0) { + expect_bytes = 0; + } + + + } + + n++; + } + + if (expect_bytes) { + if(dataIndex_ + n == inputLength_) { + interrupt_decode_ = true; + } + } + + result.clear(); + result.reserve(n + 1); + if (leftToDecode_.size()) { + result += leftToDecode_; + switch(server_encoding_) + { + case FQTERM_ENCODING_GBK: + case FQTERM_ENCODING_BIG5: + case FQTERM_ENCODING_HKSCS: + case FQTERM_ENCODING_UAO: + charstate |= FQTermTextLine::SECONDPART; + break; + case FQTERM_ENCODING_UTF8: + break; + } + leftToDecode_.clear(); + } + int real_n = n; + if (expect_bytes) { + real_n = last_char_index; + leftToDecode_ = QByteArray(inputData_ + dataIndex_ + last_char_index, n - last_char_index); + } + + result.push_back(QByteArray(inputData_ + dataIndex_, real_n)); + if (expect_bytes) { + switch(server_encoding_) + { + case FQTERM_ENCODING_GBK: + case FQTERM_ENCODING_BIG5: + case FQTERM_ENCODING_HKSCS: + case FQTERM_ENCODING_UAO: + result.push_back('?'); //make sure the attr is recorded, + //since last -1 operation can make cstr to be empty + charstate |= FQTermTextLine::FIRSTPART; + break; + case FQTERM_ENCODING_UTF8: + break; + } + } + + n--; + dataIndex_ += n; + + return charstate; +} + + +// fill letters into char buffer +// TODO: this function may contain bug, need double-check. +// 1. input should be ascii-compitable encoding. +void FQTermDecode::normalInput() { + + FQ_FUNC_TRACE("ansi", 8); + + // TODO_UTF16: check ascii-incompitable encoding. + if (signed(inputData_[dataIndex_]) < 0x20 && signed(inputData_[dataIndex_]) >= 0x00) { + // not print char + return ; + } + + QByteArray cstr; + int charstate = processInput(cstr); + + + + QString str = bbs2unicode(cstr); + FQ_TRACE("normal_input", 9) << "hex: " << dumpHexString + << str.toLocal8Bit().constData() ; + FQ_TRACE("normal_input", 9) << "text: " << str; + termBuffer_->writeText(str, charstate); + +} + +// non-printing characters functions +void FQTermDecode::cr() { + FQ_FUNC_TRACE("ansi", 8); + // FIXME: dirty + termBuffer_->carriageReturn(); +} + +void FQTermDecode::lf() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->lineFeed(); +} + +void FQTermDecode::ff() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->eraseEntireTerm(); + + termBuffer_->moveCaretTo(0, 0); +} + +void FQTermDecode::tab() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->tab(); +} + +void FQTermDecode::bs() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->moveCaretOffset(-1, 0); +} + +void FQTermDecode::bell() { + FQ_FUNC_TRACE("ansi", 8); + isBell_ = true; +} + +void FQTermDecode::del() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->moveCaretOffset(-1, 0); + //termBuffer_->deleteText(1); +} + +void FQTermDecode::g0() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->invokeCharset(true); +} + +void FQTermDecode::g1() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->invokeCharset(false); +} + +void FQTermDecode::enq() { + emit enqReceived(); +} + +void FQTermDecode::addTabStop() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->addTabStop(); +} + +void FQTermDecode::clearTabStop() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + if (param_[0] == 0) { + termBuffer_->clearTabStop(false); + } else if (param_[0] == 3) { + termBuffer_->clearTabStop(true); + } +} + +void FQTermDecode::setMargins() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + if (isParamAvailable_) { + termBuffer_->setMargins(param_[0] - 1, param_[1] - 1); + } else { + termBuffer_->setMargins(0, termBuffer_->getNumRows() - 1); + } +} + +// parameters functions +void FQTermDecode::clearParam() { + FQ_FUNC_TRACE("ansi", 9); + paramIndex_ = 0; + memset(param_, 0, sizeof(param_)); + isParamAvailable_ = false; +} + +// for performance, this grabs all digits +void FQTermDecode::paramDigit() { + FQ_FUNC_TRACE("ansi", 10); + isParamAvailable_ = true; + + // make stream into number + // ( e.g. this input character is '1' and this param is 4 + // after the following sentence this param is changed to 41 + param_[paramIndex_] = param_[paramIndex_] *10+inputData_[dataIndex_] - '0'; +} + +void FQTermDecode::nextParam() { + FQ_FUNC_TRACE("ansi", 9); + paramIndex_++; +} + +void FQTermDecode::saveCursor() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->saveCaret(); +} + +void FQTermDecode::restoreCursor() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->restoreCaret(); +} + +void FQTermDecode::cursorPosition() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int x = param_[1]; + int y = param_[0]; + + if (x == 0) { + x = 1; + } + if (y == 0) { + y = 1; + } + + termBuffer_->changeCaretPosition(x - 1, y - 1); +} + +void FQTermDecode::cursorLeft() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int n = param_[0]; + + if (n < 1) { + n = 1; + } + + termBuffer_->moveCaretOffset(-n, 0); +} + +void FQTermDecode::cursorRight() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int n = param_[0]; + + if (n < 1) { + n = 1; + } + + termBuffer_->moveCaretOffset(n, 0); +} + +void FQTermDecode::cursorUp() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int n = param_[0]; + + if (n < 1) { + n = 1; + } + + termBuffer_->moveCaretOffset(0, -n); +} + +void FQTermDecode::cursorDown() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int n = param_[0]; + + if (n < 1) { + n = 1; + } + + termBuffer_->moveCaretOffset(0, n); +} + +void FQTermDecode::moveCursorUp() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->scrollTerm(-1);//moveCaretOffset(0, -1, true); +} + +void FQTermDecode::moveCursorDown() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->scrollTerm(1);//moveCaretOffset(0, 1, true); +} + +void FQTermDecode::nextLine() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->carriageReturn(); + termBuffer_->moveCaretOffset(0, 1, true); +} + +void FQTermDecode::selectG0A() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet(FQTermBuffer::UNITED_KINGDOM_SET, true); +} + +void FQTermDecode::selectG0B() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet(FQTermBuffer::ASCII_SET, true); +} + +void FQTermDecode::selectG00() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet(FQTermBuffer::SPECIAL_GRAPHICS, true); +} + +void FQTermDecode::selectG01() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet( + FQTermBuffer::ALTERNATE_CHARACTER_ROM_STANDARD_CHARACTER_SET, true); +} + +void FQTermDecode::selectG02() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet( + FQTermBuffer::ALTERNATE_CHARACTER_ROM_SPECIAL_GRAPHICS, true); +} + +void FQTermDecode::selectG1A() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet(FQTermBuffer::UNITED_KINGDOM_SET, false); +} + +void FQTermDecode::selectG1B() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet(FQTermBuffer::ASCII_SET, false); +} + +void FQTermDecode::selectG10() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet(FQTermBuffer::SPECIAL_GRAPHICS, false); +} + +void FQTermDecode::selectG11() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet( + FQTermBuffer::ALTERNATE_CHARACTER_ROM_STANDARD_CHARACTER_SET, false); +} + +void FQTermDecode::selectG12() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->SelectVtCharacterSet( + FQTermBuffer::ALTERNATE_CHARACTER_ROM_SPECIAL_GRAPHICS, false); +} + +// erase functions +void FQTermDecode::eraseStr() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int n = param_[0]; + + if (n < 1) { + n = 1; + } + + termBuffer_->eraseText(n); +} + +// insert functions +void FQTermDecode::insertStr() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int n = param_[0]; + + if (n < 1) { + n = 1; + } + + termBuffer_->insertSpaces(n); +} + +// delete functions +void FQTermDecode::deleteStr() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int n = param_[0]; + + if (n < 1) { + n = 1; + } + + termBuffer_->deleteText(n); +} + +void FQTermDecode::eraseLine() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + switch (param_[0]) { + case 0: + termBuffer_->eraseToLineEnd(); + break; + case 1: + termBuffer_->eraseToLineBegin(); + break; + case 2: + termBuffer_->eraseEntireLine(); + break; + default: + break; + } +} + +void FQTermDecode::insertLine() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int n = param_[0]; + + if (n < 1) { + n = 1; + } + + termBuffer_->insertLines(n); +} + +void FQTermDecode::deleteLine() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + int n = param_[0]; + + if (n < 1) { + n = 1; + } + + termBuffer_->deleteLines(n); +} + +void FQTermDecode::eraseScreen() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + switch (param_[0]) { + case 0: + termBuffer_->eraseToTermEnd(); + break; + case 1: + termBuffer_->eraseToTermBegin(); + break; + case 2: + termBuffer_->eraseEntireTerm(); + break; + case 3: + break; + } +} + +void FQTermDecode::setAttr() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + // get all attributes of character + if (!paramIndex_ && param_[0] == 0) { + current_color_ = default_color_; + current_attr_ = default_attr_; + + termBuffer_->setCurrentAttr(current_color_, current_attr_); + return ; + } + + unsigned char cp = current_color_; + unsigned char ea = current_attr_; + for (int n = 0; n <= paramIndex_; n++) { + if (param_[n] / 10 == 4) { + // background color + cp = cp &~BGMASK; + cp += SETBG(param_[n] % 10); + } else if (param_[n] / 10 == 3) { + // front color + cp = cp &~FGMASK; + cp += SETFG(param_[n] % 10); + } else { + switch (param_[n]) { + case 0: + // attr off + cp = default_color_; //NO_COLOR; + ea = default_attr_; //NO_ATTR; + break; + case 1: + // bright + ea = SETBRIGHT(ea); + break; + case 2: + // dim + ea = SETDIM(ea); + break; + case 4: + // underline + ea = SETUNDERLINE(ea); + break; + case 5: + // blink + ea = SETBLINK(ea); + break; + case 7: + // reverse + ea = SETREVERSE(ea); + break; + case 8: + // invisible + ea = SETINVISIBLE(ea); + break; + default: + break; + } + } + } + + current_color_ = cp; + current_attr_ = ea; + + termBuffer_->setCurrentAttr(current_color_, current_attr_); +} + +void FQTermDecode::setMode() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + for (int i = 0; i <= paramIndex_; i++) { + int n = param_[i]; + switch (n) { + case 4: + termBuffer_->setMode(FQTermBuffer::INSERT_MODE); + break; + case 20: + termBuffer_->setMode(FQTermBuffer::NEWLINE_MODE); + break; + default: + break; + } + } +} + +void FQTermDecode::resetMode() { + //TODO: more modes here. + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + for (int i = 0; i <= paramIndex_; i++) { + int n = param_[i]; + switch (n) { + case 4: + termBuffer_->resetMode(FQTermBuffer::INSERT_MODE); + break; + case 20: + termBuffer_->resetMode(FQTermBuffer::NEWLINE_MODE); + break; + default: + break; + } + } +} + +void FQTermDecode::setDecPrivateMode() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + for (int i = 0; i <= paramIndex_; i++) { + int n = param_[i]; + switch (n) { + case 1: + termBuffer_->setMode(FQTermBuffer::CURSOR_MODE); + break; + case 2: + termBuffer_->setMode(FQTermBuffer::ANSI_MODE); + break; + case 3: + termBuffer_->setTermSize(132, 24); + break; + case 4: + // smooth scrolling mode + // nothing to do. + break; + case 5: + termBuffer_->setMode(FQTermBuffer::LIGHTBG_MODE); + break; + case 6: + termBuffer_->setMode(FQTermBuffer::ORIGIN_MODE); + break; + case 7: + termBuffer_->setMode(FQTermBuffer::AUTOWRAP_MODE); + break; + case 8: + termBuffer_->setMode(FQTermBuffer::AUTOREPEAT_MODE); + break; + case 9: + // Interlace mode + // nothing to do. + break; + case 1000: + case 1001: + emit mouseMode(true); + currentMode_[MODE_MouseX11] = true; + break; + default: + break; + } + } +} + +void FQTermDecode::resetDecPrivateMode() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + for (int i = 0; i <= paramIndex_; i++) { + int n = param_[i]; + switch (n) { + case 1: + termBuffer_->resetMode(FQTermBuffer::CURSOR_MODE); + break; + case 2: + termBuffer_->resetMode(FQTermBuffer::ANSI_MODE); + break; + case 3: + termBuffer_->setTermSize(80, 24); + break; + case 4: + // jump scrolling mode + // nothing to do. + break; + case 5: + termBuffer_->resetMode(FQTermBuffer::LIGHTBG_MODE); + break; + case 6: + termBuffer_->resetMode(FQTermBuffer::ORIGIN_MODE); + break; + case 7: + termBuffer_->resetMode(FQTermBuffer::AUTOWRAP_MODE); + break; + case 8: + termBuffer_->resetMode(FQTermBuffer::AUTOREPEAT_MODE); + break; + case 9: + // Interlace mode + // nothing to do. + break; + case 1000: + case 1001: + currentMode_[MODE_MouseX11] = false; + emit mouseMode(false); + break; + default: + break; + } + } +} + +void FQTermDecode::setNumericKeypad() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->setMode(FQTermBuffer::NUMERIC_MODE); +} + +void FQTermDecode::setAppKeypad() { + FQ_FUNC_TRACE("ansi", 8); + termBuffer_->resetMode(FQTermBuffer::NUMERIC_MODE); +} + +void FQTermDecode::saveMode() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + for (int i = 0; i <= paramIndex_; i++) { + int n = param_[i]; + switch (n) { + case 1000: + case 1001: + savedMode_[MODE_MouseX11] = currentMode_[MODE_MouseX11]; + break; + default: + break; + } + } +} + +void FQTermDecode::restoreMode() { + FQ_FUNC_TRACE("ansi", 8); + logParam(); + + for (int i = 0; i <= paramIndex_; i++) { + int n = param_[i]; + switch (n) { + case 1000: + case 1001: + currentMode_[MODE_MouseX11] = savedMode_[MODE_MouseX11]; + emit mouseMode(currentMode_[MODE_MouseX11]); + break; + default: + break; + } + } +} + +void FQTermDecode::fillScreen() { + FQ_FUNC_TRACE("ansi", 8); + + termBuffer_->fillScreenWith('E'); +} + +void FQTermDecode::test() { + FQ_FUNC_TRACE("ansi", 8); +} + +void FQTermDecode::logParam() const { + if (isParamAvailable_) { + for (int i = 8; i <= paramIndex_; ++i) { + FQ_TRACE("ansi", 8) << "Parameter[" << i << "] = " << param_[i]; + } + } else { + FQ_TRACE("ansi", 8) << "No parameter."; + } +} + +void FQTermDecode::onCaretChangeRow() { + leftToDecode_.clear(); +} + +void FQTermDecode::setTitle() { + if (!isParamAvailable_) { + return; + } + switch(param_[0]) + { + case 0: + //icon and text + break; + case 1: + //icon + break; + case 2: + //text + emit onTitleSet(bbs2unicode(textParam_)); + break; + case 46: + //log file + break; + case 50: + //font + break; + default: + break; + } +} + +void FQTermDecode::collectText() { + FQ_FUNC_TRACE("ansi", 10); + if (textParam_.length() < 4096) + textParam_ += inputData_[dataIndex_]; +} + +void FQTermDecode::clearText() { + FQ_FUNC_TRACE("ansi", 10); + textParam_.clear(); +} + + + + +} // namespace FQTerm + +#include "fqterm_decode.moc" diff --git a/src/terminal/internal/fqterm_decode.h b/src/terminal/internal/fqterm_decode.h new file mode 100644 index 0000000..5f3f46d --- /dev/null +++ b/src/terminal/internal/fqterm_decode.h @@ -0,0 +1,194 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_DECODE_H +#define FQTERM_DECODE_H + +#include +#include "fqterm_text_line.h" + +namespace FQTerm { + +class FQTermDecode; +class FQTermBuffer; +class FQTermTelnet; + +// this for FSM +typedef void(FQTermDecode:: *StateFunc)(); + +struct StateOption { + int byte; // char value to look for; -1==end/default + StateFunc action; + StateOption *nextState; +}; + +class FQTermDecode: public QObject { + Q_OBJECT; + public: + FQTermDecode(FQTermBuffer *, int server_encoding); + ~FQTermDecode(); + + + // translate data from telnet socket to our own buffer + // return how many bytes are processed. + int decode(const char *cstr, int length); + + bool bellReceive() { + return isBell_; + } + + void setServerEncoding(int encoding) { + server_encoding_ = encoding; + } + + + //signals: + // void decodeFinished(); + signals: + void mouseMode(bool); + void enqReceived(); + void onTitleSet(const QString&); + public slots: + void onCaretChangeRow(); + private: + // escape sequence actions + // you'd better see FSM structure array in FQTermDecode.cpp + + void setAttr(); + void setMargins(); + + // char screen functions + void deleteStr(); + void deleteLine(); + void insertStr(); + void insertLine(); + void eraseStr(); + void eraseLine(); + void eraseScreen(); + + // cursor functions + void saveCursor(); + void restoreCursor(); + void cursorPosition(); + + // Move cursor, stop at boundary. + void cursorLeft(); + void cursorDown(); + void cursorRight(); + void cursorUp(); + + // Move cursor, scroll at boundary. + void moveCursorUp(); + void moveCursorDown(); + void nextLine(); + + void selectG0A(); + void selectG0B(); + void selectG00(); + void selectG01(); + void selectG02(); + + void selectG1A(); + void selectG1B(); + void selectG10(); + void selectG11(); + void selectG12(); + + // other escape sequence actions + void normalInput(); + + //title settings + void setTitle(); + void collectText(); + void clearText(); + + // action parameters + void clearParam(); + void paramDigit(); + void nextParam(); + + // non-printing characters + void cr(), lf(), ff(), bell(), tab(), bs(), del(), g0(), g1(), enq(); + + void addTabStop(); + void clearTabStop(); + + void setMode(); + void resetMode(); + void setDecPrivateMode(); + void resetDecPrivateMode(); + void setNumericKeypad(); + void setAppKeypad(); + + void saveMode(); + void restoreMode(); + + // video alignment test - fill screen with E's. + void fillScreen(); + + void test(); + + private: + + bool isBell_; + // short currentAttr_, defaultAttr_; + unsigned char current_color_, default_color_; + unsigned char current_attr_, default_attr_; + + // ********** ansi decoder states **************** + StateOption *current_state_; + + struct VT100StateMachine { + static StateOption normal_state_[], esc_state_[], bracket_state_[]; + static StateOption private_state_[], sharp_state_[]; + static StateOption title_state_[], title_text_state_[]; + static StateOption select_g0_charset_state_[], select_g1_charset_state_[]; + }; + + static const char *getStateName(const StateOption *state); + + void logParam() const; + + + bool interrupt_decode_; + + // ********** decoder ***************** + const char *inputData_; + int inputLength_, dataIndex_; + + int paramIndex_, param_[30]; + bool isParamAvailable_; + + QByteArray textParam_; + + bool savedMode_[30]; + bool currentMode_[30]; + + FQTermBuffer *termBuffer_; + int server_encoding_; + + QString bbs2unicode(const QByteArray &text); + int processInput(QByteArray& result); + QByteArray leftToDecode_; +}; + +} // namespace FQTerm + +#endif // FQTERM_DECODE_H diff --git a/src/terminal/internal/fqterm_telnet.cpp b/src/terminal/internal/fqterm_telnet.cpp new file mode 100644 index 0000000..2446b8a --- /dev/null +++ b/src/terminal/internal/fqterm_telnet.cpp @@ -0,0 +1,1041 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include + +#include + +#include "fqterm.h" +#include "fqterm_telnet.h" +#include "fqterm_socket.h" + +#ifndef _NO_SSH_COMPILED +#include "fqterm_ssh_socket.h" +#endif + +/* TELNET Command Codes: */ +/* Hints: These NVT control characters are sent from client to server, So + the client side will not receive these commands */ +#define TCSB (u_char)250 /* Start Subnegotiation */ +#define TCSE (u_char)240 /* End Of Subnegotiation */ +#define TCNOP (u_char)241 /* No Operation */ +#define TCDM (u_char)242 /* Data Mark (for Sync) */ +#define TCBRK (u_char)243 /* NVT Character BRK */ +#define TCIP (u_char)244 /* Interrupt Process */ +#define TCAO (u_char)245 /* Abort Output */ +#define TCAYT (u_char)246 /* "Are You There?" Function */ +#define TCEC (u_char)247 /* Erase Character */ +#define TCEL (u_char)248 /* Erase Line */ +#define TCGA (u_char)249 /* "Go Ahead" Function */ +#define TCWILL (u_char)251 /* Desire/Confirm Will Do Option*/ +#define TCWONT (u_char)252 /* Refusal To Do Option */ +#define TCDO (u_char)253 /* Request To Do Option */ +#define TCDONT (u_char)254 /* Request NOT To Do Option */ +#define TCIAC (u_char)255 /* Interpret As Command Escape */ + +/* Telnet Option Codes: */ +#define TOTXBINARY (u_char) 0 /* TRANSMIT-BINARY option */ +#define TOECHO (u_char) 1 /* ECHO Option */ +#define TONOGA (u_char) 3 /* Suppress Go-Ahead Option */ +#define TOTERMTYPE (u_char) 24 /* Terminal-Type Option */ +#define TONAWS (u_char) 31 /* Window Size */ + +/* Network Virtual Printer Special Characters: */ +/* In normal situations, these characters will to translated into local + control characters , then pass to upper layer term. But in our situation, + we can pass them to term directly */ + +#define VPLF '\n' /* Line Feed */ +#define VPCR '\r' /* Carriage Return */ +#define VPBEL '\a' /* Bell (attention signal) */ +#define VPBS '\b' /* Back Space */ +#define VPHT '\t' /* Horizontal Tab */ +#define VPVT '\v' /* Vertical Tab */ +#define VPFF '\f' /* Form Feed */ + +/* Keyboard Command Characters: */ + +/* Option Subnegotiation Constants: */ +#define TT_IS 0 /* TERMINAL_TYPE option "IS" command */ +#define TT_SEND 1 /* TERMINAL_TYPE option "SEND" command */ + +/* Telnet Socket-Input FSM States: */ +#define TSDATA 0 /* normal data processing */ +#define TSIAC 1 /* have seen IAC */ +#define TSWOPT 2 /* have seen IAC-{WILL/WONT} */ +#define TSDOPT 3 /* have seen IAC-{DO/DONT} */ +#define TSSUBNEG 4 /* have seen IAC-SB */ +#define TSSUBIAC 5 /* have seen IAC-SB-...-IAC */ +// if any state added here, please update NTSTATES (currently 6). + +// Telnet Option Subnegotiation FSM States: +#define SS_START 0 // initial state +#define SS_TERMTYPE 1 // TERMINAL_TYPE option subnegotiation +#define SS_END 2 // state after all legal input +// if any state added here, please update NSSTATES (currently 3). + +#define FSINVALID 0xff // an invalid state number +#define TCANY (NCHRS+1) // match any character + +#define TINVALID 0xff // an invalid transition index + +namespace FQTerm { + +struct fsm_trans FQTermTelnet::ttstab[] = { + /* State Input Next State Action */ + /* ------ ------ ----------- ------- */ + { + TSDATA, TCIAC, TSIAC, &FQTermTelnet::no_op + }, { + TSDATA, TCANY, TSDATA, &FQTermTelnet::ttputc + }, { + TSIAC, TCIAC, TSDATA, &FQTermTelnet::ttputc + }, { + TSIAC, TCSB, TSSUBNEG, &FQTermTelnet::no_op + }, {/* Telnet Commands */ + TSIAC, TCNOP, TSDATA, &FQTermTelnet::no_op + }, { + TSIAC, TCDM, TSDATA, &FQTermTelnet::tcdm + }, { /* Option Negotiation */ + TSIAC, TCWILL, TSWOPT, &FQTermTelnet::recopt + }, { + TSIAC, TCWONT, TSWOPT, &FQTermTelnet::recopt + }, { + TSIAC, TCDO, TSDOPT, &FQTermTelnet::recopt + }, { + TSIAC, TCDONT, TSDOPT, &FQTermTelnet::recopt + }, { + TSIAC, TCANY, TSDATA, &FQTermTelnet::no_op + }, { /* Option Subnegotion */ + TSSUBNEG, TCIAC, TSSUBIAC, &FQTermTelnet::no_op + }, { + TSSUBNEG, TCANY, TSSUBNEG, &FQTermTelnet::subopt + }, { + TSSUBIAC, TCSE, TSDATA, &FQTermTelnet::subend + }, { + TSSUBIAC, TCANY, TSSUBNEG, &FQTermTelnet::subopt + }, { + TSWOPT, TOECHO, TSDATA, &FQTermTelnet::do_echo + }, { + TSWOPT, TONOGA, TSDATA, &FQTermTelnet::do_noga + }, { + TSWOPT, TOTXBINARY, TSDATA, &FQTermTelnet::do_txbinary + }, { + TSWOPT, TCANY, TSDATA, &FQTermTelnet::do_notsup + },{ + TSDOPT, TONAWS, TSDATA, &FQTermTelnet::will_naws + }, { + TSDOPT, TOTERMTYPE, TSDATA, &FQTermTelnet::will_termtype + }, { + TSDOPT, TOTXBINARY, TSDATA, &FQTermTelnet::will_txbinary + }, { + TSDOPT, TCANY, TSDATA, &FQTermTelnet::will_notsup + }, { + FSINVALID, TCANY, FSINVALID, &FQTermTelnet::tnabort + }, +}; + + +struct fsm_trans FQTermTelnet::substab[] = { + /* State Input Next State Action */ + /* ---------------------------------------------------- */ + { + SS_START, TOTERMTYPE, SS_TERMTYPE, &FQTermTelnet::no_op + }, { + SS_START, TCANY, SS_END, &FQTermTelnet::no_op + }, { + SS_TERMTYPE, TT_SEND, SS_END, &FQTermTelnet::subtermtype + }, { + SS_TERMTYPE, TCANY, SS_END, &FQTermTelnet::no_op + }, { + SS_END, TCANY, SS_END, &FQTermTelnet::no_op + }, { + FSINVALID, TCANY, FSINVALID, &FQTermTelnet::tnabort + }, +}; + + + +/*------------------------------------------------------------------------ + * Constructor + *------------------------------------------------------------------------ + */ +FQTermTelnet::FQTermTelnet(const QString &strTermType, int rows, int columns, + int protocolType, int hostType, const char *sshuser, const char *sshpasswd) + : from_socket(), + to_ansi(), + from_ansi(), + to_socket(), + hostType_(hostType), + protocolType_(protocolType) { + term = new char[21]; + memset(term, 0, sizeof(term)); + // TODO: clean up, need??? +#ifdef WIN32 + _snprintf(term, sizeof(term), "%s", strTermType.toLatin1().constData()); +#else + strncpy(term,strTermType.toLatin1(),20); +#endif + + wx = columns; + wy = rows; + wsize = 0; + done_naws = 0; + synching = 0; + doecho = 0; + sndbinary = 0; + rcvbinary = 0; + noga = 0; + termtype = 0; + naws = 0; + server_sent_do_naws = 0; + raw_size = 0; + +#ifndef _NO_SSH_COMPILED + if (protocolType == 1 || protocolType == 2) { + socket = new FQTermSSHSocket(columns, rows, strTermType, sshuser, sshpasswd); + FQ_VERIFY(connect(socket, SIGNAL(sshAuthOK()), + this, SIGNAL(onSSHAuthOK()))); + } else if (protocolType == 3) { + socket = new FQTermLocalSocket(""); + } else { + socket = new FQTermTelnetSocket(); + } +#else + socket = new FQTermTelnetSocket(); +#endif + + // connect signal and slots + FQ_VERIFY(connect(socket, SIGNAL(connected()), this, SLOT(connected()))); + FQ_VERIFY(connect(socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()))); + FQ_VERIFY(connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(showError(QAbstractSocket::SocketError)))); + FQ_VERIFY(connect(socket, SIGNAL(hostFound()), this, SLOT(hostFound()))); + FQ_VERIFY(connect(socket, SIGNAL(delayedCloseFinished()), + this, SLOT(delayCloseFinished()))); + FQ_VERIFY(connect(socket, SIGNAL(connectionClosed()), this, SLOT(closed()))); + FQ_VERIFY(connect(socket, SIGNAL(socketState(int)), this, SIGNAL(TelnetState(int)))); + + FQ_VERIFY(connect(socket, SIGNAL(requestUserPwd(QString *, QString *, bool *)), + this, SIGNAL(requestUserPwd(QString *, QString *, bool *)))); + + FQ_VERIFY(connect(socket, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString)))); + + // Init telnet, mainly the FSMs + init_telnet(); +} + +/*------------------------------------------------------------------------ + * destructor + *------------------------------------------------------------------------ + */ +FQTermTelnet::~FQTermTelnet() { + // delete objects + delete [] term; + delete socket; +} + + + +/*------------------------------------------------------------------------ + * init_telnet + *------------------------------------------------------------------------ + */ +void FQTermTelnet::init_telnet() { + fsmbuild(); /* setup FSMs */ +} + + +/*------------------------------------------------------------------------ + * fsmbuild - build the Finite State Machine data structures + *------------------------------------------------------------------------ + */ +void FQTermTelnet::fsmbuild() { + fsminit(ttfsm, ttstab, NTSTATES); + ttstate = TSDATA; + + fsminit(subfsm, substab, NSSTATES); + substate = SS_START; + +} + +/*------------------------------------------------------------------------ + * fsminit - Finite State Machine initializer + *------------------------------------------------------------------------ + */ +void FQTermTelnet::fsminit(u_char fsm[][NCHRS], struct fsm_trans ttab[], int + nstates) { + struct fsm_trans *pt; + int sn, ti, cn; + + for (cn = 0; cn < NCHRS; ++cn) { + for (ti = 0; ti < nstates; ++ti) { + fsm[ti][cn] = TINVALID; + } + } + + for (ti = 0; ttab[ti].ft_state != FSINVALID; ++ti) { + pt = &ttab[ti]; + sn = pt->ft_state; + if (pt->ft_char == TCANY) { + for (cn = 0; cn < NCHRS; ++cn) { + if (fsm[sn][cn] == TINVALID) { + fsm[sn][cn] = ti; + } + } + } else { + fsm[sn][pt->ft_char] = ti; + } + } + + /* set all uninitialized indices to an invalid transition */ + for (cn = 0; cn < NCHRS; ++cn) { + for (ti = 0; ti < nstates; ++ti) { + if (fsm[ti][cn] == TINVALID) { + fsm[ti][cn] = ti; + } + } + } + +} + +/*------------------------------------------------------------------------ + * connect to host + *------------------------------------------------------------------------ + */ +void FQTermTelnet::connectHost(const QString &hostname, quint16 portnumber) { + done_naws = 0; + synching = 0; + doecho = 0; + sndbinary = 0; + rcvbinary = 0; + noga = 0; + termtype = 0; + naws = 0; + + socket->connectToHost(hostname, portnumber); + // host name resolving + emit TelnetState(TSRESOLVING); +} + +void FQTermTelnet::windowSizeChanged(int x, int y) { + wx = x; + wy = y; + if (bConnected) { + if (hostType_ == 1 && (protocolType_ == 1 || protocolType_ == 2)) { + //This is a *nix host, with ssh connection. + socket->setTermSize(x, y); + return; + } + naws = 0; + + QByteArray cmd(10, 0); + cmd[0] = (char)TCIAC; + cmd[1] = (char)TCSB; + cmd[2] = (char)TONAWS; + cmd[3] = (char)(short(wx) >> 8); + cmd[4] = (char)(short(wx) & 0xff); + cmd[5] = (char)(short(wy) >> 8); + cmd[6] = (char)(short(wy) & 0xff); + cmd[7] = (char)TCIAC; + cmd[8] = (char)TCSE; + socket->writeBlock(cmd); + + } +} + +/*------------------------------------------------------------------------ + * set proxy + *----------------------------------------------------------------------- + */ +void FQTermTelnet::setProxy(int nProxyType, bool bAuth, const QString + &strProxyHost, quint16 uProxyPort, + const QString &strProxyUsr, + const QString &strProxyPwd) { + socket->setProxy(nProxyType, bAuth, strProxyHost, + uProxyPort, strProxyUsr, strProxyPwd); +} + +/*------------------------------------------------------------------------ + * close connection + *----------------------------------------------------------------------- + */ + +void FQTermTelnet::close() { + socket->close(); +} + +/*------------------------------------------------------------------------ + * SLOT connected + *------------------------------------------------------------------------ + */ +void FQTermTelnet::connected() { + bConnected = true; + emit TelnetState(TSHOSTCONNECTED); +} + +/*------------------------------------------------------------------------ + * SLOT closed + *------------------------------------------------------------------------ + */ + +void FQTermTelnet::closed() { + bConnected = false; + emit TelnetState(TSCLOSED); +} + +/*------------------------------------------------------------------------ + * SLOT delayCloseFinished + *------------------------------------------------------------------------ + */ + +void FQTermTelnet::delayCloseFinished() { + bConnected = false; + emit TelnetState(TSCLOSEFINISH); +} + +/*------------------------------------------------------------------------ + * SLOT hostFound + *------------------------------------------------------------------------ + */ +void FQTermTelnet::hostFound() { + emit TelnetState(TSHOSTFOUND); +} + +/*------------------------------------------------------------------------ + * SLOT error + *------------------------------------------------------------------------ + */ +void FQTermTelnet::showError(QAbstractSocket::SocketError index) { + + switch (index) { + case QAbstractSocket::ConnectionRefusedError: emit TelnetState(TSREFUSED); + break; + case QAbstractSocket::HostNotFoundError: emit TelnetState(TSHOSTNOTFOUND); + break; + //FIXME: am I right + case QAbstractSocket::SocketAccessError: emit TelnetState(TSREADERROR); + break; + case QAbstractSocket::RemoteHostClosedError: emit TelnetState(TSCLOSED); + break; + default: + emit TelnetState(TSERROR); + ; + break; + } + +} + +/*------------------------------------------------------------------------ + * SLOOT socketReadyRead - + * when socket has data to upload, it send out readyRead() signal, it + * invokes this SLOT to read data in, do telnet decode job, and send out + * readyRead() SIGNAL to upper layer + *------------------------------------------------------------------------ + */ +void FQTermTelnet::socketReadyRead() { + int nbytes, nread; + // TODO_UTF16: check this function. + + // get the data size + nbytes = socket->bytesAvailable(); + if (nbytes <= 0) { + return ; + } + + raw_size = nbytes; + + //resize input buffer + from_socket.resize(0); + + //read data from socket to from_socket + from_socket = socket->readBlock(nbytes); + nread = from_socket.size(); + //do some checks + if (nread <= 0) { + FQ_TRACE("telnet", 8) << "Failed to read socket: " << nread << " <= 0."; + return ; + } + if (nread > nbytes) { + FQ_TRACE("telnet", 0) << "Overflow when reading socket: " + << " nread = " << nread + << " > nbytes = " << nbytes; + return ; + } + + //resize output buffer + to_ansi.resize(2 *nread); + to_socket.resize(4 *nread); + + rsize = 0; + wsize = 0; + + // do telnet decode job... + struct fsm_trans *pt; + int i, ti; + + u_char c; + for (i = 0; i < nread; ++i) { + c = (u_char)(from_socket[i]); + ti = ttfsm[ttstate][c]; + pt = &ttstab[ti]; + (this->*(pt->ft_action))((int)c); + ttstate = pt->ft_next; + } + + // flush the to_socket buffer, it contain response to server + if (wsize > 0) { + socket->writeBlock(to_socket.left(wsize)); + socket->flush(); + } + + /* send SIGNAL readyRead() with the size of data available*/ + if (rsize > 0 || raw_size > 0) { + emit readyRead(rsize, raw_size); + } + +} + +int FQTermTelnet::raw_len() { + return raw_size; +} + +/*------------------------------------------------------------------------ + * actions + *------------------------------------------------------------------------ + */ +int FQTermTelnet::read_raw(char *data, uint maxlen) { + //do some checks + if (data == 0) { + FQ_TRACE("telnet", 0) << "NULL pointer."; + return -1; + } + if ((long)maxlen < raw_size) { + /* we need all data be read out in one read */ + FQ_TRACE("telnet", 0) << "The upper layer's buffer is too small."; + return -1; + } + + //do it, memcpy( destination, source, size) + memcpy(data, from_socket.data(), raw_size); + return raw_size; +} + + +/*------------------------------------------------------------------------ + * actions + *------------------------------------------------------------------------ + */ +int FQTermTelnet::read(char *data, uint maxlen) { + //do some checks + if (data == 0) { + FQ_TRACE("telent", 0) << "NULL pointer."; + return -1; + } + if (maxlen < rsize) { + /* we need all data be read out in one read */ + FQ_TRACE("telnet", 0) << "The upper layer's buffer is too small."; + return -1; + } + + //do it, memcpy( destination, source, size) + memcpy(data, to_ansi.data(), rsize); + + FQ_TRACE("telnet", 8) << "read " << rsize << " bytes:\n" + << dumpHexString << std::string(data, rsize); + + return rsize; +} + +/*------------------------------------------------------------------------ + * actions + *------------------------------------------------------------------------ + */ + + +/*------------------------------------------------------------------------ + * writeBlock + * write data from data-> to socket, the length of data is len + *------------------------------------------------------------------------ + */ +int FQTermTelnet::write(const char *data, uint len) { + // TODO: accept data, (This seems can be removed????) + from_ansi.resize(len); + memcpy(from_ansi.data(), data, len); + + // resize output buffer + to_socket.resize(2 *len); + wsize = 0; + + // process keyboard input + // because we use GUI, there is no need to support a "command mode" + // So the keyboard-input FSM isnt' necessary. + + uint i; + + u_char c; // TODO: for gcc's happy :) + for (i = 0; i < len; ++i) { + c = (u_char)(from_ansi[i]); + soputc((int)c); + } + + FQ_TRACE("telnet", 2) << "write " << len << " bytes:\n" + << dumpHexString << std::string(data, len); + + //flush socket + socket->writeBlock(to_socket.left(wsize)); + socket->flush(); + + emit TelnetState(TSWRITED); + return 0; +} + + +/*------------------------------------------------------------------------ + * Trans functions + * All trans functions use from_socket, to_ansi, to_socket buffers, and + * rsize, wsize . + *------------------------------------------------------------------------ + */ + +/*------------------------------------------------------------------------ + * tcdm - handle the telnet "DATA MARK" command (marks end of SYNCH) + *------------------------------------------------------------------------ + */ +int FQTermTelnet::tcdm(int) { + if (synching > 0) { + synching--; + } + return 0; +} + +/*------------------------------------------------------------------------ + * rcvurg - receive urgent data input (indicates a telnet SYNCH) + *------------------------------------------------------------------------ + */ +/* + int FQTermTelnet::rcvurg(int sig) + { + synching++; + } +*/ + +/*------------------------------------------------------------------------ + * recopt - record option type + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::recopt(int c) { + option_cmd = c; + return 0; +} + +/*------------------------------------------------------------------------ + * no_op - do nothing + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::no_op(int) { + return 0; +} + + +/*------------------------------------------------------------------------ + * do_echo - handle TELNET WILL/WON'T ECHO option + *------------------------------------------------------------------------ + */ +int FQTermTelnet::do_echo(int c) { + if (doecho) { + if (option_cmd == TCWILL) { + return 0; + } + /* already doing ECHO */ + } else if (option_cmd == TCWONT) { + return 0; + } + /* already NOT doing ECHO */ + + doecho = !doecho; + + putc_down(TCIAC); + if (doecho) { + putc_down(TCDO); + } else { + putc_down(TCDONT); + } + putc_down((char)c); + return 0; +} + +/*------------------------------------------------------------------------ + * putc_down - put a character in to_socket buffer. + * wsize represent the number of bytes in to_socket buffer, and the buffer + * is addressed from 0, NOT 1. + *------------------------------------------------------------------------ + */ +void FQTermTelnet::putc_down(u_char c) { + // check overflow + if ((long)(wsize + 1) > to_socket.size()) { + FQ_TRACE("telnet", 0) << "Buffer to_socket overflow."; + return ; + } + // put it in the buffer + //to_socket->replace(wsize, 1, (const char *)&c); + to_socket[wsize] = c; + + wsize++; + return ; +} + +/*------------------------------------------------------------------------ + * do_notsup - handle an unsupported telnet "will/won't" option + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::do_notsup(int c) { + putc_down(TCIAC); + putc_down(TCDONT); + putc_down((char)c); + return 0; +} + +/*------------------------------------------------------------------------ + * do_noga - don't do telnet Go-Ahead's + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::do_noga(int c) { + if (noga) { + if (option_cmd == TCWILL) { + return 0; + } + } else if (option_cmd == TCWONT) { + return 0; + } + + noga = !noga; + + putc_down(TCIAC); + if (noga) { + putc_down(TCDO); + } else { + putc_down(TCDONT); + } + putc_down((char)c); + return 0; +} + +/*------------------------------------------------------------------------ + * do_txbinary - handle telnet "will/won't" TRANSMIT-BINARY option + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::do_txbinary(int c) { + if (rcvbinary) { + if (option_cmd == TCWILL) { + return 0; + } + } else if (option_cmd == TCWONT) { + return 0; + } + + rcvbinary = !rcvbinary; + + putc_down(TCIAC); + if (rcvbinary) { + putc_down(TCDO); + } else { + putc_down(TCDONT); + } + putc_down((char)c); + return 0; +} + +/*------------------------------------------------------------------------ + * will_notsup - handle an unsupported telnet "do/don't" option + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::will_notsup(int c) { + putc_down(TCIAC); + putc_down(TCWONT); + putc_down((char)c); + return 0; +} + +/*------------------------------------------------------------------------ + * will_txbinary - handle telnet "do/don't" TRANSMIT-BINARY option + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::will_txbinary(int c) { + if (sndbinary) { + if (option_cmd == TCDO) { + return 0; + } + } else if (option_cmd == TCDONT) { + return 0; + } + + sndbinary = !sndbinary; + + putc_down(TCIAC); + if (sndbinary) { + putc_down(TCWILL); + } else { + putc_down(TCWONT); + } + putc_down((char)c); + return 0; +} + +/*------------------------------------------------------------------------ + * will_termtype - handle telnet "do/don't" TERMINAL-TYPE option + *------------------------------------------------------------------------ + */ +int FQTermTelnet::will_termtype(int c) { + if (termtype) { + if (option_cmd == TCDO) { + return 0; + } + } else if (option_cmd == TCDONT) { + return 0; + } + + termtype = !termtype; + + putc_down(TCIAC); + + if (termtype) { + putc_down(TCWILL); + } else { + putc_down(TCWONT); + } + + putc_down((char)c); + + // TODO: Do NOT use this assume! some foolish BBS not response the request + /* The client expects that once the remote application receives + terminal type information it will send control sequences for + the terminal, which cannot be sent using the NVT encoding, So + change the transfer mode to binary in both directions */ + /* set up binary data path; send WILL, DO */ + /* if (termtype) { + option_cmd = TCWILL; + do_txbinary(TOTXBINARY); + option_cmd = TCDO; + will_txbinary(TOTXBINARY); + } + */ + return 0; +} + +int FQTermTelnet::will_naws(int c) { + if (naws) { + if (option_cmd == TCDO) + return 0; + } else if (option_cmd == TCDONT) + return 0; + + + naws = !naws; + + putc_down(TCIAC); + if (naws) + putc_down(TCWILL); + else + putc_down(TCWONT); + putc_down((char)c); + + putc_down(TCIAC); + putc_down(TCSB); + putc_down(TONAWS); + putc_down((char)(short(wx) >> 8)); + putc_down((char)(short(wx)&0xff)); + putc_down((char)(short(wy) >> 8)); + putc_down((char)(short(wy)&0xff)); + putc_down(((char)TCIAC)); + putc_down((char)TCSE); + + return 0; +} + +/*------------------------------------------------------------------------ + * subopt - do option subnegotiation FSM transitions + *------------------------------------------------------------------------ + */ +int FQTermTelnet::subopt(int c) { + struct fsm_trans *pt; + int ti; + + ti = subfsm[substate][c]; + pt = &substab[ti]; + (this->*(pt->ft_action))(c); + substate = pt->ft_next; + return 0; +} + +/*------------------------------------------------------------------------ + * subtermtype - do terminal type option subnegotation + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::subtermtype(int) { + char *i; + /* have received IAC.SB.TERMTYPE.SEND */ + + putc_down(TCIAC); + putc_down(TCSB); + putc_down(TOTERMTYPE); + putc_down(TT_IS); + + //write term type string + //fputs(term, sfp); + for (i = term; (*i) != '\000'; i++) { + putc_down(*i); + } + + putc_down(TCIAC); + putc_down(TCSE); + return 0; +} + +/*------------------------------------------------------------------------ + * subend - end of an option subnegotiation; reset FSM + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::subend(int) { + substate = SS_START; + return 0; +} + +/*------------------------------------------------------------------------ + * soputc - move a character from the keyboard to the socket + * convert an character into the NVT encoding and send it + * through the socket to the server. + *------------------------------------------------------------------------ + */ + +int FQTermTelnet::soputc(int c) { + if (sndbinary) { + if (c == TCIAC) { + putc_down(TCIAC); + } + /* byte-stuff IAC */ + putc_down(c); + return 0; + } + + //c &= 0x7f; /* 7-bit ASCII only ???*/ + // Convert local special characters to NVT characters + /* TODO: // BBS don't need control signals + if (c == t_intrc || c == t_quitc) { // Interrupt + putc_down(TCIAC); + putc_down(TCIP); + } else if (c == sg_erase) { // Erase Char + putc_down(TCIAC); + putc_down(TCEC); + } else if (c == sg_kill) { // Erase Line + putc_down(TCIAC); + putc_down(TCEL); + } else if (c == t_flushc) { // Abort Output + putc_down(TCIAC); + putc_down(TCAO); + } else */ + putc_down((char)c); + + return 0; +} + +/*------------------------------------------------------------------------ + * xputc - putc to upper layer with optional file scripting + *------------------------------------------------------------------------ + */ +int FQTermTelnet::xputc_up(char ch) { + if ((long)(rsize + 1) > to_ansi.size()) { + FQ_TRACE("telnet", 0) << "Buffer to_ansi overflow."; + return - 1; + } + //to_ansi->replace(wsize, 1, &ch); + to_ansi[rsize] = u_char(ch); + rsize++; + + return 0; +} + +/*------------------------------------------------------------------------ + * xfputs - fputs with optional file scripting + *------------------------------------------------------------------------ + */ +int FQTermTelnet::xputs_up(char *str) { + /*if (scrfp) + fputs(str, scrfp);*/ + + char *i; + for (i = str; (*i) != '\000'; i++) { + xputc_up(*i); + } + return 0; +} + +/*------------------------------------------------------------------------ + * ttputc - print a single character on a Network Virtual Terminal + *------------------------------------------------------------------------ + */ +int FQTermTelnet::ttputc(int c) { + if (rcvbinary) { + xputc_up((char)c); /* print uninterpretted */ + return 0; + } + /* no data, if in SYNCH */ + /* + if (synching) + return 0; + */ + /* TODO: FQTermTelnet doesnot interpret NVT code, provide datas to upper + layer directly. So, will not be replaced with + */ + xputc_up((char)c); + + return 0; +} + +/*------------------------------------------------------------------------ + * invalid state reached, aborted + *------------------------------------------------------------------------ + */ +int FQTermTelnet::tnabort(int) { + FQ_VERIFY(false); // "invalid state reached, aborted"; + // exit(-1); + return -1; +} + +bool FQTermTelnet::readyForInput() +{ + return socket->readyForInput(); +} + + + +} // namespace FQTerm + +#include "fqterm_telnet.moc" diff --git a/src/terminal/internal/fqterm_telnet.h b/src/terminal/internal/fqterm_telnet.h new file mode 100644 index 0000000..33e8c6e --- /dev/null +++ b/src/terminal/internal/fqterm_telnet.h @@ -0,0 +1,195 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_TELNET_H +#define FQTERM_TELNET_H + +#include +#include + +namespace FQTerm { + +#ifndef u_char +#define u_char uchar +#endif + +#define NTSTATES 6 // # of Telnet Socket-Input FSM States +#define NSSTATES 3 // # of Telnet Option Subnegotiation FSM States +#define NCHRS 256 // # of valid characters + +// decleration +class FQTermTelnet; +// actionFunc is a pointer, point to a FQTermTelnet's func +typedef int(FQTermTelnet:: *ptrActionFunc)(int c); + +//fsm struct +struct fsm_trans { + u_char ft_state; // current state + short ft_char; // input character + u_char ft_next; // next state + ptrActionFunc ft_action; // action to take +}; + + +/*------------------------------------------------------------------------------ + * FQTermTelnet class definition + *------------------------------------------------------------------------------- + */ +class FQTermSocket; + +// Telnet connection, a wrapper of socket. +// It will translate raw NVT data from low level socket to ansi data, +// and then upper level application can read it. +// It also can send ascii data (0~127). +class FQTermTelnet: public QObject { + Q_OBJECT; + public: + FQTermTelnet(const QString &termtype, int rows, int numColumns, int protocolType, int hostType, const + char *sshuser = NULL, const char *sshpasswd = NULL); + ~FQTermTelnet(); + + void setProxy(int nProxyType, //0-no proxy; 1-wingate; 2-sock4; 3-socks5 + bool bAuth, // if authentation needed + const QString &strProxyHost, quint16 uProxyPort, const QString &strProxyUsr, + const QString &strProxyPwd); + void connectHost(const QString &hostname, quint16 portnumber); + + // Read ansi data. + int read(char *data, uint maxlen); + + // Write data raw data + int write(const char *data, uint len); + + void close(); // User close the connection + + int raw_len(); + int read_raw(char *data, uint maxlen); + + bool readyForInput(); + + + signals: + void readyRead(int, int); // There are datas to be read out + void TelnetState(int); // The state telnet, defined as TSXXXX in fqterm.h + void requestUserPwd(QString *user, QString *pwd, bool *isOK); + void errorMessage(QString); + + public slots: + void windowSizeChanged(int, int); + + private slots: + // Retrieve data from socket, translate NVT data to ansi data, + // then notify data ready. + void socketReadyRead(); + + void connected(); + void showError(QAbstractSocket::SocketError); + void hostFound(); + void delayCloseFinished(); + void closed(); + protected: + //init structure fsm + void init_telnet(); + void fsmbuild(); + void fsminit(u_char fsm[][NCHRS], struct fsm_trans ttab[], int nstates); + + //actions + int tcdm(int); + int recopt(int); + int no_op(int); + int do_echo(int); + int do_notsup(int); + int do_noga(int); + int do_txbinary(int); + int will_notsup(int); + int will_txbinary(int); + int will_termtype(int); + int will_naws(int); + int subopt(int); + int subtermtype(int); + int subend(int); + int soputc(int); + int ttputc(int); + int tnabort(int); + + //utility functions + int xputc_up(char); + int xputs_up(char*); + void putc_down(u_char); + +signals: + + void onSSHAuthOK(); + + private: + // Boolean Flags + char synching, doecho, sndbinary, rcvbinary; + char noga; + char naws; + char server_sent_do_naws; + u_char option_cmd; // has value WILL, WONT, DO, or DONT + + char termtype; // non-zero if received "DO TERMTYPE" + char *term; // terminal name + + /* // TODO: BBS don't need control signals + // Special keys - Terminal control characters + // need work... + static const char t_flushc=FQTERM_CTRL('S'); // Abort Output i.e:(^S) + static const char t_intrc=FQTERM_CTRL('C'); // Interrupt i.e:(^C) + static const char t_quitc=FQTERM_CTRL('\\'); // Quit i.e:(^\) + static const char sg_erase=FQTERM_CTRL('?'); // Erase a character i.e:(^?) + static const char sg_kill=FQTERM_CTRL('U'); // Kill a line i.e:(^U) + */ + + // FSM stuffs + static struct fsm_trans ttstab[]; + int ttstate; + u_char ttfsm[NTSTATES][NCHRS]; + + static struct fsm_trans substab[]; + int substate; + u_char subfsm[NSSTATES][NCHRS]; + + // socket stuffs + FQTermSocket *socket; + + //Pointers to internal buffers + // + // |-->from_socket-->process-->to_ansi-->| + // socket<---> <---> ansi decode + // |<---to_socket<--process<--from_ansi--| + // + QByteArray from_socket, to_ansi, from_ansi, to_socket; + uint rsize; // size of to_ansi buffer + uint wsize; // size of to_socket buffer + + // for test + int wx, wy; + int done_naws; + bool bConnected; + int raw_size; + int hostType_; + int protocolType_; +}; + +} // namespace FQTerm + +#endif // FQTERM_TELNET_H diff --git a/src/terminal/internal/fqterm_zmodem.cpp b/src/terminal/internal/fqterm_zmodem.cpp new file mode 100644 index 0000000..afb99c9 --- /dev/null +++ b/src/terminal/internal/fqterm_zmodem.cpp @@ -0,0 +1,3056 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "fqterm.h" +#include "fqterm_config.h" +#include "fqterm_param.h" +#include "fqterm_path.h" +#include "fqterm_telnet.h" +#include "fqterm_zmodem.h" +#include "fqterm_filedialog.h" + +#ifdef FQTERM_ZMODEM_DEBUG +#include +#endif + +namespace FQTerm { + +static const uchar zeros[4] = { + 0, 0, 0, 0 +}; + +static const char hexChars[] = "0123456789abcdef"; + +static const uchar AckStr[1] = { + ACK +}; +static const uchar NakStr[1] = { + NAK +}; +static const uchar CanStr[2] = { + CAN, CAN +}; +static const uchar eotstr[1] = { + EOT +}; + + +/* + * Crc calculation stuff + */ + +/* crctab calculated by Mark G. Mendel, Network Systems Corporation */ +unsigned short crctab[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, + 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, + 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, + 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, + 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, + 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, + 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, + 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, + 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, + 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, + 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, + 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, + 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, + 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, + 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, + 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, + 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, + 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, + 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, + 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, + 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, + 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, + 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, + 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, + 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, + 0x3eb2, 0x0ed1, 0x1ef0 +}; + +/* + * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. + * NOTE: First argument must be in range 0 to 255. + * Second argument is referenced twice. + * + * Programmers may incorporate any or all code into their programs, + * giving proper credit within the source. Publication of the + * source routines is permitted so long as proper credit is given + * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, + * Omen Technology. + */ + +#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +unsigned long cr3tab[] = { + /* CRC polynomial 0xedb88320 */ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + +#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) + +#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) + + + +#if 1 +StateTable FQTermZmodem::RStartOps[] = { + {ZSINIT, &FQTermZmodem::GotSinit, 0, 1, RSinitWait}, + /* SINIT, wait for attn str */ + {ZFILE, &FQTermZmodem::GotFile, 0, 0, RFileName}, + /* FILE, wait for filename */ + {ZRQINIT, &FQTermZmodem::SendRinit, 0, 1, RStart}, + /* sender confused, resend */ + {ZFIN, &FQTermZmodem::GotFin, 1, 0, RFinish}, + /* sender shutting down */ + {ZNAK, &FQTermZmodem::SendRinit, 1, 0, RStart}, + /* RINIT was bad, resend */ + {ZFREECNT, &FQTermZmodem::GotFreecnt, 0, 0, RStart}, + /* sender wants free space */ + {ZCOMMAND, &FQTermZmodem::GotCommand, 0, 0, CommandData}, + /* sender wants command */ + {ZSTDERR, &FQTermZmodem::GotStderr, 0, 0, StderrData}, + /* sender wants to send msg */ + {ZRINIT, &FQTermZmodem::ZmodemTInit, 1, 1, TStart}, + {99, &FQTermZmodem::ZPF, 0, 0, RStart} + /* anything else is an error */ +}; + +StateTable FQTermZmodem::RSinitWaitOps[] = { + /* waiting for data */ + { + 99, &FQTermZmodem::ZPF, 0, 0, RSinitWait + }, +}; + +StateTable FQTermZmodem::RFileNameOps[] = { + /* waiting for file name */ + { + 99, &FQTermZmodem::ZPF, 0, 0, RFileName + }, +}; + +StateTable FQTermZmodem::RCrcOps[] = { + /* waiting for CRC */ + { + ZCRC, &FQTermZmodem::GotFileCrc, 0, 0, RFile + }, { /* sender sent it */ + ZNAK, &FQTermZmodem::ResendCrcReq, 0, 0, RCrc + }, { /* ZCRC was bad, resend */ + ZRQINIT, &FQTermZmodem::SendRinit, 1, 1, RStart + }, { /* sender confused, restart */ + ZFIN, &FQTermZmodem::GotFin, 1, 1, RFinish + }, { /* sender signing off */ + 99, &FQTermZmodem::ZPF, 0, 0, RCrc + }, +}; + + +StateTable FQTermZmodem::RFileOps[] = { + /* waiting for ZDATA */ + { + ZDATA, &FQTermZmodem::GotData, 0, 0, RData + }, { /* got it */ + ZNAK, &FQTermZmodem::ResendRpos, 0, 0, RFile + }, { /* ZRPOS was bad, resend */ + ZEOF, &FQTermZmodem::GotEof, 0, 0, RStart + }, { /* end of file */ + ZRQINIT, &FQTermZmodem::SendRinit, 1, 1, RStart + }, { /* sender confused, restart */ + ZFILE, &FQTermZmodem::ResendRpos, 0, 0, RFile + }, { /* ZRPOS was bad, resend */ + ZFIN, &FQTermZmodem::GotFin, 1, 1, RFinish + }, { /* sender signing off */ + 99, &FQTermZmodem::ZPF, 0, 0, RFile + }, +}; + +/* waiting for data, but a packet could possibly arrive due + * to error recovery or something + */ +StateTable FQTermZmodem::RDataOps[] = { + { + ZRQINIT, &FQTermZmodem::SendRinit, 1, 1, RStart + }, { /* sender confused, restart */ + ZFILE, &FQTermZmodem::GotFile, 0, 1, RFileName + }, { /* start a new file (??) */ + ZNAK, &FQTermZmodem::ResendRpos, 1, 1, RFile + }, { /* ZRPOS was bad, resend */ + ZFIN, &FQTermZmodem::GotFin, 1, 1, RFinish + }, { /* sender signing off */ + ZDATA, &FQTermZmodem::GotData, 0, 1, RData + }, { /* file data follows */ + ZEOF, &FQTermZmodem::GotEof, 1, 1, RStart + }, { /* end of file */ + 99, &FQTermZmodem::ZPF, 0, 0, RData + }, +}; + +/* here if we've sent ZFERR or ZABORT. Waiting for ZFIN */ + +StateTable FQTermZmodem::RFinishOps[] = { + + { + ZRQINIT, &FQTermZmodem::SendRinit, 1, 1, RStart + } , { /* sender confused, restart */ + ZFILE, &FQTermZmodem::GotFile, 1, 1, RFileName + }, { /* start a new file */ + ZNAK, &FQTermZmodem::GotFin, 1, 1, RFinish + }, { /* resend ZFIN */ + ZFIN, &FQTermZmodem::GotFin, 1, 1, RFinish + }, { /* sender signing off */ + 99, &FQTermZmodem::ZPF, 0, 0, RFinish + }, +}; + + +/* sent ZRQINIT, waiting for response */ +StateTable FQTermZmodem::TStartOps[] = { + { + ZRINIT, &FQTermZmodem::GotRinit, 1, 1, TStart + }, { + ZCHALLENGE, &FQTermZmodem::AnswerChallenge, 1, 0, TStart + }, { + ZABORT, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZFERR, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZNAK, &FQTermZmodem::Ignore, 0, 0, TStart + }, { + ZCOMMAND, &FQTermZmodem::GotCommand, 0, 0, CommandData + }, { + ZSTDERR, &FQTermZmodem::GotStderr, 0, 0, StderrData + }, { + 99, &FQTermZmodem::ZPF, 0, 0, TStart + }, +}; + +/* sent ZSINIT, waiting for response */ +StateTable FQTermZmodem::TInitOps[] = { + { + ZACK, &FQTermZmodem::RetDone, 1, 0, TInit + }, { + ZNAK, &FQTermZmodem::SendZSInit, 1, 0, TInit + }, { + ZRINIT, &FQTermZmodem::GotRinit, 1, 1, TInit + }, { /* redundant, but who cares */ + ZCHALLENGE, &FQTermZmodem::AnswerChallenge, 1, 0, TInit + }, { + ZABORT, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZFERR, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZCOMMAND, &FQTermZmodem::GotCommand, 0, 0, CommandData + }, { + ZSTDERR, &FQTermZmodem::GotStderr, 0, 0, StderrData + }, { + 99, &FQTermZmodem::ZPF, 0, 0, TInit + }, +}; + +/* sent ZFILE, waiting for response */ +StateTable FQTermZmodem::FileWaitOps[] = { + { + ZRPOS, &FQTermZmodem::SendFileData, 1, 1, Sending + }, { + ZSKIP, &FQTermZmodem::SkipFile, 1, 0, TStart + }, { + ZCRC, &FQTermZmodem::SendFileCrc, 1, 0, FileWait + }, { + ZNAK, &FQTermZmodem::sendFilename, 1, 0, FileWait + }, { + ZRINIT, &FQTermZmodem::sendFilename, 1, 1, FileWait + }, { /* rcvr confused, retry file */ + ZABORT, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZFERR, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZCHALLENGE, &FQTermZmodem::AnswerChallenge, 1, 0, FileWait + }, { + ZCOMMAND, &FQTermZmodem::GotCommand, 0, 0, CommandData + }, { + ZSTDERR, &FQTermZmodem::GotStderr, 0, 0, StderrData + }, { + ZACK, &FQTermZmodem::SendFileData, 1, 0, Sending + }, { // receiver always sends ZACK back + 99, &FQTermZmodem::ZPF, 0, 0, FileWait + }, +}; + +/* sent file CRC, waiting for response */ +StateTable FQTermZmodem::CrcWaitOps[] = { + { + ZRPOS, &FQTermZmodem::SendFileData, 1, 0, Sending + }, { + ZSKIP, &FQTermZmodem::SkipFile, 1, 0, FileWait + }, { + ZNAK, &FQTermZmodem::SendFileCrc, 1, 0, CrcWait + }, { + ZRINIT, &FQTermZmodem::sendFilename, 1, 1, FileWait + }, { /* rcvr confused, retry file */ + ZABORT, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZFERR, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZCRC, &FQTermZmodem::SendFileCrc, 0, 0, CrcWait + }, { + ZCHALLENGE, &FQTermZmodem::AnswerChallenge, 0, 0, CrcWait + }, { + ZCOMMAND, &FQTermZmodem::GotCommand, 0, 0, CommandData + }, { + ZSTDERR, &FQTermZmodem::GotStderr, 0, 0, StderrData + }, { + 99, &FQTermZmodem::ZPF, 0, 0, CrcWait + }, +}; + +/* sending data, interruptable */ +StateTable FQTermZmodem::SendingOps[] = { + { + ZACK, &FQTermZmodem::GotSendAck, 0, 0, Sending + }, { + ZRPOS, &FQTermZmodem::GotSendPos, 1, 1, Sending + }, { + ZSKIP, &FQTermZmodem::SkipFile, 1, 1, FileWait + }, { + ZNAK, &FQTermZmodem::GotSendNak, 1, 1, Sending + }, { + ZRINIT, &FQTermZmodem::sendFilename, 1, 1, FileWait + },{ /* rcvr confused, retry file */ + ZABORT, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZFERR, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + 99, &FQTermZmodem::ZPF, 0, 0, SendWait + }, +}; + +/* sent data, need to send EOF */ +StateTable FQTermZmodem::SendDoneOps[] = { + { + ZACK, &FQTermZmodem::GotSendDoneAck, 0, 0, SendWait + }, { + ZRPOS, &FQTermZmodem::GotSendPos, 1, 1, Sending + }, { + ZSKIP, &FQTermZmodem::SkipFile, 1, 1, FileWait + }, { + ZNAK, &FQTermZmodem::GotSendNak, 1, 1, Sending + }, { + ZRINIT, &FQTermZmodem::sendFilename, 1, 1, FileWait + }, { /* rcvr confused, retry file */ + ZABORT, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZFERR, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + 99, &FQTermZmodem::ZPF, 0, 0, SendWait + }, +}; + +/* sending data, waiting for ACK */ +StateTable FQTermZmodem::SendWaitOps[] = { + { + ZACK, &FQTermZmodem::GotSendWaitAck, 0, 0, Sending + }, { + ZRPOS, &FQTermZmodem::GotSendPos, 0, 0, SendWait + }, { + ZSKIP, &FQTermZmodem::SkipFile, 1, 1, FileWait + }, { + ZNAK, &FQTermZmodem::GotSendNak, 0, 0, Sending + }, { + ZRINIT, &FQTermZmodem::sendFilename, 1, 1, FileWait + }, { /* rcvr confused, retry file */ + ZABORT, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZFERR, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + 99, &FQTermZmodem::ZPF, 0, 0, SendWait + }, +}; + +/* sent ZEOF, waiting for new RINIT */ +StateTable FQTermZmodem::SendEofOps[] = { + { + ZRINIT, &FQTermZmodem::SkipFile, 1, 0, TFinish + }, { /* successful completion */ + ZACK, &FQTermZmodem::Ignore, 0, 0, SendEof + }, { /* probably ACK from last packet */ + ZRPOS, &FQTermZmodem::GotSendPos, 1, 1, SendWait + }, { + ZSKIP, &FQTermZmodem::SkipFile, 1, 1, TStart + }, { + ZNAK, &FQTermZmodem::ResendEof, 1, 0, SendEof + }, { + ZRINIT, &FQTermZmodem::sendFilename, 1, 1, FileWait + }, { /* rcvr confused, retry file */ + ZABORT, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZFERR, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + 99, &FQTermZmodem::ZPF, 0, 0, SendEof + }, +}; + +StateTable FQTermZmodem::TFinishOps[] = { + { + ZFIN, &FQTermZmodem::OverAndOut, 1, 1, Done + }, { + ZNAK, &FQTermZmodem::ZmodemTFinish, 1, 1, TFinish + }, { + ZRINIT, &FQTermZmodem::ZmodemTFinish, 1, 1, TFinish + }, { + ZABORT, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + ZFERR, &FQTermZmodem::GotAbort, 1, 1, TFinish + }, { + 99, &FQTermZmodem::ZPF, 0, 0, TFinish + }, +}; + +StateTable FQTermZmodem::CommandDataOps[] = { + { + 99, &FQTermZmodem::ZPF, 0, 0, CommandData + }, +}; + +StateTable FQTermZmodem::CommandWaitOps[] = { + { + 99, &FQTermZmodem::ZPF, 0, 0, CommandWait + }, +}; + +StateTable FQTermZmodem::StderrDataOps[] = { + { + 99, &FQTermZmodem::ZPF, 0, 0, StderrData + }, +}; + +StateTable FQTermZmodem::DoneOps[] = { + { + 99, &FQTermZmodem::ZPF, 0, 0, Done + }, +}; + +StateTable *FQTermZmodem::tables[] = { + FQTermZmodem::RStartOps, FQTermZmodem::RSinitWaitOps, FQTermZmodem::RFileNameOps, + FQTermZmodem::RCrcOps, FQTermZmodem::RFileOps, FQTermZmodem::RDataOps, + FQTermZmodem::RDataOps, /* RDataErr is the same as RData */ + FQTermZmodem::RFinishOps, + + FQTermZmodem::TStartOps, FQTermZmodem::TInitOps, FQTermZmodem::FileWaitOps, + FQTermZmodem::CrcWaitOps, FQTermZmodem::SendingOps, FQTermZmodem::SendWaitOps, + FQTermZmodem::SendDoneOps, FQTermZmodem::SendEofOps, FQTermZmodem::TFinishOps, + + FQTermZmodem::CommandDataOps, FQTermZmodem::CommandWaitOps, + FQTermZmodem::StderrDataOps, FQTermZmodem::DoneOps, +}; + +const char *FQTermZmodem::hdrnames[] = { + "ZRQINIT", "ZRINIT", "ZSINIT", "ZACK", "ZFILE", "ZSKIP", "ZNAK", "ZABORT", + "ZFIN", "ZRPOS", "ZDATA", "ZEOF", "ZFERR", "ZCRC", "ZCHALLENGE", "ZCOMPL", + "ZCAN", "ZFREECNT", "ZCOMMAND", "ZSTDERR", +}; + +#endif + +FQTermZmodem::FQTermZmodem(FQTermConfig *config, FQTermTelnet *netinterface, int type, int serverEncoding) { + + //now set network interface Telnet + + connectionType = type; + + serverEncodingID = serverEncoding; + + switch (connectionType) { + case 0: + case 1: + case 2: + telnet_ = netinterface; + break; + default: + FQ_TRACE("zmodem", 0) << "connection type unknown! Expect segmentation fault!"; + telnet_ = netinterface; + break; + } + + config_ = config; + + sending = false; + + transferstate = notransfer; + + zmodemTimer = new QTimer(this); + FQ_VERIFY(connect(zmodemTimer, SIGNAL(timeout()), this, SLOT(ZmodemTimeout()))); + +#ifdef FQTERM_ZMODEM_DEBUG + zmodemlogfile = fopen("zmodem.log", "w+"); + fprintf(zmodemlogfile, "%s", "\n================================\n"); + fclose(zmodemlogfile); +#endif + + + //init struct INFO + info.zrinitflags = CANFDX | CANOVIO | CANBRK | CANFC32; + info.zsinitflags = 0; + info.attn = NULL; + info.bufsize = 0; /* full streaming */ + info.buffer = NULL; + + zerrno = 0; + lastPullByte = 0; + + ZmodemReset(&info); + // other init function not complete + +} + +FQTermZmodem::~FQTermZmodem(){} + +int FQTermZmodem::ZmodemTInit(ZModem *info) { + int err; + int i; + + info->state = TStart; + info->Protocol = ZMODEM; + info->crc32 = 0; + info->packetCount = 0; + info->errCount = 0; + info->escCtrl = info->escHibit = info->atSign = info->escape = 0; + info->InputState = Idle; + info->canCount = info->chrCount = 0; + info->windowCount = 0; + info->filename = NULL; + info->bufsize = 0; + info->interrupt = 0; + info->waitflag = 0; + + // if( info->packetsize <= 0 ) + info->packetsize = 8096; + info->windowsize = 0; + //we won't be receiving much data, pick a reasonable buffer + // size (largest packet will do) + // + + i = info->packetsize *2; + + if (info->buffer != NULL) { + free(info->buffer); + info->buffer = NULL; + } + //since in the constructor function buffer is malloc + + if (i < 1024) { + i = 1024; + } + info->buffer = (uchar*)malloc(i); + + ZIFlush(info); + +// FQTermConfig *config = new FQTermConfig(getPath(USER_CONFIG) + "fqterm.cfg"); +// QString strPrevSave = config->getItemValue("global", "previous"); + +// if (strPrevSave.isEmpty()) { +// strFileList = QFileDialog::getOpenFileNames(0, "Choose the files", +// getPath(USER_CONFIG), "All files(*)"); +// } else { +// strFileList = QFileDialog::getOpenFileNames(0, "Choose the files", +// strPrevSave, "All files(*)"); +// } + FQTermFileDialog fileDialog(config_); + strFileList = fileDialog.getOpenNames("Choose a file to upload", ""); + if (strFileList.count() != 0) { + QStringList::Iterator itFile = strFileList.begin(); + QFileInfo fi(*itFile); + } + + this->transferstate = transferstop; + + // optional: send "rz\r" to remote end + if (DoInitRZ) { + if ((err = ZXmitStr((uchar*)"rz\r", 3, info))) { + return err; + } + } + + if ((err = ZXmitHdr(ZRQINIT, ZHEX, zeros, info))) { + // nudge receiver + return err; + } + + info->timeout = 60; + + zmodemlog("ZmodemTInit[%s]: sent ZRQINIT\n", sname(info)); + + return 0; +} + + +int FQTermZmodem::ZmodemTFile(char *file, char *rfile, uint f0, uint f1, uint f2, + uint f3, int filesRem, int bytesRem, ZModem *info) { + if (file == NULL || (info->file = fopen(file, "rb")) == NULL) { + return ZmErrCantOpen; + } + + info->fileEof = 0; + info->filename = file; + if (rfile != NULL) { + info->rfilename = rfile; + } else { + info->rfilename = strdup("noname"); + } + info->filesRem = filesRem; + info->bytesRem = bytesRem; + info->fileFlags[3] = f0; + info->fileFlags[2] = f1; + info->fileFlags[1] = f2; + info->fileFlags[0] = f3; + info->offset = info->lastOffset = 0; + info->len = info->date = info->fileType = info->mode = 0; + if (info->filename != NULL) { + struct stat buf; + if (stat(info->filename, &buf) == 0) { + info->len = buf.st_size; + info->date = buf.st_mtime; + info->fileType = 0; + info->mode = (buf.st_mode &0777) | 0100000; + } + } + + if (info->Protocol == XMODEM) { + return YSendData(info); + } + + if (info->Protocol == YMODEM) { + return YSendFilename(info); + } + + info->state = FileWait; + ZStatus(FileBegin, info->bytesRem, info->rfilename); + zmodemlog("ZmodemTFile[%s]: send ZFILE(%s)\n", sname(info), info->rfilename); + return sendFilename(info); +} + + +int FQTermZmodem::ZmodemTFinish(ZModem *info) { + int i; + if (info->Protocol == XMODEM) { + return ZmDone; + } + + if (info->Protocol == YMODEM) { + return YSendFin(info); + } + + info->state = TFinish; + if (info->buffer != NULL) { + free(info->buffer); + info->buffer = NULL; + } + zmodemlog("ZmodemTFinish[%s]: send ZFIN\n", sname(info)); + i = ZXmitHdr(ZFIN, ZHEX, zeros, info); + + return i; +} + + + +int FQTermZmodem::ZmodemAbort(ZModem *info) { + uchar canistr[] = { + CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0 + }; + info->state = Done; + ZIFlush(info); + ZOFlush(info); + + transferstate = transferstop; // transfer complete + ZmodemReset(info); //Tranfer complete, zmodem return to receive state + + zmodemlog("ZmodemAbort[%s]: send CAN\n", sname(info)); + return ZXmitStr(canistr, sizeof(canistr), info); +} + + +int FQTermZmodem::ZmodemRInit(ZModem *info) { + info->packetCount = 0; + info->offset = 0; + info->errCount = 0; + info->escCtrl = info->escHibit = info->atSign = info->escape = 0; + info->InputState = Idle; + info->canCount = info->chrCount = 0; + info->filename = NULL; + info->interrupt = 0; + info->waitflag = 0; + info->attn = NULL; + info->file = NULL; + + if (info->buffer != NULL) { + free(info->buffer); + info->buffer = NULL; + } + + info->buffer = (uchar*)malloc(1024); + + info->state = RStart; + info->timeoutCount = 0; + + ZIFlush(info); + + /* Don't send ZRINIT right away, there might be a ZRQINIT in + * the input buffer. Instead, set timeout to zero and return. + * This will allow ZmodemRcv() to check the input stream first. + * If nothing found, a ZRINIT will be sent immediately. + */ + info->timeout = 0; + + zmodemlog("ZmodemRInit[%s]: flush input, new state = RStart\n", sname(info)); + + return 0; +} + +int FQTermZmodem::ZmodemRcv(uchar *str, int len, ZModem *info, + int &consumed_bytes) { + register uchar c; + int err; + + zmodemlog("zmodemRcv called"); + + info->rcvlen = len; + + while (--info->rcvlen >= 0) { + c = *str++; + + if (c == CAN) { + if (++info->canCount >= 5) { + ZStatus(RmtCancel, 0, NULL); + consumed_bytes = len - info->rcvlen - 1; + return ZmErrCancel; + } + } else { + info->canCount = 0; + } + + if (info->InputState == Ysend) { + if ((err = YsendChar(c, info))) { + consumed_bytes = len - info->rcvlen - 1; + return err; + } + } else if (info->InputState == Yrcv) { + if ((err = YrcvChar(c, info))) { + consumed_bytes = len - info->rcvlen - 1; + return err; + } + } else if (c != XON && c != XOFF) { + /* now look at what we have */ + switch (info->InputState) { + case Idle: + if ((err = IdleChar(c, info))) { + consumed_bytes = len - info->rcvlen - 1; + return err; + } + break; + case Inhdr: + if ((err = HdrChar(c, info))) { + consumed_bytes = len - info->rcvlen - 1; + return err; + } + break; + case Indata: + if ((err = DataChar(c, info))) { + consumed_bytes = len - info->rcvlen - 1; + return err; + } + break; + case Finish: + if ((err = FinishChar(c, info))) { + consumed_bytes = len - info->rcvlen - 1; + return err; + } + break; + default: + break; + } + } + } + + consumed_bytes = len - info->rcvlen - 1; + return 0; +} + + + + +int FQTermZmodem::ZmodemTimeout( /*ZModem *info*/) { + /* timed out while waiting for input */ + + ++info.timeoutCount; + + zmodemlog("timeout %d [%s]\n", info.timeoutCount, sname(&info)); + + switch (info.state) { + /* receive */ + case RStart: + /* waiting for INIT frame from other end */ + if (info.timeoutCount > 4) { + return YmodemRInit(&info); + } + + case RSinitWait: + case RFileName: + if (info.timeout > 0) { + ZStatus(SndTimeout, info.timeoutCount, NULL); + } + if (info.timeoutCount > 4) { + return ZmErrRcvTo; + } + info.state = RStart; + return SendRinit(&info); + + case RCrc: + case RFile: + case RData: + ZStatus(SndTimeout, info.timeoutCount, NULL); + if (info.timeoutCount > 2) { + info.timeoutCount = 0; + info.state = RStart; + return SendRinit(&info); + } + return info.state == RCrc ? ResendCrcReq(&info): ResendRpos(&info); + + case RFinish: + ZStatus(SndTimeout, info.timeoutCount, NULL); + return ZmDone; + + case YRStart: + case YRDataWait: + case YRData: + case YREOF: + return YrcvTimeout(&info); + + /* transmit */ + case TStart: + /* waiting for INIT frame from other end */ + case TInit: + /* sent INIT, waiting for ZACK */ + case FileWait: + /* sent file header, waiting for ZRPOS */ + case CrcWait: + /* sent file crc, waiting for ZRPOS */ + case SendWait: + /* waiting for ZACK */ + case SendEof: + /* sent EOF, waiting for ZACK */ + case TFinish: + /* sent ZFIN, waiting for ZFIN */ + case YTStart: + case YTFile: + case YTDataWait: + case YTData: + case YTEOF: + case YTFin: + ZStatus(RcvTimeout, 0, NULL); + return ZmErrRcvTo; + + case Sending: + /* sending data subpackets, ready for int */ + return SendMoreFileData(&info); + + /* general */ + case CommandData: + /* waiting for command data */ + case StderrData: + /* waiting for stderr data */ + return ZmErrSndTo; + case CommandWait: + /* waiting for command to execute */ + return ZmErrCmdTo; + case Done: + return ZmDone; + default: + return 0; + } +} + + + +int FQTermZmodem::ZmodemAttention(ZModem *info) { + /* attention received from remote end */ + if (info->state == Sending) { + ZOFlush(info); + info->interrupt = 1; + } + return 0; +} + +int FQTermZmodem::YmodemTInit(ZModem *info) { + info->state = YTStart; + info->Protocol = YMODEM; + info->errCount = 0; + info->InputState = Ysend; + info->canCount = info->chrCount = 0; + info->windowCount = 0; + info->filename = NULL; + + if (info->packetsize != 1024) { + info->packetsize = 128; + } + + info->buffer = (uchar*)malloc(1024); + + ZIFlush(info); + ZFlowControl(0, info); + + info->timeout = 60; + + return 0; +} + + +int FQTermZmodem::XmodemTInit(ZModem *info) { + (void)YmodemTInit(info); + info->Protocol = XMODEM; + return 0; +} + + +int FQTermZmodem::YmodemRInit(ZModem *info) { + info->errCount = 0; + info->InputState = Yrcv; + info->canCount = info->chrCount = 0; + info->noiseCount = 0; + info->filename = NULL; + info->file = NULL; + + if (info->buffer == NULL) { + info->buffer = (uchar*)malloc(1024); + } + + info->state = YRStart; + info->packetCount = -1; + info->timeoutCount = 0; + info->timeout = 10; + info->offset = 0; + + ZIFlush(info); + + return ZXmitStr((uchar*)"C", 1, info); +} + + +int FQTermZmodem::XmodemRInit(ZModem *info) { +#if 0 + int err; + + state = Start; + protocol = prot; + ymodem = prot == Ymodem || prot == YmodemG; + + if (ymodem) { + strcpy(xmDefPath, file); + } else { + strcpy(xmFilename, file); + } + + eotCount = errorCount = errorCount2 = 0; + + if (err = XmodemRStart()) { + return err; + } + + state = Init; + packetId = ymodem ? 255 : 0; + packetCount = 0; + + pktHdrLen = protocol == Xmodem ? 3 : 4; +#endif + return 0; +} + + +ulong FQTermZmodem::FileCrc(char *name) { + ulong crc; + FILE *ifile = fopen(name, "rb"); + int i; + + if (ifile == NULL) + /* shouldn't happen, since we did access(2) */ { + return 0; + } + + crc = 0xffffffff; + + while ((i = fgetc(ifile)) != EOF) { + crc = UPDC32(i, crc); + } + + fclose(ifile); + return ~crc; +} + + + +const char *FQTermZmodem::sname(ZModem *info) { + return sname2(info->state); +} + +const char *FQTermZmodem::sname2(ZMState state) { + const char *names[] = { + "RStart", "RSinitWait", "RFileName", "RCrc", "RFile", "RData", "RDataErr", + "RFinish", "TStart", "TInit", "FileWait", "CrcWait", "Sending", "SendWait", + "SendDone", "SendEof", "TFinish", "CommandData", "CommandWait", "StderrData", + "Done", "YTStart", "YTFile", "YTDataWait", "YTData", "YTEOF", "YTFin", + "YRStart", "YRDataWait", "YRData", "YREOF" + }; + + return names[(int)state]; + +} + + +int FQTermZmodem::ZXmitChr(uchar c, ZModem *info) { + // to be completed + return 0; +} + +int FQTermZmodem::ZXmitStr(const uchar *str, int len, ZModem *info) { + //to be completed + telnet_->write((const char*)str, (uint)len); + return 0; +} + +void FQTermZmodem::ZIFlush(ZModem *info) { + //to be completed +} + +void FQTermZmodem::ZOFlush(ZModem *info) { + //to be completed +} + +int FQTermZmodem::ZAttn(ZModem *info) { + //to be completed + return 0; +} + +void FQTermZmodem::ZStatus(int type, int value, const char *status) { + emit ZmodemState(type, value, status); + switch (type) { + case RcvByteCount: + FQ_TRACE("zmodem", 5) << value << " bytes received."; + break; + case SndByteCount: + FQ_TRACE("zmodem", 5) << value << " bytes sent."; + break; + case RcvTimeout: + /* receiver did not respond, aborting */ + FQ_TRACE("zmodem", 0) << "Zmodem time out!"; + break; + case SndTimeout: + /* value is # of consecutive send timeouts */ + FQ_TRACE("zmodem", 0) << "Zmodem time out after trying " + << value << " times"; + break; + case RmtCancel: + /* remote end has cancelled */ + FQ_TRACE("zmodem", 1) << "Zmodem canceled by remote peer"; + break; + case ProtocolErr: + /* protocol error has occurred, val=hdr */ + FQ_TRACE("zmodem", 0) << "Unhandled header " << value + << " at state " << status; + break; + case RemoteMessage: + /* message from remote end */ + FQ_TRACE("zmodem", 0) << "Message from remote peer: " << status; + break; + case DataErr: + /* data error, val=error count */ + FQ_TRACE("zmodem", 0) << "Data errors " << value; + break; + case FileErr: + /* error writing file, val=errno */ + FQ_TRACE("zmodem", 0) << "Falied to write file."; + break; + case FileBegin: + /* file transfer begins, str=name */ + FQ_TRACE("zmodem", 0) << "Starting file: " << status; + break; + case FileEnd: + /* file transfer ends, str=name */ + FQ_TRACE("zmodem", 0) << "Finishing file: " << status; + break; + case FileSkip: + /* file being skipped, str=name */ + FQ_TRACE("zmodem", 0) << "Skipping file: " << status; + break; + } +} + +FILE *FQTermZmodem::ZOpenFile(char *name, ulong crc, ZModem *info) { + //to be complete + FILE *rval; + int apnd = 0; + QString strText; + strText = encoding2unicode(name, serverEncodingID); + QString str = FQTermPref::getInstance()->zmodemDir_ + strText; + + QString zpath = QFileInfo(FQTermPref::getInstance()->zmodemDir_).absoluteFilePath(); + QString path = QFileInfo(str).absoluteFilePath(); + + lastDownloadedFilename_ = path; + + if (path.startsWith(zpath)) { + // Ensure that file is only saved under zmodemDir_. + // TODO: lazy, should use bbs2unicode + rval = fopen(str.toLocal8Bit(), apnd ? "ab" : "wb"); + } else { + rval = NULL; + } + + if (rval == NULL) { + perror(name); + } + + return rval; +} + +int FQTermZmodem::ZXmitHdr(int type, int format, const uchar data[4], ZModem *info) { + if (format == ZBIN && info->crc32) { + format = ZBIN32; + } + + switch (format) { + case ZHEX: + return ZXmitHdrHex(type, data, info); + + case ZBIN: + return ZXmitHdrBin(type, data, info); + + case ZBIN32: + return ZXmitHdrBin32(type, data, info); + + default: + return 0; + } +} + + +int FQTermZmodem::ZXmitHdrHex(int type, const uchar data[4], ZModem *info) { + uchar buffer[128]; + uchar *ptr = buffer; + uint crc; + int i; + + zmodemlog("sending %s: %2.2x %2.2x %2.2x %2.2x = %lx\n", hdrnames[type], + data[0], data[1], data[2], data[3], ZDec4(data)); + + *ptr++ = ZPAD; + *ptr++ = ZPAD; + *ptr++ = ZDLE; + *ptr++ = ZHEX; + + ptr = putHex(ptr, type); + crc = updcrc(type, 0); + for (i = 4; --i >= 0; ++data) { + ptr = putHex(ptr, *data); + crc = updcrc(*data, crc); + } + crc = updcrc(0, crc); + crc = updcrc(0, crc); + ptr = putHex(ptr, (crc >> 8) &0xff); + ptr = putHex(ptr, crc &0xff); + *ptr++ = '\r'; + *ptr++ = '\n'; + if (type != ZACK && type != ZFIN) { + *ptr++ = XON; + } + + return ZXmitStr(buffer, ptr - buffer, info); +} + + +int FQTermZmodem::ZXmitHdrBin(int type, const uchar data[4], ZModem *info) { + uchar buffer[128]; + uchar *ptr = buffer; + uint crc; + int len; + + zmodemlog("sending %s: %2.2x %2.2x %2.2x %2.2x = %lx\n", hdrnames[type], + data[0], data[1], data[2], data[3], ZDec4(data)); + + *ptr++ = ZPAD; + *ptr++ = ZDLE; + *ptr++ = ZBIN; + + ptr = putZdle(ptr, type, info); + crc = updcrc(type, 0); + for (len = 4; --len >= 0; ++data) { + ptr = putZdle(ptr, *data, info); + crc = updcrc(*data, crc); + } + crc = updcrc(0, crc); + crc = updcrc(0, crc); + ptr = putZdle(ptr, (crc >> 8) &0xff, info); + ptr = putZdle(ptr, crc &0xff, info); + + len = ptr - buffer; + return ZXmitStr(buffer, len, info); +} + +int FQTermZmodem::ZXmitHdrBin32(int type, const uchar data[4], ZModem *info) { + uchar buffer[128]; + uchar *ptr = buffer; + ulong crc; + int len; + + zmodemlog("sending %s: %2.2x %2.2x %2.2x %2.2x = %lx\n", hdrnames[type], + data[0], data[1], data[2], data[3], ZDec4(data)); + + *ptr++ = ZPAD; + *ptr++ = ZDLE; + *ptr++ = ZBIN32; + ptr = putZdle(ptr, type, info); + crc = UPDC32(type, 0xffffffffL); + for (len = 4; --len >= 0; ++data) { + ptr = putZdle(ptr, *data, info); + crc = UPDC32(*data, crc); + } + crc = ~crc; + for (len = 4; --len >= 0; crc >>= 8) { + ptr = putZdle(ptr, crc &0xff, info); + } + + len = ptr - buffer; + return ZXmitStr(buffer, len, info); +} + + +uchar *FQTermZmodem::putZdle(uchar *ptr, uchar c, ZModem *info) { + uchar c2 = c &0177; + + if (c == ZDLE || c2 == 020 || c2 == 021 || c2 == 023 || c2 == 0177 || (c2 == + 015 && connectionType == 0 /*&& info->atSign*/) || +#ifdef COMMENT + c2 == 035 || (c2 == '~' && info->lastCR) || +#endif /* COMMENT */ + c2 == 035 || (c2 < 040 && info->escCtrl)) { + *ptr++ = ZDLE; + if (c == 0177) { + *ptr = ZRUB0; + } else if (c == 0377) { + *ptr = ZRUB1; + } else { + *ptr = c ^ 0100; + } + } else { + *ptr = c; + } + + info->atSign = c2 == '@'; + info->lastCR = c2 == '\r'; + + return ++ptr; +} + + +uchar *FQTermZmodem::ZEnc4(ulong n) { + static uchar buf[4]; + buf[0] = n &0xff; + n >>= 8; + buf[1] = n &0xff; + n >>= 8; + buf[2] = n &0xff; + n >>= 8; + buf[3] = n &0xff; + return buf; +} + +ulong FQTermZmodem::ZDec4(const uchar buf[4]) { + return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); +} + + + + +int FQTermZmodem::YrcvChar(char c, register ZModem *info) { + int err; + + if (info->canCount >= 2) { + ZStatus(RmtCancel, 0, NULL); + return ZmErrCancel; + } + + switch (info->state) { + case YREOF: + if (c == EOT) { + ZCloseFile(info); + info->file = NULL; + ZStatus(FileEnd, 0, info->filename); + if (info->filename != NULL) { + free(info->filename); + } + if ((err = acceptPacket(info)) != 0) { + return err; + } + info->packetCount = -1; + info->offset = 0; + info->state = YRStart; + return ZXmitStr((uchar*)"C", 1, info); + } + /* else, drop through */ + + case YRStart: + case YRDataWait: + switch (c) { + case SOH: + case STX: + info->pktLen = c == SOH ? (128+4): (1024+4); + info->state = YRData; + info->chrCount = 0; + info->timeout = 1; + info->noiseCount = 0; + info->crc = 0; + break; + + case EOT: + /* ignore first EOT to protect against false eot */ + info->state = YREOF; + return rejectPacket(info); + + default: + if (++info->noiseCount > 135) { + return ZXmitStr(NakStr, 1, info); + } + break; + } + break; + + case YRData: + info->buffer[info->chrCount++] = c; + if (info->chrCount >= info->pktLen) { + return ProcessPacket(info); + } + break; + + default: + break; + } + + return 0; +} + +int FQTermZmodem::YrcvTimeout(ZModem *info) { + switch (info->state) { + case YRStart: + if (info->timeoutCount >= 10) { + (void)ZXmitStr(CanStr, 2, info); + return ZmErrInitTo; + } + return ZXmitStr((uchar*)"C", 1, info); + + case YRDataWait: + case YREOF: + case YRData: + if (info->timeoutCount >= 10) { + (void)ZXmitStr(CanStr, 2, info); + return ZmErrRcvTo; + } + return ZXmitStr(NakStr, 1, info); + default: + return 0; + } +} + + +void FQTermZmodem::ZIdleStr(uchar *buffer, int len, ZModem *info) { + //to be completed +} + + +int FQTermZmodem::FinishChar(char c, register ZModem *info) { + if (c == 'O') { + if (++info->chrCount >= 2) { + return ZmDone; + } + } else { + info->chrCount = 0; + } + return 0; +} + + + +int FQTermZmodem::DataChar(uchar c, register ZModem *info) { + if (c == ZDLE) { + info->escape = 1; + return 0; + } + + if (info->escape) { + info->escape = 0; + switch (c) { + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + info->PacketType = c; + info->crcCount = (info->DataType == ZBIN32) ? 4 : 2; + if (info->DataType == ZBIN) { + info->crc = updcrc(c, info->crc); + } else { + info->crc = UPDC32(c, info->crc); + } + return 0; + case ZRUB0: + c = 0177; + break; + case ZRUB1: + c = 0377; + break; + default: + c ^= 0100; + break; + } + } + if (connectionType == 0) { + if (lastPullByte == 0x0d && c == 0x00) { + lastPullByte = 0; + return 0; + } else if (lastPullByte == 0xff && c == 0xff) { + lastPullByte = 0; + return 0; + } + } + lastPullByte = c; + + switch (info->DataType) { + /* TODO: are hex data packets ever used? */ + case ZBIN: + info->crc = updcrc(c, info->crc); + if (info->crcCount == 0) { + info->buffer[info->chrCount++] = c; + } else if (--info->crcCount == 0) { + return ZDataReceived(info, (info->crc &0xffff) == 0); + } + break; + + + case ZBIN32: + info->crc = UPDC32(c, info->crc); + if (info->crcCount == 0) { + info->buffer[info->chrCount++] = c; + } else if (--info->crcCount == 0) { + return ZDataReceived(info, info->crc == 0xdebb20e3); + } + break; + } + return 0; +} + + +int FQTermZmodem::HdrChar(uchar c, register ZModem *info) { + int i; + int crc = 0; + + if (c == ZDLE) { + info->escape = 1; + return 0; + } + + if (info->escape) { + info->escape = 0; + switch (c) { + case ZRUB0: + c = 0177; + break; + case ZRUB1: + c = 0377; + break; + default: + c ^= 0100; + break; + } + } + + if (info->chrCount == 0) { + /* waiting for format */ + switch (c) { + case ZHEX: + case ZBIN: + case ZBIN32: + info->DataType = c; + info->chrCount = 1; + info->crc = (info->DataType != ZBIN32) ? 0 : 0xffffffffL; + memset(info->hdrData, 0, sizeof(info->hdrData)); + break; + default: + info->InputState = Idle; + info->chrCount = 0; + return ZXmitHdrHex(ZNAK, zeros, info); + } + return 0; + } + + + switch (info->DataType) { + /* hex header is 14 hex digits, cr, lf. Optional xon is ignored */ + case ZHEX: + if (info->chrCount <= 14 && !isxdigit(c)) { + info->InputState = Idle; + info->chrCount = 0; + return ZXmitHdrHex(ZNAK, zeros, info); + } + + if (info->chrCount <= 14) { + i = (info->chrCount - 1) / 2; + info->hdrData[i] = rcvHex(info->hdrData[i], c); + } + + if (info->chrCount == 16) { + crc = 0; + for (i = 0; i < 7; ++i) { + crc = updcrc(info->hdrData[i], crc); + } + info->InputState = Idle; + info->chrCount = 0; + if ((crc &0xffff) != 0) { + return ZXmitHdrHex(ZNAK, zeros, info); + } else { + return ZProtocol(info); + } + } + else { + ++info->chrCount; + } + break; + + + case ZBIN: + /* binary header is type, 4 bytes data, 2 bytes CRC */ + info->hdrData[info->chrCount - 1] = c; + info->crc = updcrc(c, info->crc); + if (++info->chrCount > 7) { + info->InputState = Idle; + info->chrCount = 0; + if ((crc &0xffff) != 0) { + return ZXmitHdrHex(ZNAK, zeros, info); + } else { + return ZProtocol(info); + } + } + break; + + + case ZBIN32: + /* binary32 header is type, 4 bytes data, 4 bytes CRC */ + info->hdrData[info->chrCount - 1] = c; + info->crc = UPDC32(c, info->crc); + if (++info->chrCount > 9) { + info->InputState = Idle; + info->chrCount = 0; + if (info->crc != 0xdebb20e3) + /* see note below */ { + return ZXmitHdrHex(ZNAK, zeros, info); + } else { + return ZProtocol(info); + } + } + break; + } + return 0; +} + + + + +int FQTermZmodem::IdleChar(uchar c, register ZModem *info) { + if (info->chrCount == 0) { + if (c == ZPAD) { + ++info->chrCount; + } else if (info->state == Sending && ++info->noiseCount > MaxNoise) { + info->waitflag = 1; + } else if (info->state == TStart && (c == 'C' || c == 'G' || c == NAK)) { + /* switch to ymodem */ + info->state = YTStart; + info->InputState = Ysend; + info->Protocol = YMODEM; + return YsendChar(c, info); + } else { + ZIdleStr(&c, 1, info); + } + } + + else { + switch (c) { + case ZPAD: + ++info->chrCount; + break; + case ZDLE: + info->InputState = Inhdr; + info->chrCount = 0; + break; + default: + while (--info->chrCount >= 0) { + ZIdleStr((uchar*)"*", 1, info); + } + info->chrCount = 0; + break; + } + } + return 0; +} + + + +int FQTermZmodem::YsendChar(char c, ZModem *info) { + int err; + + if (info->canCount >= 2) { + ZStatus(RmtCancel, 0, NULL); + return ZmErrCancel; + } + + switch (info->state) { + case YTStart: + /* wait for 'G', 'C' or NAK */ + switch (c) { + case 'G': + /* streaming YModem */ + case 'C': + /* CRC YModem */ + case NAK: + /* checksum YModem */ + info->PacketType = c; + return ZmDone; + default: + return 0; + } + + case YTFile: + /* sent filename, waiting for ACK or NAK */ + switch (c) { + case NAK: + /* resend */ + case 'C': + case 'G': + ZStatus(DataErr, ++info->errCount, NULL); + return YSendFilename(info); + case ACK: + info->state = YTDataWait; + default: + return 0; + } + + case YTDataWait: + /* sent filename, waiting for G,C or NAK */ + switch (c) { + case NAK: + case 'C': + case 'G': + info->chrCount = 0; + if (info->PacketType == 'G') { + /* send it all at once */ + while (info->state == YTData) { + if ((err = YSendData(info))) { + return err; + } + } + return 0; + } else { + return YSendData(info); + } + break; + default: + return 0; + } + + case YTData: + /* sent data, waiting for ACK or NAK */ + switch (c) { + case 'C': + case 'G': + /* protocol failure, resend filename */ + if (info->Protocol == YMODEM) { + ZStatus(DataErr, ++info->errCount, NULL); + info->state = YTFile; + rewind(info->file); + return YSendFilename(info); + } + /* else XModem, treat it like a NAK */ + case NAK: + ZStatus(DataErr, ++info->errCount, NULL); + return YXmitData(info->buffer + info->bufp, info->ylen, info); + case ACK: + info->offset += info->ylen; + info->bufp += info->ylen; + info->chrCount -= info->ylen; + ZStatus(SndByteCount, info->offset, NULL); + return YSendData(info); + default: + return 0; + } + + case YTEOF: + /* sent EOF, waiting for ACK or NAK */ + switch (c) { + case NAK: + return ZXmitStr(eotstr, 1, info); + case ACK: + info->state = info->Protocol == YMODEM ? YTStart : Done; + return ZmDone; + default: + return 0; + } + + case YTFin: + /* sent Fin, waiting for ACK or NAK */ + switch (c) { + case NAK: + return YSendFin(info); + case ACK: + return ZmDone; + default: + return 0; + } + default: + return 0; + } +} + + + +int FQTermZmodem::ZProtocol(register ZModem *info) { + register StateTable *table; + + zmodemlog("received %s: %2.2x %2.2x %2.2x %2.2x = %lx\n", + hdrnames[info->hdrData[0]], info->hdrData[1], info->hdrData[2], + info->hdrData[3], info->hdrData[4], ZDec4(info->hdrData + 1)); + + /* Flags are sent in F3 F2 F1 F0 order. Data is sent in P0 P1 P2 P3 */ + + info->timeoutCount = 0; + info->noiseCount = 0; + + // zmodemTimer->start(info->timeout*1000); + + table = tables[(int)info->state]; + while (table->type != 99 && table->type != info->hdrData[0]) { + ++table; + } + + zmodemlog(" state %s => %s, iflush=%d, oflush=%d, call %x\n", sname(info), + sname2(table->newstate), table->IFlush, table->OFlush, table->func); + + info->state = table->newstate; + + if (table->IFlush) { + info->rcvlen = 0; + ZIFlush(info); + } + if (table->OFlush) { + ZOFlush(info); + } + return (this->*(table->func))(info); +} + + +int FQTermZmodem::ZDataReceived(register ZModem *info, int crcGood) { + switch (info->state) { + case RSinitWait: + return GotSinitData(info, crcGood); + case RFileName: + return GotFileName(info, crcGood); + case RData: + return GotFileData(info, crcGood); + case CommandData: + return GotCommandData(info, crcGood); + case StderrData: + return GotStderrData(info, crcGood); + default: + return ZPF(info); + } +} + + +int FQTermZmodem::ZPF(ZModem *info) { + info->waitflag = 1; /* pause any in-progress transmission */ + ZStatus(ProtocolErr, info->hdrData[0], sname(info)); + return 0; +} + + +int FQTermZmodem::Ignore(ZModem *info) { + return 0; +} + + +int FQTermZmodem::AnswerChallenge(register ZModem *info) { + return ZXmitHdrHex(ZACK, info->hdrData + 1, info); +} + + +int FQTermZmodem::GotAbort(register ZModem *info) { + ZStatus(RmtCancel, 0, NULL); + return ZXmitHdrHex(ZFIN, zeros, info); +} + + +int FQTermZmodem::GotCancel(ZModem *info) { + return ZmErrCancel; +} + + +int FQTermZmodem::GotCommand(ZModem *info) { + uchar rbuf[4]; + /* TODO: add command capability */ + + + /// EPERM not defined???????? + + rbuf[0] = EPERM; + rbuf[1] = rbuf[2] = rbuf[3] = 0; + return ZXmitHdrHex(ZCOMPL, rbuf, info); +} + +int FQTermZmodem::GotStderr(register ZModem *info) { + info->InputState = Indata; + info->chrCount = 0; + return 0; +} + + +int FQTermZmodem::RetDone(ZModem *info) { + + + return ZmDone; +} + + +int FQTermZmodem::GotCommandData(register ZModem *info, int crcGood) { + /* TODO */ + return 0; +} + + +int FQTermZmodem::GotStderrData(register ZModem *info, int crcGood) { + info->buffer[info->chrCount] = '\0'; + ZStatus(RemoteMessage, info->chrCount, (char*)info->buffer); + return 0; +} + + +int FQTermZmodem::GotFileName(ZModem *info, int crcGood) { + info->InputState = Idle; + info->chrCount = 0; + + if (!crcGood) { + zmodemlog("GotFileName[%s]: bad crc, send ZNAK\n", sname(info)); + info->state = RStart; + return ZXmitHdrHex(ZNAK, zeros, info); + } + + parseFileName(info, (char*)info->buffer); + + if ((info->f1 &ZMMASK) == ZMCRC) { + info->state = RCrc; + return ZXmitHdrHex(ZCRC, zeros, info); + } + + zmodemlog("GotFileName[%s]: good crc, call requestFile\n", sname(info)); + info->state = RFile; + return requestFile(info, 0); +} + + +int FQTermZmodem::ResendCrcReq(ZModem *info) { + zmodemlog("ResendCrcReq[%s]: send ZCRC\n", sname(info)); + return ZXmitHdrHex(ZCRC, zeros, info); +} + + +int FQTermZmodem::GotSinitData(ZModem *info, int crcGood) { + info->InputState = Idle; + info->chrCount = 0; + info->state = RStart; + + zmodemlog("GotSinitData[%s]: crcGood=%d\n", sname(info), crcGood); + + if (!crcGood) { + return ZXmitHdrHex(ZNAK, zeros, info); + } + + if (info->attn != NULL) { + free(info->attn); + } + info->attn = NULL; + if (info->buffer[0] != '\0') { + info->attn = strdup((char*)info->buffer); + } + return ZXmitHdrHex(ZACK, ZEnc4(SerialNo), info); +} + + +int FQTermZmodem::ResendRpos(ZModem *info) { + zmodemlog("ResendRpos[%s]: send ZRPOS(%ld)\n", sname(info), info->offset); + return ZXmitHdrHex(ZRPOS, ZEnc4(info->offset), info); +} + + +int FQTermZmodem::GotFileData(ZModem *info, int crcGood) { + /* OK, now what? Fushing the buffers and executing the + * attn sequence has likely chopped off the input stream + * mid-packet. Now we switch to idle mode and treat all + * incoming stuff like noise until we get a new valid + * packet. + */ + + if (!crcGood) { + /* oh bugger, an error. */ + zmodemlog("GotFileData[%s]: bad crc, send ZRPOS(%ld), new state = RFile\n", + sname(info), info->offset); + ZStatus(DataErr, ++info->errCount, NULL); + if (info->errCount > MaxErrs) { + ZmodemAbort(info); + return ZmDataErr; + } else { + info->state = RFile; + info->InputState = Idle; + info->chrCount = 0; + return fileError(info, ZRPOS, info->offset); + } + } + + if (ZWriteFile(info->buffer, info->chrCount, info->file, info)) { + /* RED ALERT! Could not write the file. */ + ZStatus(FileErr, zerrno, NULL); + info->state = RFinish; + info->InputState = Idle; + info->chrCount = 0; + return fileError(info, ZFERR, zerrno); + } + + zmodemlog("GotFileData[%s]: %ld.%d,", sname(info), info->offset, + info->chrCount); + info->offset += info->chrCount; + ZStatus(RcvByteCount, info->offset, NULL); + + /* if this was the last data subpacket, leave data mode */ + if (info->PacketType == ZCRCE || info->PacketType == ZCRCW) { + zmodemlog(" ZCRCE|ZCRCW, new state RFile"); + info->state = RFile; + info->InputState = Idle; + info->chrCount = 0; + } else { + zmodemlog(" call dataSetup"); + (void)dataSetup(info); + } + + if (info->PacketType == ZCRCQ || info->PacketType == ZCRCW) { + zmodemlog(", send ZACK\n"); + return ZXmitHdrHex(ZACK, ZEnc4(info->offset), info); + } else { + zmodemlog("\n"); + } + + return 0; +} + +int FQTermZmodem::SendRinit(ZModem *info) { + uchar dbuf[4]; + + + +#ifdef COMMENT + if (info->timeoutCount >= 5) + /* TODO: switch to Ymodem */ +#endif /* COMMENT */ + { + transferstate = transferstart; + } + //transfer would be active, it must be set to false when transfer complete or abort + zmodemlog("SendRinit[%s]: send ZRINIT\n", sname(info)); + + info->timeout = ResponseTime; + dbuf[0] = info->bufsize &0xff; + dbuf[1] = (info->bufsize >> 8) &0xff; + dbuf[2] = 0; + dbuf[3] = info->zrinitflags; + return ZXmitHdrHex(ZRINIT, dbuf, info); +} + + +int FQTermZmodem::SendMoreFileData(ZModem *info) { + int type; + int qfull = 0; + int err; + int len; /* max # chars to send this packet */ + long pending; /* # of characters sent but not acknowledged */ + + /* ZCRCE: CRC next, frame ends, header follows + * ZCRCG: CRC next, frame continues nonstop + * ZCRCQ: CRC next, send ZACK, frame continues nonstop + * ZCRCW: CRC next, send ZACK, frame ends, header follows + */ + + if (info->interrupt) { + /* Bugger, receiver sent an interrupt. Enter a wait state + * and see what they want. Next header *should* be ZRPOS. + */ + info->state = SendWait; + info->timeout = 60; + return 0; + } + + /* Find out how many bytes we can transfer in the next packet */ + + len = info->packetsize; + + pending = info->offset - info->lastOffset; + + if (info->windowsize != 0 && info->windowsize - pending <= len) { + len = info->windowsize - pending; + qfull = 1; + } + if (info->bufsize != 0 && info->bufsize - pending <= len) { + len = info->bufsize - pending; + qfull = 1; + } + + if (len == 0) { + /* window still full, keep waiting */ + info->state = SendWait; + info->timeout = 60; + return 0; + } + + + /* OK, we can safely transmit 'len' bytes of data. Start reading + * file until buffer is full. + */ + + len -= 10; /* Pre-deduct 10 bytes for trailing CRC */ + + + /* find out what kind of packet to send */ + if (info->waitflag) { + type = ZCRCW; + info->waitflag = 0; + } +#ifdef COMMENT + else if (info->fileEof) { + type = ZCRCE; + } +#endif /* COMMENT */ + else if (qfull) { + type = ZCRCW; + } else { + switch (info->Streaming) { + case Full: + case Segmented: + type = ZCRCG; + break; + + case StrWindow: + if ((info->windowCount += len) < info->windowsize / 4) { + type = ZCRCG; + } else { + type = ZCRCQ; + info->windowCount = 0; + } + break; + + default: + case SlidingWindow: + type = ZCRCQ; + break; + } + } + + { + int crc32 = info->crc32; + int c = 0, c2, atSign = 0; + ulong crc; + uchar *ptr = info->buffer; + + crc = crc32 ? 0xffffffff : 0; + + /* read characters from file and put into buffer until buffer is + * full or file is exhausted + */ + + + while (len > 0 && (c = getc(info->file)) != EOF) { + if (!crc32) { + crc = updcrc(c, crc); + } else { + crc = UPDC32(c, crc); + } + + /* zmodem protocol requires that CAN(ZDLE), DLE, XON, XOFF and + * a CR following '@' be escaped. In addition, I escape '^]' + * to protect telnet, "~." to protect rlogin, and ESC for good + * measure. + */ + c2 = c &0177; + if (c == ZDLE || c2 == 020 || c2 == 021 || c2 == 023 || c2 == 0177 || c2 == + '\r' || c2 == '\n' || c2 == 033 || c2 == 035 || (c2 < 040 && info->escCtrl)) { + *ptr++ = ZDLE; + if (c == 0177) { + *ptr = ZRUB0; + } else if (c == 0377) { + *ptr = ZRUB1; + } else { + *ptr = c ^ 0100; + } + len -= 2; + } else { + *ptr = c; + --len; + } + ++ptr; + + atSign = c2 == '@'; + ++info->offset; + } + + /* if we've reached file end, a ZEOF header will follow. If + * there's room in the outgoing buffer for it, end the packet + * with ZCRCE and append the ZEOF header. If there isn't room, + * we'll have to do a ZCRCW + */ + if ((info->fileEof = (c == EOF))) { + if (qfull || (info->bufsize != 0 && len < 24)) { + type = ZCRCW; + } else { + type = ZCRCE; + } + } + + *ptr++ = ZDLE; + if (!crc32) { + crc = updcrc(type, crc); + } else { + crc = UPDC32(type, crc); + } + *ptr++ = type; + + if (!crc32) { + crc = updcrc(0, crc); + crc = updcrc(0, crc); + ptr = putZdle(ptr, (crc >> 8) &0xff, info); + ptr = putZdle(ptr, crc &0xff, info); + } else { + crc = ~crc; + for (len = 4; --len >= 0; crc >>= 8) { + ptr = putZdle(ptr, crc &0xff, info); + } + } + + len = ptr - info->buffer; + } + + ZStatus(SndByteCount, info->offset, NULL); + + if ((err = ZXmitStr(info->buffer, len, info))) { + return err; + } + +#ifdef COMMENT + if ((err = ZXmitData(ZBIN, len, uchar(type), info->buffer, info))) { + return err; + } +#endif /* COMMENT */ + + /* finally, do we want to wait after this packet? */ + + switch (type) { + case ZCRCE: + info->state = SendEof; + info->timeout = 60; + return ZXmitHdrHex(ZEOF, ZEnc4(info->offset), info); + case ZCRCW: + info->state = info->fileEof ? SendDone : SendWait; + info->timeout = 60; + break; + default: + info->state = Sending; + info->timeout = 0; + break; + } + + +#ifdef COMMENT + if (info->fileEof) { + /* Yes, file is done, send EOF and wait */ + info->state = SendEof; + info->timeout = 60; + return ZXmitHdrHex(ZEOF, ZEnc4(info->offset), info); + } else if (type == ZCRCW) { + info->state = SendWait; + info->timeout = 60; + } else { + info->state = Sending; + info->timeout = 0; + } +#endif /* COMMENT */ + return 0; +} + + +uint FQTermZmodem::rcvHex(uint i, char c) { + if (c <= '9') { + c -= '0'; + } else if (c <= 'F') { + c -= 'A' - 10; + } else { + c -= 'a' - 10; + } + return (i << 4) + c; +} + + +int FQTermZmodem::dataSetup(register ZModem *info) { + info->InputState = Indata; + info->chrCount = 0; + info->crcCount = 0; + info->crc = (info->DataType != ZBIN32) ? 0 : 0xffffffffL; + return 0; +} + +int FQTermZmodem::ZWriteFile(uchar *buffer, int len, FILE *file, ZModem*) { + return (int)fwrite(buffer, 1, len, file) == len ? 0 : ZmErrSys; +} + +int FQTermZmodem::ZCloseFile(ZModem *info) { + //to be completed + fclose(info->file); + return 0; +} + +void FQTermZmodem::ZFlowControl(int onoff, ZModem *info) { + //to be completed +} + +int FQTermZmodem::GotSinit(ZModem *info) { + zmodemlog("GotSinit[%s]: call dataSetup\n", sname(info)); + + info->zsinitflags = info->hdrData[4]; + info->escCtrl = info->zsinitflags &TESCCTL; + info->escHibit = info->zsinitflags &TESC8; + ZFlowControl(1, info); + return dataSetup(info); +} + +int FQTermZmodem::GotFile(ZModem *info) { + zmodemlog("GotFile[%s]: call dataSetup\n", sname(info)); + + info->errCount = 0; + info->f0 = info->hdrData[4]; + info->f1 = info->hdrData[3]; + info->f2 = info->hdrData[2]; + info->f3 = info->hdrData[1]; + return dataSetup(info); +} + +int FQTermZmodem::GotFin(ZModem *info) { + int i; + zmodemlog("GotFin[%s]: send ZFIN\n", sname(info)); + info->InputState = Finish; + info->chrCount = 0; + if (info->filename != NULL) { + free(info->filename); + } + i = ZXmitHdrHex(ZFIN, zeros, info); + ZmodemReset(info); + transferstate = transferstop; // transfer complete + return i; +} + + +int FQTermZmodem::GotData(ZModem *info) { + int err; + + zmodemlog("GotData[%s]:\n", sname(info)); + + if (ZDec4(info->hdrData + 1) != info->offset) { + if (info->attn != NULL && (err = ZAttn(info)) != 0) { + return err; + } + zmodemlog(" bad, send ZRPOS(%ld)\n", info->offset); + return ZXmitHdrHex(ZRPOS, ZEnc4(info->offset), info); + } + + /* Let's do it! */ + zmodemlog(" call dataSetup\n"); + return dataSetup(info); +} + +int FQTermZmodem::GotEof(ZModem *info) { + zmodemlog("GotEof[%s]: offset=%ld\n", sname(info), info->offset); + if (ZDec4(info->hdrData + 1) != info->offset) { + zmodemlog("zdec4(info->hdrdata+1)=%ld\n", ZDec4(info->hdrData + 1)); + zmodemlog(" bad length, state = RFile\n"); + info->state = RFile; + return 0; /* it was probably spurious */ + } + + /* TODO: if we can't close the file, send a ZFERR */ + + ZCloseFile(info); + info->file = NULL; + ZStatus(FileEnd, 0, info->filename); + if (info->filename != NULL) { + free(info->filename); + info->filename = NULL; + } + return SendRinit(info); +} + +int FQTermZmodem::GotFreecnt(ZModem *info) { + /* TODO: how do we find free space on system? */ + return ZXmitHdrHex(ZACK, ZEnc4(0xffffffff), info); +} + + +int FQTermZmodem::GotFileCrc(ZModem *info) { + zmodemlog("GotFileCrc[%s]: call requestFile\n", sname(info)); + return requestFile(info, ZDec4(info->hdrData + 1)); +} + +int FQTermZmodem::requestFile(ZModem *info, ulong crc) { + info->file = ZOpenFile((char*)info->buffer, crc, info); + + if (info->file == NULL) { + zmodemlog("requestFile[%s]: send ZSKIP\n", sname(info)); + + info->state = RStart; + ZStatus(FileSkip, 0, info->filename); + return ZXmitHdrHex(ZSKIP, zeros, info); + } else { + zmodemlog("requestFile[%s]: send ZRPOS(%ld)\n", sname(info), info->offset); + info->offset = info->f0 == ZCRESUM ? ftell(info->file): 0; + info->state = RFile; + ZStatus(FileBegin, info->len, info->filename); + return ZXmitHdrHex(ZRPOS, ZEnc4(info->offset), info); + } +} + +void FQTermZmodem::parseFileName(ZModem *info, char *fileinfo) { + char *ptr; + int serial = 0; + + info->len = info->mode = info->filesRem = info->bytesRem = info->fileType = 0; + ptr = fileinfo + strlen(fileinfo) + 1; + if (info->filename != NULL) { + free(info->filename); + } + info->filename = strdup(fileinfo); + sscanf(ptr, "%d %lo %o %o %d %d %d", &info->len, &info->date, &info->mode, + &serial, &info->filesRem, &info->bytesRem, &info->fileType); +} + + + +int FQTermZmodem::fileError(ZModem *info, int type, int data) { + int err; + + info->InputState = Idle; + info->chrCount = 0; + + if (info->attn != NULL && (err = ZAttn(info)) != 0) { + return err; + } + return ZXmitHdrHex(type, ZEnc4(data), info); +} + + +int FQTermZmodem::ProcessPacket(ZModem *info) { + int idx = (uchar)info->buffer[0]; + int idxc = (uchar)info->buffer[1]; + int crc0, crc1; + int err; + + info->state = YRDataWait; + + if (idxc != 255-idx) { + ZStatus(DataErr, ++info->errCount, NULL); + return rejectPacket(info); + } + + if (idx == (info->packetCount % 256)) + /* quietly ignore dup */ { + return acceptPacket(info); + } + + if (idx != (info->packetCount + 1) % 256) { + /* out of sequence */ + (void)ZXmitStr(CanStr, 2, info); + return ZmErrSequence; + } + + crc0 = (uchar)info->buffer[info->pktLen - 2] << 8 + | (uchar)info->buffer[info->pktLen - 1]; + crc1 = calcCrc(info->buffer + 2, info->pktLen - 4); + if (crc0 != crc1) { + ZStatus(DataErr, ++info->errCount, NULL); + return rejectPacket(info); + } + + ++info->packetCount; + + if (info->packetCount == 0) { + /* packet 0 is filename */ + if (info->buffer[2] == '\0') { + /* null filename is FIN */ + (void)acceptPacket(info); + return ZmDone; + } + + parseFileName(info, (char*)info->buffer + 2); + info->file = ZOpenFile(info->filename, 0, info); + if (info->file == NULL) { + (void)ZXmitStr(CanStr, 2, info); + return ZmErrCantOpen; + } + if ((err = acceptPacket(info)) != 0) { + return err; + } + return ZXmitStr((uchar*)"C", 1, info); + } + + + if (ZWriteFile(info->buffer + 2, info->pktLen - 4, info->file, info)) { + ZStatus(FileErr, zerrno, NULL); + (void)ZXmitStr(CanStr, 2, info); + return ZmErrSys; + } + info->offset += info->pktLen - 4; + ZStatus(RcvByteCount, info->offset, NULL); + + (void)acceptPacket(info); + return 0; +} + +int FQTermZmodem::rejectPacket(ZModem *info) { + info->timeout = 10; + return ZXmitStr(NakStr, 1, info); +} + + +int FQTermZmodem::acceptPacket(ZModem *info) { + info->state = YRDataWait; + info->timeout = 10; + return ZXmitStr(AckStr, 1, info); +} + + +int FQTermZmodem::calcCrc(uchar *str, int len) { + int crc = 0; + while (--len >= 0) { + crc = updcrc(*str++, crc); + } + crc = updcrc(0, crc); + crc = updcrc(0, crc); + return crc &0xffff; +} + + +char *FQTermZmodem::strdup(const char *str) { + char *rval; + int len = strlen(str) + 1; + rval = (char*)malloc(len); + strcpy(rval, str); + return rval; +} + + +int FQTermZmodem::ZXmitData(int format, int len, uchar term, uchar *data, ZModem + *info) { + uchar *ptr = info->buffer; + uint crc; + + if (format == ZBIN && info->crc32) { + format = ZBIN32; + } + + zmodemlog("ZXmiteData: fmt=%c, len=%d, term=%c\n", format, len, term); + + crc = (format == ZBIN) ? 0 : 0xffffffff; + + while (--len >= 0) { + if (format == ZBIN) { + crc = updcrc(*data, crc); + } else { + crc = UPDC32(*data, crc); + } + ptr = putZdle(ptr, *data++, info); + } + + *ptr++ = ZDLE; + if (format == ZBIN) { + crc = updcrc(term, crc); + } else { + crc = UPDC32(term, crc); + } + *ptr++ = term; + if (format == ZBIN) { + crc = updcrc(0, crc); + crc = updcrc(0, crc); + ptr = putZdle(ptr, (crc >> 8) &0xff, info); + ptr = putZdle(ptr, crc &0xff, info); + } else { + crc = ~crc; + for (len = 4; --len >= 0; crc >>= 8) { + ptr = putZdle(ptr, crc &0xff, info); + } + } + + return ZXmitStr(info->buffer, ptr - info->buffer, info); +} + + + +int FQTermZmodem::YXmitData(uchar *buffer, int len, ZModem *info) { + uchar hdr[3]; + uchar trail[2]; + ulong crc = 0; + int i, err; + + hdr[0] = len == 1024 ? STX : SOH; + hdr[1] = info->packetCount; + hdr[2] = ~hdr[1]; + if ((err = ZXmitStr(hdr, 3, info)) || (err = ZXmitStr(buffer, len, info))) { + return err; + } + + if (info->PacketType == NAK) { + /* checksum */ + for (i = 0; i < len; ++i) { + crc += buffer[i]; + } + trail[0] = crc % 256; + return ZXmitStr(trail, 1, info); + } else { + for (i = 0; i < len; ++i) { + crc = updcrc(buffer[i], crc); + } + crc = updcrc(0, crc); + crc = updcrc(0, crc); + trail[0] = crc / 256; + trail[1] = crc % 256; + return ZXmitStr(trail, 2, info); + } +} + + +int FQTermZmodem::YSendFilename(ZModem *info) { + int i, len; + uchar obuf[1024]; + uchar *ptr = obuf; + + info->state = info->PacketType != 'G' ? YTFile : YTDataWait; + info->packetCount = 0; + info->offset = 0; + + i = strlen(info->rfilename); + memcpy(ptr, info->rfilename, i + 1); + ptr += i + 1; + sprintf((char*)ptr, "%d %lo %o 0", info->len, info->date, info->mode); + ptr += strlen((char*)ptr); + *ptr++ = '\0'; + /* pad out to 128 bytes or 1024 bytes */ + i = ptr - obuf; + len = i > 128 ? 1024 : 128; + for (; i < len; ++i) { + *ptr++ = '\0'; + } + + return YXmitData(obuf, len, info); +} + +int FQTermZmodem::YSendData(ZModem *info) { + int i; + + /* are there characters still in the read buffer? */ + + if (info->chrCount <= 0) { + info->bufp = 0; + info->chrCount = fread(info->buffer, 1, info->packetsize, info->file); + info->fileEof = feof(info->file); + } + + if (info->chrCount <= 0) { + fclose(info->file); + info->state = YTEOF; + return ZXmitStr(eotstr, 1, info); + } + + /* pad out to 128 bytes if needed */ + if (info->chrCount < 128) { + i = 128-info->chrCount; + memset(info->buffer + info->bufp + info->chrCount, 0x1a, i); + info->chrCount = 128; + } + + info->ylen = info->chrCount >= 1024 ? 1024 : 128; + ++info->packetCount; + + info->state = YTData; + + return YXmitData(info->buffer + info->bufp, info->ylen, info); +} + + +int FQTermZmodem::YSendFin(ZModem *info) { + uchar obuf[128]; + + info->state = YTFin; + info->packetCount = 0; + + memset(obuf, 0, 128); + + return YXmitData(obuf, 128, info); +} + +int FQTermZmodem::sendFilename(ZModem *info) { + int err; + int i; + uchar obuf[2048]; + uchar *ptr = obuf; + + info->state = FileWait; + + if ((err = ZXmitHdr(ZFILE, ZBIN, info->fileFlags, info))) { + return err; + } + + i = strlen(info->rfilename); + memcpy(ptr, info->rfilename, i + 1); + ptr += i + 1; + sprintf((char*)ptr, "%d %lo %o 0 %d %d 0", info->len, info->date, info->mode, + info->filesRem, info->bytesRem); + ptr += strlen((char*)ptr); + *ptr++ = '\0'; + + return ZXmitData(ZBIN, ptr - obuf, ZCRCW, obuf, info); +} + +int FQTermZmodem::GotRinit(ZModem *info) { + if (strFileList.count() == 0) { + return ZmodemTFinish(info); + } + + + info->bufsize = info->hdrData[1] + info->hdrData[2] *256; + info->zrinitflags = info->hdrData[4] + info->hdrData[3] *256; + info->crc32 = info->zrinitflags &CANFC32; + info->escCtrl = info->zrinitflags &ESCCTL; + info->escHibit = info->zrinitflags &ESC8; + + /* Full streaming: If receiver can overlap I/O, and if + * the sender can sample the reverse channel without hanging, + * and the receiver has not specified a buffer size, then we + * can simply blast away with ZCRCG packets. If the receiver + * detects an error, it sends an attn sequence and a new ZRPOS + * header to restart the file where the error occurred. + * + * [note that zmodem8.doc does not define how much noise is + * required to trigger a ZCRCW packet. We arbitrarily choose + * 64 bytes] + * + * If 'windowsize' is nonzero, and the receiver can do full + * duplex, ZCRCQ packets are sent instead of ZCRCG, to keep track + * of the number of characters in the queue. If the queue fills + * up, we pause and wait for a ZACK. + * + * + * Full Streaming with Reverse Interrupt: If sender cannot + * sample the input stream, then we define an Attn sequence + * that will be used to interrupt transmission. + * + * + * Full Streaming with Sliding Window: If sender cannot + * sample input stream or respond to Attn signal, we send + * several ZCRCQ packets until we're sure the receiver must + * have sent back at least one ZACK. Then we stop sending and + * read that ZACK. Then we send one more packet and so on. + * + * + * Segmented Streaming: If receiver cannot overlap I/O or can't do + * full duplex and has specified a maximum receive buffer size, + * whenever the buffer size is reached, we send a ZCRCW packet. + * + * TODO: what if receiver can't overlap, but hasn't set a buffer + * size? + * + * ZCRCE: CRC next, frame ends, header follows + * ZCRCG: CRC next, frame continues nonstop + * ZCRCQ: CRC next, send ZACK, frame continues nonstop + * ZCRCW: CRC next, send ZACK, frame ends, header follows + */ + + transferstate = transferstart; + + ZFlowControl(1, info); + + if ((info->zrinitflags &(CANFDX | CANOVIO)) == (CANFDX | CANOVIO) && + (SendSample || SendAttn) && info->bufsize == 0) { + if (info->windowsize == 0) { + info->Streaming = Full; + } else { + info->Streaming = StrWindow; + } + } + + else if ((info->zrinitflags &(CANFDX | CANOVIO)) == (CANFDX | CANOVIO) && + info->bufsize == 0) { + info->Streaming = SlidingWindow; + } + + else { + info->Streaming = Segmented; + } + // get filenames to transfer + zmodemlog("GotRinit[%s]\n", sname(info)); + + if (AlwaysSinit || info->zsinitflags != 0 || info->attn != NULL) { + SendZSInit(info); + } + + + itFile = strFileList.begin(); + QFileInfo fi(*itFile); + FQ_TRACE("zmodem", 0) << "Number of files to be transfered: " + << strFileList.count(); + char *filename = strdup(fi.absoluteFilePath().toLatin1()); + char *rfilename = strdup(fi.fileName().toLatin1()); + ZmodemTFile(filename, rfilename, 0, 0, 0, 0, strFileList.count(), fi.size(), + info); + strFileList.erase(itFile); + return ZmDone; +} + + +int FQTermZmodem::SendZSInit(ZModem *info) { + char tmp = '\0'; + int err; + //char *at = (info->attn != NULL) ? info->attn : "" ; + char *at; + if (info->attn != NULL) { + at = info->attn; + } else { + at = &tmp; + } + uchar fbuf[4]; + + /* TODO: zmodem8.doc states: "If the ZSINIT header specifies + * ESCCTL or ESC8, a HEX header is used, and the receiver + * activates the specified ESC modes before reading the following + * data subpacket." What does that mean? + */ + + zmodemlog("SendZSInit[%s]\n", sname(info)); + + info->state = TInit; + fbuf[0] = fbuf[1] = fbuf[2] = 0; + fbuf[3] = info->zsinitflags; + if ((err = ZXmitHdr(ZSINIT, ZBIN, fbuf, info)) || (err = ZXmitData(ZBIN, + strlen(at) + 1, ZCRCW, (uchar*)at, info))) { + return err; + } + return 0; +} + + +int FQTermZmodem::SendFileCrc(ZModem *info) { + ulong crc; + + crc = FileCrc(info->filename); + + zmodemlog("SendFileCrc[%s]: %lx\n", sname(info), crc); + + return ZXmitHdrHex(ZCRC, ZEnc4(crc), info); +} + +int FQTermZmodem::GotSendAck(ZModem *info) { + ulong offset; + + offset = ZDec4(info->hdrData + 1); + + if (offset > info->lastOffset) { + info->lastOffset = offset; + } + + zmodemlog("GotSendAck[%s]: %lx\n", sname(info), info->offset); + + return 0; /* DONT send more data, that will happen + * later anyway */ +} + +int FQTermZmodem::GotSendDoneAck(ZModem *info) { + ulong offset; + + offset = ZDec4(info->hdrData + 1); + + if (offset > info->lastOffset) { + info->lastOffset = offset; + } + + zmodemlog("GotSendDoneAck[%s]: %ld\n", sname(info), info->offset); + + info->state = SendEof; + info->timeout = 60; + return ZXmitHdrHex(ZEOF, ZEnc4(info->offset), info); +} + +int FQTermZmodem::GotSendNak(ZModem *info) { + info->offset = info->zrposOffset; + + fseek(info->file, info->offset, 0); + + /* TODO: what if fseek fails? Send EOF? */ + + zmodemlog("GotSendNak[%s]: %ld\n", sname(info), info->offset); + + return SendMoreFileData(info); +} + +int FQTermZmodem::GotSendWaitAck(ZModem *info) { + + ulong offset; + int err; + + offset = ZDec4(info->hdrData + 1); + + FQ_TRACE("zmodem", 10) << "last = " << info->lastOffset + << ", now = " << offset; + + if (offset > info->lastOffset) { + info->lastOffset = offset; + } + + //receiver return -1 without setting this flag, kingson 00:07 14-07-04 + info->waitflag = 1; + + zmodemlog("GotSendWaitAck[%s]\n", sname(info), offset); + + if ((err = ZXmitHdr(ZDATA, ZBIN, info->hdrData + 1, info))) { + return err; + } + return SendMoreFileData(info); +} + +int FQTermZmodem::SkipFile(ZModem *info) { + zmodemlog("SkipFile[%s]\n", sname(info)); + ZStatus(FileEnd, 0, info->rfilename); + fclose(info->file); + + // stupid SMTH doesnt send further command, kick + // lets send files in the list + info->state = TStart; + return GotRinit(info); +} + +int FQTermZmodem::GotSendPos(ZModem *info) { + ZStatus(DataErr, ++info->errCount, NULL); + info->waitflag = 1; /* next pkt should wait, to resync */ + FQ_TRACE("zmodem", 9) << "GotSendPos, offset = " << info->offset; + zmodemlog("GotSendPos[%s] %lx\n", sname(info), info->offset); + return startFileData(info); +} + +int FQTermZmodem::SendFileData(ZModem *info) { + info->waitflag = 0; + return startFileData(info); +} + +int FQTermZmodem::ResendEof(ZModem *info) { + return ZXmitHdrHex(ZEOF, ZEnc4(info->offset), info); +} + +int FQTermZmodem::OverAndOut(ZModem *info) { + zmodemlog("OverAndOut[%s]\n", sname(info)); + + ZXmitStr((uchar*)"OO", 2, info); + + transferstate = transferstop; // transfer complete + + ZmodemReset(info); //Tranfer complete, zmodem return to receive state + + return ZmDone; +} + +int FQTermZmodem::startFileData(ZModem *info) { + int err; + + info->offset = info->lastOffset = info->zrposOffset = ZDec4(info->hdrData + 1); + + fseek(info->file, info->offset, 0); + + /* TODO: what if fseek fails? Send EOF? */ + + zmodemlog("startFileData[%s]: %lx\n", sname(info), info->offset); + + if ((err = ZXmitHdr(ZDATA, ZBIN, ZEnc4(info->offset), info))) { + return err; + } + return SendMoreFileData(info); +} + +uchar *FQTermZmodem::putHex(uchar *ptr, uchar c) { + *ptr++ = hexChars[(c >> 4) &0xf]; + *ptr++ = hexChars[c &0xf]; + return ptr; +} + + +int FQTermZmodem::ZmodemReset(ZModem *info) { + zmodemlog("\nZmodemReset\n"); + + ZmodemRInit(info); + + return 0; +} + + +void FQTermZmodem::zmodemlog(const char *fmt, ...) { + // only for debug +#ifdef FQTERM_ZMODEM_DEBUG + va_list ap; + struct timeval tv; + struct tm *tm; + static int do_ts = 1; + + zmodemlogfile = fopen("zmodem.log", "a"); + + if (zmodemlogfile == NULL) { + return ; + } + + if (do_ts) { + gettimeofday(&tv, NULL); + tm = localtime(&tv.tv_sec); + fprintf(zmodemlogfile, "%2.2d:%2.2d:%2.2d.%2.2ld: ", tm->tm_hour, tm->tm_min, + tm->tm_sec, tv.tv_usec / 10000); + } + do_ts = strchr(fmt, '\n') != NULL; + + va_start(ap, fmt); + vfprintf(zmodemlogfile, fmt, ap); + va_end(ap); + + fclose(zmodemlogfile); +#endif + +} + +void FQTermZmodem::zmodemCancel() { + ZmodemAbort(&info); +} + +} // namespace FQTerm + +#include "fqterm_zmodem.moc" + diff --git a/src/terminal/internal/fqterm_zmodem.h b/src/terminal/internal/fqterm_zmodem.h new file mode 100644 index 0000000..bd1f4f4 --- /dev/null +++ b/src/terminal/internal/fqterm_zmodem.h @@ -0,0 +1,623 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_ZMODEM_H +#define FQTERM_ZMODEM_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace FQTerm { + +/* PARAMETERS + * + * The following #defines control the behavior of the Zmodem + * package. Note that these may be replaced with variables + * if you like. For example, "#define DoInitRZ" may be replaced + * with "extern int DoInitRz" to use a global variable, or with + * "#define DoInitRZ (info->doInitRz)" to use a variable you + * add to the ZModem structure. + * + * It is assumed that the compiler is good enough to optimize + * "if( 0 )" and "if( 1 )" cases. If not, you may wish to modify + * the source code to use #ifdef instead. + */ + +#define DoInitRZ 1 /* send initial "rz\r" when transmitting */ +#define AllowCommand 0 /* allow remote end to execute commands */ +#define SendSample 1 /* sender can sample reverse channel */ +#define SendAttn 1 /* sender can be interrupted with Attn signal */ +#define ResponseTime 10 /* reasonable response time for sender to + * respond to requests from receiver */ +#define SerialNo 1 /* receiver serial # */ +#define MaxNoise 64 /* max "noise" characters before transmission + * pauses */ +#define MaxErrs 30 /* Max receive errors before cancel */ +#define AlwaysSinit 1 /* always send ZSINIT header, even if not + * needed, this makes protocol more robust */ + +#define SendOnly 0 /* compiles smaller version for send only */ +#define RcvOnly 0 /* compiles smaller version for receive only */ + +enum enum_InputState { + Idle, Padding, Inhdr, Indata, Finish, Ysend, Yrcv +}; +enum enum_Protocol { + XMODEM, YMODEM, ZMODEM +}; +enum enum_Streaming { + Full, StrWindow, SlidingWindow, Segmented +}; +enum enum_transferstate { + notransfer, transferstart, transferstop +}; + + +/* Internal State */ + +typedef enum zmstate { + /* receive */ + RStart, /* sent RINIT, waiting for ZFILE or SINIT */ + RSinitWait, /* got SINIT, waiting for data */ + RFileName, /* got ZFILE, waiting for filename & info */ + RCrc, /* got filename, want crc too */ + RFile, /* got filename, ready to read */ + RData, /* reading data */ + RDataErr, /* encountered error, ignoring input */ + RFinish, /* sent ZFIN, waiting for 'OO' */ + + /* transmit */ + TStart, /* waiting for INIT frame from other end */ + TInit, /* received INIT, sent INIT, waiting for ZACK */ + FileWait, /* sent file header, waiting for ZRPOS */ + CrcWait, /* sent file crc, waiting for ZRPOS */ + Sending, /* sending data subpackets, ready for int */ + SendWait, /* waiting for ZACK */ + SendDone, /* file finished, need to send EOF */ + SendEof, /* sent EOF, waiting for ZACK */ + TFinish, /* sent ZFIN, waiting for ZFIN */ + + /* general */ + CommandData, /* waiting for command data */ + CommandWait, /* waiting for command to execute */ + StderrData, /* waiting for stderr data */ + Done, + + /* x/ymodem transmit */ + YTStart, /* waiting for 'G', 'C' or NAK */ + YTFile, /* sent filename, waiting for ACK */ + YTDataWait, /* ready to send data, waiting for 'C' */ + YTData, /* sent data, waiting for ACK */ + YTEOF, /* sent eof, waiting for ACK */ + YTFin, /* sent null filename, waiting for ACK */ + + /* x/ymodem receive */ + YRStart, /* sent 'C', waiting for filename */ + YRDataWait, /* received filename, waiting for data */ + YRData, /* receiving filename or data */ + YREOF /* received first EOT, waiting for 2nd */ + +} ZMState; + + + + +typedef struct { + int ifd; /* input fd, for use by caller's routines */ + int ofd; /* output fd, for use by caller's routines */ + FILE *file; /* file being transfered */ + int zrinitflags; /* receiver capabilities, see below */ + int zsinitflags; /* sender capabilities, see below */ + char *attn; /* attention string, see below */ + int timeout; /* timeout value, in seconds */ + int bufsize; /* receive buffer size, bytes */ + int packetsize; /* preferred transmit packet size */ + int windowsize; /* max window size */ + + /* file attributes: read-only */ + + int filesRem, bytesRem; + uchar f0, f1, f2, f3; /* file flags */ + int len, mode, fileType; /* file flags */ + ulong date; /* file date */ + + /* From here down, internal to Zmodem package */ + + ZMState state; /* protocol internal state */ + char *filename; /* filename */ + char *rfilename; /* remote filename */ + int crc32; /* use 32-bit crc */ + int pktLen; /* length of this packet */ + int DataType; /* input data type */ + int PacketType; /* type of this packet */ + int rcvlen; + int chrCount; /* chars received in current header/buffer */ + int crcCount; /* crc characters remaining at end of buffer */ + int canCount; /* how many CAN chars received? */ + int noiseCount; /* how many noise chars received? */ + int errorFlush; /* ignore incoming data because of error */ + uchar *buffer; /* data buffer */ + ulong offset; /* file offset */ + ulong lastOffset; /* last acknowledged offset */ + ulong zrposOffset; /* last offset specified w/zrpos */ + int ylen, bufp; /* len,location of last Ymodem packet */ + int fileEof; /* file eof reached */ + int packetCount; /* # packets received */ + int errCount; /* how many data errors? */ + int timeoutCount; /* how many times timed out? */ + int windowCount; /* how much data sent in current window */ + int atSign; /* last char was '@' */ + int lastCR; /* last char was CR */ + int escCtrl; /* other end requests ctrl chars be escaped */ + int escHibit; /* other end requests hi bit be escaped */ + int escape; /* next character is escaped */ + int interrupt; /* received attention signal */ + int waitflag; /* next send should wait */ + /* parser state */ + // enum enum_InputState {Idle, Padding, Inhdr, Indata, Finish, Ysend, Yrcv} InputState ; + enum_InputState InputState; + // enum enum_Protocol {XMODEM, YMODEM, ZMODEM} Protocol ; + enum_Protocol Protocol; + uchar hdrData[9]; /* header type and data */ + uchar fileFlags[4]; /* file xfer flags */ + ulong crc; /* crc of incoming header/data */ + // enum enum_Streaming {Full, StrWindow, SlidingWindow, Segmented} Streaming ; + enum_Streaming Streaming; +} ZModem; + + + +/* ZRINIT flags. Describe receiver capabilities */ + +#define CANFDX 1 /* Rx is Full duplex */ +#define CANOVIO 2 /* Rx can overlap I/O */ +#define CANBRK 4 /* Rx can send a break */ +#define CANCRY 010 /* Rx can decrypt */ +#define CANLZW 020 /* Rx can uncompress */ +#define CANFC32 040 /* Rx can use 32-bit crc */ +#define ESCCTL 0100 /* Rx needs control chars escaped */ +#define ESC8 0200 /* Rx needs 8th bit escaped. */ + +/* ZSINIT flags. Describe sender capabilities */ + +#define TESCCTL 0100 /* Tx needs control chars escaped */ +#define TESC8 0200 /* Tx needs 8th bit escaped. */ + + +/* ZFILE transfer flags */ + +/* F0 */ +#define ZCBIN 1 /* binary transfer */ +#define ZCNL 2 /* convert NL to local eol convention */ +#define ZCRESUM 3 /* resume interrupted file xfer, or append to a + growing file. */ + +/* F1 */ +#define ZMNEWL 1 /* transfer if source newer or longer */ +#define ZMCRC 2 /* transfer if different CRC or length */ +#define ZMAPND 3 /* append to existing file, if any */ +#define ZMCLOB 4 /* replace existing file */ +#define ZMNEW 5 /* transfer if source is newer */ +#define ZMDIFF 6 /* transfer if dates or lengths different */ +#define ZMPROT 7 /* protect: transfer only if dest doesn't exist */ +#define ZMCHNG 8 /* change filename if destination exists */ +#define ZMMASK 037 /* mask for above. */ +#define ZMSKNOLOC 0200 /* skip if not present at Rx end */ + +/* F2 */ +#define ZTLZW 1 /* lzw compression */ +#define ZTRLE 3 /* run-length encoding */ + +/* F3 */ +#define ZCANVHDR 1 /* variable headers ok */ +#define ZRWOVR 4 /* byte position for receive window override/256 */ +#define ZXSPARS 64 /* encoding for sparse file ops. */ + + + +/* ATTN string special characters. All other characters sent verbose */ + +#define ATTNBRK '\335' /* send break signal */ +#define ATTNPSE '\336' /* pause for one second */ + +/* error code definitions [O] means link still open */ + +#define ZmDone -1 /* done */ +#define ZmErrInt -2 /* internal error */ +#define ZmErrSys -3 /* system error, see errno */ +#define ZmErrNotOpen -4 /* communication channel not open */ +#define ZmErrCantOpen -5 /* can't open file, see errno [O] */ +#define ZmFileTooLong -6 /* remote filename too long [O] */ +#define ZmFileCantWrite -7 /* could not write file, see errno */ +#define ZmDataErr -8 /* too many data errors */ +#define ZmErrInitTo -10 /* transmitter failed to respond to init req. */ +#define ZmErrSequence -11 /* packet received out of sequence */ +#define ZmErrCancel -12 /* cancelled by remote end */ +#define ZmErrRcvTo -13 /* remote receiver timed out during transfer */ +#define ZmErrSndTo -14 /* remote sender timed out during transfer */ +#define ZmErrCmdTo -15 /* remote command timed out */ + + + +/* ZModem character definitions */ + +#define ZDLE 030 /* zmodem escape is CAN */ +#define ZPAD '*' /* pad */ +#define ZBIN 'A' /* introduces 16-bit crc binary header */ +#define ZHEX 'B' /* introduces 16-bit crc hex header */ +#define ZBIN32 'C' /* introduces 32-bit crc binary header */ +#define ZBINR32 'D' /* introduces RLE packed binary frame w/32-bit crc */ +#define ZVBIN 'a' /* alternate ZBIN */ +#define ZVHEX 'b' /* alternate ZHEX */ +#define ZVBIN32 'c' /* alternate ZBIN32 */ +#define ZVBINR32 'd' /* alternate ZBINR32 */ +#define ZRESC 0177 /* RLE flag/escape character */ + + + +/* ZModem header type codes */ + +#define ZRQINIT 0 /* request receive init */ +#define ZRINIT 1 /* receive init */ +#define ZSINIT 2 /* send init sequence, define Attn */ +#define ZACK 3 /* ACK */ +#define ZFILE 4 /* file name, from sender */ +#define ZSKIP 5 /* skip file command, from receiver */ +#define ZNAK 6 /* last packet was garbled */ +#define ZABORT 7 /* abort */ +#define ZFIN 8 /* finish session */ +#define ZRPOS 9 /* resume file from this position, from receiver */ +#define ZDATA 10 /* data packets to follow, from sender */ +#define ZEOF 11 /* end of file, from sender */ +#define ZFERR 12 /* fatal i/o error, from receiver */ +#define ZCRC 13 /* request for file crc, from receiver */ +#define ZCHALLENGE 14 /* "send this number back to me", from receiver */ +#define ZCOMPL 15 /* request is complete */ +#define ZCAN 16 /* other end cancelled with CAN-CAN-CAN-CAN-CAN */ +#define ZFREECNT 17 /* request for free bytes on filesystem */ +#define ZCOMMAND 18 /* command, from sending program */ +#define ZSTDERR 19 /* output this message to stderr */ + + +/* ZDLE escape sequences */ + + +#define ZCRCE 'h' /* CRC next, frame ends, header follows */ +#define ZCRCG 'i' /* CRC next, frame continues nonstop */ +#define ZCRCQ 'j' /* CRC next, send ZACK, frame continues nonstop */ +#define ZCRCW 'k' /* CRC next, send ZACK, frame ends */ +#define ZRUB0 'l' /* translate to 0177 */ +#define ZRUB1 'm' /* translate to 0377 */ + + +/* ascii definitions */ + +#define SOH 1 /* ^A */ +#define STX 2 /* ^B */ +#define EOT 4 /* ^D */ +#define ACK 6 /* ^F */ +#define DLE 16 /* ^P */ +#define XON 17 /* ^Q */ +#define XOFF 19 /* ^S */ +#define NAK 21 /* ^U */ +#define SYN 22 /* ^V */ +#define CAN 24 /* ^X */ + + +/* state table entry. There is one row of the table per + * possible state. Each row is a row of all reasonable + * inputs for this state. The entries are sorted so that + * the most common inputs occur first, to reduce search time + * Unexpected input is reported and ignored, as it might be + * caused by echo or something. + * + * Extra ZRINIT headers are the receiver trying to resync. + */ +class FQTermConfig; + +class FQTermZmodem; + +class FQTermTelnet; + +class FQTermFileDialog; + +typedef int(FQTermZmodem:: *ActionFunc)(ZModem*); + +typedef struct { + int type; /* frame type */ + // int (*func)(ZModem *) ; /* transition function */ + ActionFunc func; + int IFlush; /* flag: flush input first */ + int OFlush; /* flag: flush output first */ + ZMState newstate; /* new state. May be overridden by func */ +} StateTable; + +//class FQTermTelnet; + +class FQTermZmodem: public QObject { + Q_OBJECT; + public: + FQTermZmodem(FQTermConfig *config, FQTermTelnet *netinterface, int type, int serverEncoding); + ~FQTermZmodem(); + + /* zmodem-supplied functions: */ + int ZmodemTInit(ZModem *info); + int ZmodemTFile(char *file, char *rmtname, uint f0, uint f1, uint f2, uint f3, + int filesRem, int bytesRem, ZModem *info); + int ZmodemTFinish(ZModem *info); + int ZmodemAbort(ZModem *info); + int ZmodemRInit(ZModem *info); + int ZmodemRcv(uchar *str, int len, ZModem *info, int &consumed_bytes); + int ZmodemAttention(ZModem *info); + + int ZmodemReset(ZModem *info); + + int YmodemTInit(ZModem *info); + int XmodemTInit(ZModem *info); + int YmodemRInit(ZModem *info); + int XmodemRInit(ZModem *info); + + ulong FileCrc(char *name); + const char *sname(ZModem*); + const char *sname2(ZMState); + + /* caller-supplied functions: */ + int ZXmitChr(uchar c, ZModem *info); + int ZXmitStr(const uchar *str, int len, ZModem *info); + void ZIFlush(ZModem *info); + void ZOFlush(ZModem *info); + int ZAttn(ZModem *info); + void ZStatus(int type, int value, const char *status); + FILE *ZOpenFile(char *name, ulong crc, ZModem *info); + + int ZWriteFile(uchar *buffer, int len, FILE *, ZModem*); + int ZCloseFile(ZModem *info); + void ZFlowControl(int onoff, ZModem *info); + + /* end caller-supplied functions */ + + int ZXmitHdr(int type, int format, const uchar data[4], ZModem *info); + int ZXmitHdrHex(int type, const uchar data[4], ZModem *info); + int ZXmitHdrBin(int type, const uchar data[4], ZModem *info); + int ZXmitHdrBin32(int type, const uchar data[4], ZModem *info); + uchar *putZdle(uchar *ptr, uchar c, ZModem *info); + uchar *putHex(uchar *ptr, uchar c); + + uchar *ZEnc4(ulong n); + ulong ZDec4(const uchar buf[4]); + + int YrcvChar(char c, register ZModem *info); + int YrcvTimeout(register ZModem *info); + void ZIdleStr(uchar *buffer, int len, ZModem *info); + + /* LEXICAL BOX: handle characters received from remote end. + * These may be header, data or noise. + * + * This section is a finite state machine for parsing headers + * and reading input data. The info->chrCount field is effectively + * the state variable. + */ + + int FinishChar(char c, register ZModem *info); + int DataChar(uchar c, register ZModem *info); + int HdrChar(uchar c, register ZModem *info); + int IdleChar(uchar c, register ZModem *info); + + int YsendChar(char c, ZModem *info); + + int ZPF(ZModem *info); + int Ignore(ZModem *info); + int AnswerChallenge(register ZModem *info); + int GotAbort(register ZModem *info); + int GotCancel(ZModem *info); + int GotCommand(ZModem *info); + int GotStderr(register ZModem *info); + int RetDone(ZModem *info); + int GotCommandData(register ZModem *info, int crcGood); + int GotStderrData(register ZModem *info, int crcGood); + + int GotFileName(ZModem *info, int crcGood); + int ResendCrcReq(ZModem *info); + int GotSinitData(ZModem *info, int crcGood); + int ResendRpos(ZModem *info); + int GotFileData(ZModem *info, int crcGood); + int SendRinit(ZModem *info); + + int GotSinit(ZModem *info); + int GotFile(ZModem *info); + int GotFin(ZModem *info); + int GotData(ZModem *info); + int GotEof(ZModem *info); + int GotFreecnt(ZModem *info); + int GotFileCrc(ZModem *info); + + int GotRinit(ZModem*); + int SendZSInit(ZModem*); + int SendFileCrc(ZModem*); + int GotSendAck(ZModem*); + int GotSendDoneAck(ZModem*); + int GotSendNak(ZModem*); + int GotSendWaitAck(ZModem*); + int SkipFile(ZModem*); + int GotSendPos(ZModem*); + + int requestFile(ZModem *info, ulong crc); + void parseFileName(ZModem *info, char *fileinfo); + int fileError(ZModem *info, int type, int data); + + int ProcessPacket(ZModem *info); + int rejectPacket(ZModem *info); + int acceptPacket(ZModem *info); + + int calcCrc(uchar *str, int len); + + char *strdup(const char *str); + + int SendMoreFileData(ZModem *info); + + uint rcvHex(uint i, char c); + + int ZDataReceived(register ZModem *info, int crcGood); + int dataSetup(register ZModem *info); + int ZProtocol(register ZModem *info); + + int ZXmitData(int, int, uchar, uchar *data, ZModem*); + int YXmitData(uchar *, int, ZModem*); + + int YSendFilename(ZModem*); + int YSendData(ZModem*); + int YSendFin(ZModem*); + + int sendFilename(ZModem*); + int SendFileData(ZModem*); + int ResendEof(ZModem*); + + int OverAndOut(ZModem*); + + int startFileData(ZModem *info); + + void zmodemlog(const char *fmt, ...); + + // interface function + // all not completed + void transferTimeOut(void*); + void upload(char*); + void uploadNext(char*); + void transferFinish(); + void xferCancel(); + + /* data received from remote, pass it to Zmodem funcs */ + void transferSendData(char *, int); + void TransferCancel(); + +#if 1 + static StateTable RStartOps[]; + static StateTable RSinitWaitOps[]; + static StateTable RFileNameOps[]; + static StateTable RCrcOps[]; + static StateTable RFileOps[]; + static StateTable RDataOps[]; + static StateTable RFinishOps[]; + + + static StateTable TStartOps[]; + static StateTable TInitOps[]; + static StateTable FileWaitOps[]; + static StateTable CrcWaitOps[]; + static StateTable SendingOps[]; + static StateTable SendDoneOps[]; + static StateTable SendWaitOps[]; + static StateTable SendEofOps[]; + static StateTable TFinishOps[]; + + static StateTable CommandDataOps[]; + static StateTable CommandWaitOps[]; + static StateTable StderrDataOps[]; + static StateTable DoneOps[]; + + static StateTable *tables[]; + static const char *hdrnames[]; +#endif + +#if 0 + StateTable RStartOps[]; + StateTable RSinitWaitOps[]; + StateTable RFileNameOps[]; + StateTable RCrcOps[]; + StateTable RFileOps[]; + StateTable RDataOps[]; + StateTable RFinishOps[]; + + + StateTable TStartOps[]; + StateTable TInitOps[]; + StateTable FileWaitOps[]; + StateTable CrcWaitOps[]; + StateTable SendingOps[]; + StateTable SendDoneOps[]; + StateTable SendWaitOps[]; + StateTable SendEofOps[]; + StateTable TFinishOps[]; + + StateTable CommandDataOps[]; + StateTable CommandWaitOps[]; + StateTable StderrDataOps[]; + StateTable DoneOps[]; + + StateTable *tables[]; + char *hdrnames[]; +#endif + FQTermTelnet *telnet_; + FQTermConfig *config_; + // Dialog + // QDialog *zmodemDialog, uploadListDialog; + + bool sending; + + enum_transferstate transferstate; + + ZModem info; + + // connection type, e.g. telnet or ssh , 0=telnet, 1=ssh + + int connectionType; + + // Timer + QTimer *zmodemTimer; + + //log file + FILE *zmodemlogfile; + + int zerrno; + uchar lastPullByte; + + QStringList strFileList; + QStringList::Iterator itFile; + + int serverEncodingID; + + QString lastDownloadedFilename_; + + // end Member + signals: + void ZmodemState(int, int, const char *); + + public slots: + void zmodemCancel(); + int ZmodemTimeout(); +}; + +} // namespace FQTerm + +#endif // FQTERM_ZMODEM_H diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt new file mode 100644 index 0000000..09af483 --- /dev/null +++ b/src/ui/CMakeLists.txt @@ -0,0 +1,122 @@ +set(fqterm_ui_SRCS + aboutdialog.h + addrdialog.h + articledialog.h + keydialog.h + msgdialog.h + prefdialog.h + quickdialog.h + schemadialog.h + soundconf.h + sshlogindialog.h + zmodemdialog.h + aboutdialog.cpp + addrdialog.cpp + articledialog.cpp + keydialog.cpp + msgdialog.cpp + prefdialog.cpp + quickdialog.cpp + schemadialog.cpp + soundconf.cpp + sshlogindialog.cpp + zmodemdialog.cpp + osdmessage.h + osdmessage.cpp + overlayWidget.h + overlayWidget.cpp + pictureflow.h + pictureflow.cpp + popupMessage.h + popupMessage.cpp + popwidget.h + popwidget.cpp + progressBar.h + progressBar.cpp + fqterm_time_label.h + fqterm_time_label.cpp + fqterm_tool_button.h + fqterm_tool_button.cpp + imageviewer.h + imageviewer.cpp + shortcutdialog.h + shortcutdialog.cpp + statusBar.h + statusBar.cpp + fqterm_canvas.h + fqterm_canvas.cpp + sitemanager.h + sitemanager.cpp + iplookup.h + iplookup.cpp + defineescape.h + defineescape.cpp +) + +set(fqterm_ui_gen_HS + ui_aboutdialog.h + ui_addrdialog.h + ui_articledialog.h + ui_keydialog.h + ui_msgdialog.h + ui_prefdialog.h + ui_quickdialog.h + ui_schemadialog.h + ui_sitemanager.h + ui_soundconf.h + ui_sshlogin.h + ui_zmodemdialog.h + ui_iplookup.h + ui_defineescape.h +) + +set(fqterm_ui_UIS + aboutdialog.ui + addrdialog.ui + articledialog.ui + keydialog.ui + msgdialog.ui + prefdialog.ui + quickdialog.ui + schemadialog.ui + sitemanager.ui + soundconf.ui + sshlogin.ui + zmodemdialog.ui + iplookup.ui + defineescape.ui +) + +qt4_wrap_ui(fqterm_ui_UIS_H + ${fqterm_ui_UIS} +) + +qt4_automoc( + ${fqterm_ui_SRCS} + ${fqterm_ui_gen_HS} +) + +qt4_create_translation(fqterm_ui_qm_file + ${fqterm_ui_UIS} + ${fqterm_ui_SRCS} + ${CMAKE_SOURCE_DIR}/res/dict/ui_zh_CN.ts +) + +include_directories( + ${QT_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} + ${QT_QTGUI_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../common + ${CMAKE_CURRENT_SOURCE_DIR}/../utilities + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_library(fqterm_ui + ${fqterm_ui_SRCS} + ${fqterm_ui_gen_HS} +) + +add_dependencies(fqterm_ui + fqterm_common + fqterm_utilities +) diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp new file mode 100644 index 0000000..5c56dcc --- /dev/null +++ b/src/ui/aboutdialog.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "fqterm.h" +#include "fqterm_path.h" +#include "aboutdialog.h" + +namespace FQTerm { + +/* + * Constructs a aboutDialog which is a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +aboutDialog::aboutDialog(QWidget *parent, Qt::WFlags fl) + : QDialog(parent, fl) { + ui_.setupUi(this); + + QFile file(getPath(RESOURCE) + "credits"); + if (file.open(QIODevice::ReadOnly)) { + QTextStream stream(&file); + QString line; + while (!stream.atEnd()) { + // line of text excluding '\n' + line += stream.readLine() + "\n"; + } + ui_.TextBrowser->setPlainText(line); + file.close(); + } + QString aboutText = "FQTerm " + QString(FQTERM_VERSION_STRING) + QString("\nSVN revision ") + QString(FQTERM_SVN_REVISION) + QString("\n Built with Qt") + QT_VERSION_STR + QString("\n Running with Qt ") + qVersion(); + if (QString(FQTERM_VERSION_STRING).startsWith("0.9.8")) { + aboutText += "\n>>2012 - End of the world edition<<"; + } + ui_.TextLabel->setText(aboutText); +} + +/* + * Destroys the object and frees any allocated resources + */ +aboutDialog::~aboutDialog() { + // no need to delete child widgets, Qt does it all for us +} + +} // namespace FQTerm + +#include "aboutdialog.moc" diff --git a/src/ui/aboutdialog.h b/src/ui/aboutdialog.h new file mode 100644 index 0000000..cf40c4b --- /dev/null +++ b/src/ui/aboutdialog.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_ABOUT_DIALOG_H +#define FQTERM_ABOUT_DIALOG_H + +#include "ui_aboutdialog.h" + +namespace FQTerm { + +class aboutDialog: public QDialog { + Q_OBJECT; + public: + aboutDialog(QWidget *parent = 0, Qt::WFlags fl = 0); + ~aboutDialog(); + private: + Ui::aboutDialog ui_; +}; + +} // namespace FQTerm + +#endif // FQTERM_ABOUT_DIALOG_H diff --git a/src/ui/aboutdialog.ui b/src/ui/aboutdialog.ui new file mode 100644 index 0000000..5770cd8 --- /dev/null +++ b/src/ui/aboutdialog.ui @@ -0,0 +1,175 @@ + + aboutDialog + + + + 0 + 0 + 400 + 290 + + + + false + + + About FQTerm + + + + + + + + + true + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + FQTerm + + + Qt::AlignCenter + + + + + + + 0 + + + + + 0 + 0 + 376 + 194 + + + + About + + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br />FQTerm<br /><br /><br /><a href="http://code.google.com/p/fqterm"><span style=" text-decoration: underline; color:#0000ff;">http://code.google.com/p/fqterm</span></a></p></body></html> + + + Qt::RichText + + + Qt::AlignCenter + + + true + + + Qt::TextBrowserInteraction + + + + + + + + + 77 + 97 + 944 + 522 + + + + Authors + + + + + + fqterm@gmail.com + +devilphoenix@newsmth + + + Qt::AlignCenter + + + + + + + + + 100 + 120 + 944 + 522 + + + + Credits + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html> + + + + + + + + + + + Close + + + + + + + + closeButton + mainTabWidget + + + + + closeButton + clicked() + aboutDialog + accept() + + + 339 + 261 + + + 211 + 249 + + + + + diff --git a/src/ui/addrdialog.cpp b/src/ui/addrdialog.cpp new file mode 100644 index 0000000..79e62a8 --- /dev/null +++ b/src/ui/addrdialog.cpp @@ -0,0 +1,396 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fqterm_config.h" +#include "fqterm_param.h" +#include "fqterm_path.h" +#include "fqterm_trace.h" + +#include "addrdialog.h" +#include "schemadialog.h" + +namespace FQTerm { + +const int addrDialog::ports[3] = {23, 22, 22}; + +/* + * Constructs a addrDialog which is a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +addrDialog::addrDialog(QWidget *parent_, const FQTermParam& parameter, int buttons, Qt::WFlags fl) + : QDialog(parent_, fl), + menuButtonGroup_(this), + param_(parameter) { + ui_.setupUi(this); + menuButtonGroup_.addButton(ui_.radioButton1, 0); + menuButtonGroup_.addButton(ui_.radioButton2, 1); + menuButtonGroup_.addButton(ui_.radioButton3, 2); + if (!(buttons & SAVE)) + ui_.savePushButton->setVisible(false); + if (!(buttons & APPLY)) + ui_.applyPushButton->setVisible(false); + QMenu *fontMenu = new QMenu(this); + for (int i = 0; i < 2; ++i) { + QAction *act = fontMenu->addAction(FQTermParam::getLanguageName(bool(i)) + " Font", this, SLOT(onFont())); + act->setData(i); + } + ui_.fontToolButton->setMenu(fontMenu); + setUIFromParam(); + connector(); +} + +void addrDialog::setParamFromUI() { + param_.name_ = ui_.nameLineEdit->text(); + param_.hostAddress_ = ui_.addrLineEdit->text(); + param_.port_ = ui_.portLineEdit->text().toUShort(); + param_.hostType_ = ui_.hostTypeComboBox->currentIndex(); + param_.preLoginCommand_ = ui_.preloginLineEdit->text(); + param_.userName_ = ui_.userLineEdit->text(); + param_.password_ = ui_.passwdLineEdit->text(); + param_.postLoginCommand_ = ui_.postloginLineEdit->text(); + param_.serverEncodingID_ = ui_.bbscodeComboBox->currentIndex(); + param_.isFontAutoFit_ = ui_.fontAdjustComboBox->currentIndex(); + param_.isAlwaysHighlight_ = ui_.highlightCheckBox->isChecked(); + param_.isAnsiColor_ = ui_.ansicolorCheckBox->isChecked(); + param_.backgroundColor_ = ui_.fontPreviewer->palette().color(QPalette::Background); + param_.foregroundColor_ = ui_.fontPreviewer->palette().color(QPalette::Foreground); + param_.schemaFileName_ = ui_.schemaComboBox->currentText().isEmpty() || ui_.schemaComboBox->currentIndex() >= schemaDialog::getSchemaList().count() + ? "" : schemaDialog::getSchemaList()[ui_.schemaComboBox->currentIndex()].absoluteFilePath(); + param_.virtualTermType_ = ui_.termtypeLineEdit->text(); + param_.keyboardType_ = ui_.keytypeComboBox->currentIndex(); + param_.backspaceType_ = ui_.backspace8->isChecked()?0:1; + param_.numColumns_ = ui_.columnLineEdit->text().toInt(); + param_.numRows_ = ui_.rowLineEdit->text().toInt(); + param_.numScrollLines_ = ui_.scrollLineEdit->text().toInt(); + param_.cursorType_ = ui_.cursorTypeComboBox->currentIndex(); + param_.escapeString_ = ui_.escapeLineEdit->text(); + param_.proxyType_ = ui_.proxytypeComboBox->currentIndex(); + param_.proxyHostName_ = ui_.proxyaddrLineEdit->text(); + param_.proxyPort_ = ui_.proxyportLineEdit->text().toUShort(); + param_.isAuthentation_ = ui_.authentationGroup->isChecked(); + param_.proxyUserName_ = ui_.proxyuserLineEdit->text(); + param_.proxyPassword_ = ui_.proxypasswdLineEdit->text(); + param_.protocolType_ = ui_.protocolComboBox->currentIndex(); + if (param_.port_ != ports[param_.protocolType_]) { + ui_.portCheckBox->setChecked(true); + } + switch(param_.protocolType_) + { + case 0: + param_.isAutoLogin_ = ui_.telnetAutoLoginGroup->isChecked(); + break; + case 1: + case 2: + param_.isAutoLogin_ = ui_.sshAutoLoginGroup->isChecked(); + case 100: + break; + } + param_.sshUserName_ = ui_.sshuserLineEdit->text(); + param_.sshPassword_ = ui_.sshpasswdLineEdit->text(); + param_.maxIdleSeconds_ = ui_.idletimeLineEdit->text().toInt(); + param_.replyKeyCombination_ = ui_.replykeyLineEdit->text(); + if (param_.replyKeyCombination_.isNull()) { + FQ_TRACE("addrdialog", 0) << "Key combination for reply is NULL."; + } + param_.antiIdleMessage_ = ui_.antiLineEdit->text(); + param_.isAntiIdle_ = ui_.antiIdleGroupBox->isChecked(); + param_.isAutoReply_ = ui_.replyCheckBox->isChecked(); + param_.autoReplyMessage_ = ui_.replyLineEdit->text(); + param_.isAutoReconnect_ = ui_.reconnectCheckBox->isChecked(); + param_.reconnectInterval_ = ui_.reconnectLineEdit->text().toInt(); + param_.retryTimes_ = ui_.retryLineEdit->text().toInt(); + param_.isAutoCloseWin_ = ui_.autoCloseWinCheckBox->isChecked(); + param_.isAutoLoadScript_ = ui_.scriptCheckBox->isChecked(); + param_.enableZmodem_ = ui_.zmodemCheck->isChecked(); + param_.isBeep_ = ui_.beepCheck->isChecked(); + param_.isBuzz_ = ui_.buzzCheck->isChecked(); + param_.isSupportMouse_ = ui_.mouseCheck->isChecked(); + param_.autoLoadedScriptFileName_ = ui_.scriptLineEdit->text(); + param_.menuType_ = menuButtonGroup_.checkedId(); + param_.menuColor_ = ui_.menuLabel->palette().color(QPalette::Background); + param_.alignMode_ = ui_.alignComboBox->currentIndex(); + param_.charSpacing_ = ui_.charSpacingSpinBox->value(); + param_.lineSpacing_ = ui_.lineSpacingSpinBox->value(); +} + +void addrDialog::setUIFromParam() { + + updateSchemaList(param_.schemaFileName_); + QString strTmp; + ui_.nameLineEdit->setText(param_.name_); + ui_.addrLineEdit->setText(param_.hostAddress_); + ui_.hostTypeComboBox->setCurrentIndex(param_.hostType_); +// ui_.autoLoginCheckBox->setChecked(param_.isAutoLogin_); + ui_.preloginLineEdit->setText(param_.preLoginCommand_); + ui_.userLineEdit->setText(param_.userName_); + ui_.passwdLineEdit->setText(param_.password_); + ui_.postloginLineEdit->setText(param_.postLoginCommand_); + ui_.bbscodeComboBox->setCurrentIndex(param_.serverEncodingID_); + ui_.fontAdjustComboBox->setCurrentIndex(param_.isFontAutoFit_); + ui_.highlightCheckBox->setChecked(param_.isAlwaysHighlight_); + ui_.ansicolorCheckBox->setChecked(param_.isAnsiColor_); + ui_.termtypeLineEdit->setText(param_.virtualTermType_); + ui_.keytypeComboBox->setCurrentIndex(param_.keyboardType_); + ui_.backspace8->setChecked(param_.backspaceType_ == 0); + ui_.backspace127->setChecked(param_.backspaceType_ == 1); + strTmp.setNum(param_.numColumns_); + ui_.columnLineEdit->setText(strTmp); + strTmp.setNum(param_.numRows_); + ui_.rowLineEdit->setText(strTmp); + strTmp.setNum(param_.numScrollLines_); + ui_.scrollLineEdit->setText(strTmp); + ui_.cursorTypeComboBox->setCurrentIndex(param_.cursorType_); + ui_.escapeLineEdit->setText(param_.escapeString_); + ui_.proxytypeComboBox->setCurrentIndex(param_.proxyType_); + ui_.proxyaddrLineEdit->setText(param_.proxyHostName_); + strTmp.setNum(param_.proxyPort_); + ui_.proxyportLineEdit->setText(strTmp); + ui_.authentationGroup->setChecked(param_.isAuthentation_); + ui_.proxyuserLineEdit->setText(param_.proxyUserName_); + ui_.proxypasswdLineEdit->setText(param_.proxyPassword_); + ui_.protocolComboBox->setCurrentIndex(param_.protocolType_); + onProtocol(param_.protocolType_); + strTmp.setNum(param_.port_); + ui_.portLineEdit->setText(strTmp); + ui_.portCheckBox->setChecked(param_.port_ != ports[param_.protocolType_]); + ui_.sshuserLineEdit->setText(param_.sshUserName_); + ui_.sshpasswdLineEdit->setText(param_.sshPassword_); + strTmp.setNum(param_.maxIdleSeconds_); + ui_.idletimeLineEdit->setText(strTmp); + ui_.replykeyLineEdit->setText(param_.replyKeyCombination_); + ui_.antiLineEdit->setText(param_.antiIdleMessage_); + ui_.antiIdleGroupBox->setChecked(param_.isAntiIdle_); + ui_.replyCheckBox->setChecked(param_.isAutoReply_); + ui_.replyLineEdit->setEnabled(param_.isAutoReply_); + ui_.replyLineEdit->setText(param_.autoReplyMessage_); + ui_.reconnectCheckBox->setChecked(param_.isAutoReconnect_); + ui_.reconnectLineEdit->setEnabled(param_.isAutoReconnect_); + ui_.retryLineEdit->setEnabled(param_.isAutoReconnect_); + ui_.alignComboBox->setCurrentIndex(param_.alignMode_); + ui_.charSpacingSpinBox->setValue(param_.charSpacing_); + ui_.lineSpacingSpinBox->setValue(param_.lineSpacing_); + strTmp.setNum(param_.reconnectInterval_); + ui_.reconnectLineEdit->setText(strTmp); + strTmp.setNum(param_.retryTimes_); + ui_.retryLineEdit->setText(strTmp); + ui_.autoCloseWinCheckBox->setChecked(param_.isAutoCloseWin_); + ui_.scriptCheckBox->setChecked(param_.isAutoLoadScript_); + ui_.scriptLineEdit->setText(param_.autoLoadedScriptFileName_); + ui_.zmodemCheck->setChecked(param_.enableZmodem_); + ui_.beepCheck->setChecked(param_.isBeep_); + ui_.buzzCheck->setChecked(param_.isBuzz_); + ui_.mouseCheck->setChecked(param_.isSupportMouse_); + //ui.menuGroup->setButton(param_.m_nMenuType); + QRadioButton *rbMenu = qobject_cast < QRadioButton * > (menuButtonGroup_.button + (param_.menuType_)); + rbMenu->setChecked(true); + previewFont(); + previewMenu(); +} + + +/* + * Destroys the object and frees any allocated resources + */ +addrDialog::~addrDialog() { +} + + +void addrDialog::onOK() { + setParamFromUI(); + done(1); +} + +void addrDialog::onSave() { + setParamFromUI(); + done(2); +} +void addrDialog::onCancel() { + done(0); +} + + + +void addrDialog::onFgcolor() { + QColor color = QColorDialog::getColor(param_.foregroundColor_); + if (color.isValid() == TRUE) { + param_.foregroundColor_ = color; + previewFont(); + } +} + +void addrDialog::onBgcolor() { + QColor color = QColorDialog::getColor(param_.backgroundColor_); + if (color.isValid() == TRUE) { + param_.backgroundColor_ = color; + previewFont(); + } +} + + + +void addrDialog::onProtocol(int n) { + ui_.portCheckBox->setChecked(false); + ui_.portLineEdit->setText(QString("%1").arg(ports[n])); + switch(n) + { + case 0: //telnet + ui_.telnetAutoLoginGroup->setEnabled(true); + ui_.telnetAutoLoginGroup->setChecked(param_.isAutoLogin_); + ui_.sshAutoLoginGroup->setEnabled(false); + ui_.sshAutoLoginGroup->setChecked(false); + break; + case 1: +#if defined(_NO_SSH_COMPILED) + QMessageBox::warning(this, "sorry", + "SSH support is not compiled, check your OpenSSL and try to recompile FQTerm"); + ui_.protocolComboBox->setCurrentItem(0); +#else + ui_.telnetAutoLoginGroup->setEnabled(false); + ui_.telnetAutoLoginGroup->setChecked(false); + ui_.sshAutoLoginGroup->setEnabled(true); + ui_.sshAutoLoginGroup->setChecked(param_.isAutoLogin_); +#endif + break; + case 2: +#if defined(_NO_SSH_COMPILED) + QMessageBox::warning(this, "sorry", + "SSH support is not compiled, check your OpenSSL and try to recompile FQTerm"); + ui_.protocolComboBox->setCurrentItem(0); +#else + ui_.telnetAutoLoginGroup->setEnabled(false); + ui_.telnetAutoLoginGroup->setChecked(false); + ui_.sshAutoLoginGroup->setEnabled(true); + ui_.sshAutoLoginGroup->setChecked(param_.isAutoLogin_); +#endif + break; + } +} + +void addrDialog::onChooseScript() { + QString path = getPath(RESOURCE) + "script"; + + QString strFile = QFileDialog::getOpenFileName(this, "choose a script file", + path, "JavaScript/Python File (*.js *.py)"); + + if (strFile.isNull()) { + return ; + } + + ui_.scriptLineEdit->setText(strFile); +} + +void addrDialog::onMenuColor() { + QColor color = QColorDialog::getColor(param_.menuColor_); + if (color.isValid() == TRUE) { + param_.menuColor_ = color; + previewMenu(); + } +} + +void addrDialog::previewFont() { + //issue 98 preview both en and zh + + QPalette palette; + palette.setColor(QPalette::Window, param_.backgroundColor_); + palette.setColor(QPalette::WindowText, param_.foregroundColor_); + ui_.fontPreviewer->setPalette(palette); + QString sample("
AaBbCc"); + sample += QString("" + + param_.otherFontName_ + "
"); + ui_.fontPreviewer->setText(sample); +} + + +void addrDialog::connector() { + FQ_VERIFY(connect(ui_.applyPushButton, SIGNAL(clicked()), this, SLOT(onOK()))); + FQ_VERIFY(connect(ui_.savePushButton, SIGNAL(clicked()), this, SLOT(onSave()))); + FQ_VERIFY(connect(ui_.closePushButton, SIGNAL(clicked()), this, SLOT(onCancel()))); + + + FQ_VERIFY(connect(ui_.fgcolorPushButton, SIGNAL(clicked()), this, SLOT(onFgcolor()))); + FQ_VERIFY(connect(ui_.bgcolorPushButton, SIGNAL(clicked()), this, SLOT(onBgcolor()))); + + FQ_VERIFY(connect(ui_.protocolComboBox, SIGNAL(activated(int)), this, SLOT(onProtocol(int)))); + + FQ_VERIFY(connect(ui_.scriptPushButton, SIGNAL(clicked()), this, SLOT(onChooseScript()))); + + FQ_VERIFY(connect(ui_.menuColorButton, SIGNAL(clicked()), this, SLOT(onMenuColor()))); +} + +void addrDialog::previewMenu() { + QPalette palette; + palette.setColor(QPalette::Window, param_.menuColor_); + ui_.menuLabel->setPalette(palette); +} + +void addrDialog::onFont() { + bool isEnglish = ((QAction*)(sender()))->data().toBool(); + bool ok; + QString& fontName = isEnglish?param_.englishFontName_:param_.otherFontName_; + int& fontSize = isEnglish?param_.englishFontSize_:param_.otherFontSize_; + QFont now(fontName, fontSize); + + QFont font = QFontDialog::getFont(&ok, now, this, tr("Font Selector") +#ifdef __APPLE__ + , QFontDialog::DontUseNativeDialog +#endif + ); + if (ok == true) { + fontName = font.family(); + fontSize = font.pointSize(); + previewFont(); + } +} + +void addrDialog::updateSchemaList(const QString& currentSchema) { + ui_.schemaComboBox->clear(); + QFileInfoList lstFile = schemaDialog::getSchemaList(); + foreach(QFileInfo fi, lstFile) { + FQTermConfig *pConf = new FQTermConfig(fi.absoluteFilePath()); + ui_.schemaComboBox->addItem(pConf->getItemValue("schema", "title")); + delete pConf; + } + ui_.schemaComboBox->addItem(""); + int schemaIdx = lstFile.indexOf(currentSchema); + if (schemaIdx < 0) + schemaIdx = ui_.schemaComboBox->count() - 1; + ui_.schemaComboBox->setCurrentIndex(schemaIdx); +} + +} // namespace FQTerm + +#include "addrdialog.moc" diff --git a/src/ui/addrdialog.h b/src/ui/addrdialog.h new file mode 100644 index 0000000..8405a0a --- /dev/null +++ b/src/ui/addrdialog.h @@ -0,0 +1,87 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_ADDR_DIALOG_H +#define FQTERM_ADDR_DIALOG_H + +#include + +#include "fqterm_param.h" +#include "ui_addrdialog.h" + +namespace FQTerm { + +class FQTermConfig; + +class addrDialog: public QDialog { + Q_OBJECT; + public: + enum BUTTONS{SAVE = 0x01, APPLY = 0x02}; + addrDialog(QWidget *parent_ = 0, const FQTermParam& param = FQTermParam(), int buttons = SAVE | APPLY, Qt::WFlags fl = 0); + ~addrDialog(); + void setParam(const FQTermParam& param) { + param_ = param; + } + FQTermParam param() { + return param_; + } + + enum Tabs{General, Display, Terminal, Keyboard, Proxy, Misc, Mouse}; + void setCurrentTabIndex(Tabs tab) { + ui_.tabWidget->setCurrentIndex(tab); + } + + static const int ports[3]; // telnet, ssh1, ssh2 + + protected slots: + void onOK(); + void onSave(); + void onCancel(); + void onFgcolor(); + void onBgcolor(); + void onProtocol(int); + void onChooseScript(); + void onMenuColor(); + void onFont(); + + protected: + void connector(); + bool isChanged(); + void previewFont(); + void previewMenu(); + void setUIFromParam(); + void setParamFromUI(); + + QButtonGroup menuButtonGroup_; + + private: + + FQTermParam param_; + Ui::addrDialog ui_; + + void updateSchemaList(const QString& currentFile); +}; + + + + +} // namespace FQTerm + +#endif // FQTERM_ADDR_DIALOG_H diff --git a/src/ui/addrdialog.ui b/src/ui/addrdialog.ui new file mode 100644 index 0000000..e5dc40b --- /dev/null +++ b/src/ui/addrdialog.ui @@ -0,0 +1,1211 @@ + + + addrDialog + + + + 0 + 0 + 493 + 383 + + + + Site Setting + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Apply (&Temporarily) + + + + + + + &Cancel + + + + + + true + + + + + + + &Apply (Save) + + + + + + + 0 + + + + General + + + + + + + + Name + + + Qt::AlignVCenter + + + + + + + + + + Address + + + Qt::AlignVCenter + + + + + + + + + + Protocol + + + + + + + + Telnet + + + + + SSH1 + + + + + SSH2 + + + + + + + + false + + + + + + + Type + + + + + + + + BBS + + + + + *NIX + + + + + + + + Telnet Auto Login + + + true + + + false + + + + + + Prelogin + + + + + + + + + + User + + + Qt::AlignVCenter + + + + + + + + + + Password + + + Qt::AlignVCenter + + + + + + + QLineEdit::Password + + + + + + + Postlogin + + + + + + + + + + + + + Port + + + + + + + SSH Auto Login + + + true + + + false + + + + + + User + + + + + + + + + + Password + + + + + + + QLineEdit::Password + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Display + + + + + + BBS Encoding + + + + + + + + GBK + + + + + BIG5 + + + + + UTF8 + + + + + BIG5-HKSCS + + + + + BIG5-UAO + + + + + + + + Always Hightlight + + + + + + + true + + + TextLabel3 + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + Align Mode + + + + + + + + + + Line Spacing + + + + + + + + + + Char Spacing + + + + + + + ANSI Color + + + + + + + + Align Mid + + + + + Align Bottom + + + + + Align Top + + + + + + + + + + + Background + + + + + + + Text Color + + + + + + + + 0 + 0 + + + + Font + + + QToolButton::InstantPopup + + + Qt::ToolButtonTextOnly + + + Qt::DownArrow + + + + + + + 1 + + + + Keep Font; Adjust Row/Column. + + + + + Keep Row/Column; Adjust Font. + + + + + Keep Font; Keep Row/Column. + + + + + + + + + Terminal + + + + + + Term Type + + + + + + + + + + Key Type + + + + + + + + VT100 + + + + + XTERM + + + + + BBS + + + + + + + + Columns + + + + + + + + + + Scroll Lines + + + + + + + + + + Rows + + + + + + + + + + Cursor Type + + + + + + + + Block + + + + + Underline + + + + + I Type + + + + + + + + Escape string (i.e. *[ ) + + + + + + + + + + + Keyboard + + + + + + BackSpace Setting + + + + + + Send backspace as ^H + + + + + + + Send backspace as ^? (127) + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Proxy + + + + + + Type + + + + + + + + None + + + + + Wingate + + + + + SOCKS4 + + + + + SOCKS5 + + + + + HTTP + + + + + + + + Address + + + + + + + + + + Port + + + + + + + + + + Authentation + + + true + + + false + + + + + + User + + + + + + + + + + Password + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Misc + + + + + + Anti-idle + + + true + + + + + + + + + Max Idle Time + + + + + + + + + + s + + + + + + + Anti-idle String + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Key to reply message + + + + + + + + + + Autoreply Message + + + + + + + false + + + + + + + When disconnected, reconnect every + + + + + + + false + + + + + + + s + + + + + + + For Maximum + + + + + + + false + + + + + + + Times (-1 means infinite) + + + + + + + Load Control Script + + + + + + + false + + + + + + + false + + + Browse... + + + + + + + Enable Zmodem + + + + + + + Enable Buzz + + + + + + + Enable Beep + + + + + + + When disconnected, close window automatically + + + + + + + + Mouse + + + + + + Menu Type + + + + + + Underline + + + + + + + Reverse + + + + + + + Custom Color + + + + + + + true + + + Menu Color + + + Qt::AlignCenter + + + + + + + Color... + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Enable Mouse Support + + + + + + + + + + + + tabWidget + nameLineEdit + addrLineEdit + portLineEdit + hostTypeComboBox + preloginLineEdit + userLineEdit + passwdLineEdit + postloginLineEdit + bbscodeComboBox + highlightCheckBox + termtypeLineEdit + keytypeComboBox + columnLineEdit + scrollLineEdit + rowLineEdit + cursorTypeComboBox + escapeLineEdit + idletimeLineEdit + replykeyLineEdit + replyCheckBox + replyLineEdit + reconnectCheckBox + reconnectLineEdit + retryLineEdit + autoCloseWinCheckBox + scriptCheckBox + scriptLineEdit + scriptPushButton + radioButton1 + radioButton2 + radioButton3 + menuColorButton + applyPushButton + closePushButton + + + + + radioButton2 + toggled(bool) + menuColorButton + setDisabled(bool) + + + 260 + 79 + + + 392 + 110 + + + + + radioButton1 + toggled(bool) + menuColorButton + setDisabled(bool) + + + 53 + 79 + + + 392 + 110 + + + + + radioButton3 + toggled(bool) + menuColorButton + setEnabled(bool) + + + 392 + 79 + + + 392 + 110 + + + + + replyCheckBox + toggled(bool) + replyLineEdit + setEnabled(bool) + + + 23 + 158 + + + 168 + 156 + + + + + reconnectCheckBox + toggled(bool) + reconnectLineEdit + setEnabled(bool) + + + 23 + 184 + + + 295 + 182 + + + + + reconnectCheckBox + toggled(bool) + retryLineEdit + setEnabled(bool) + + + 23 + 184 + + + 147 + 213 + + + + + scriptCheckBox + toggled(bool) + scriptLineEdit + setEnabled(bool) + + + 26 + 236 + + + 26 + 261 + + + + + scriptCheckBox + toggled(bool) + scriptPushButton + setEnabled(bool) + + + 26 + 236 + + + 289 + 260 + + + + + portCheckBox + toggled(bool) + portLineEdit + setEnabled(bool) + + + 187 + 108 + + + 209 + 108 + + + + + antiIdleGroupBox + toggled(bool) + antiLineEdit + setEnabled(bool) + + + 89 + 42 + + + 145 + 67 + + + + + antiIdleGroupBox + toggled(bool) + idletimeLineEdit + setEnabled(bool) + + + 114 + 40 + + + 270 + 110 + + + + + beepCheck + toggled(bool) + buzzCheck + setEnabled(bool) + + + 223 + 301 + + + 298 + 299 + + + + + diff --git a/src/ui/articledialog.cpp b/src/ui/articledialog.cpp new file mode 100644 index 0000000..43ba617 --- /dev/null +++ b/src/ui/articledialog.cpp @@ -0,0 +1,105 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "articledialog.h" +#include +#include +#include "fqterm_trace.h" +#include "fqterm_path.h" +#include "fqterm_config.h" +#include "fqterm_filedialog.h" + +/* + * Constructs a articleDialog as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ + +namespace FQTerm { + +articleDialog::articleDialog(FQTermConfig *config, QWidget *parent, Qt::WFlags fl) + : QDialog(parent, fl) { + ui_.setupUi(this); + connectSlots(); + + config_ = config; +} + +/* + * Destroys the object and frees any allocated resources + */ +articleDialog::~articleDialog() { + // no need to delete child widgets, Qt does it all for us +} + + +void articleDialog::connectSlots() { + FQ_VERIFY(connect(ui_.selectButton, SIGNAL(clicked()), this, SLOT(onSelect()))); + FQ_VERIFY(connect(ui_.copyButton, SIGNAL(clicked()), this, SLOT(onCopy()))); + FQ_VERIFY(connect(ui_.saveButton, SIGNAL(clicked()), this, SLOT(onSave()))); + FQ_VERIFY(connect(ui_.closeButton, SIGNAL(clicked()), this, SLOT(onClose()))); +} + +void articleDialog::onSelect() { + ui_.textBrowser->selectAll(); +} + +void articleDialog::onCopy() { + ui_.textBrowser->copy(); + // QString strText = textBrowser->selectedText(); + // + // QClipboard *clipboard = QApplication::clipboard(); + // + // #if (QT_VERSION>=0x030100) + // clipboard->setText(strText, QClipboard::Selection ); + // clipboard->setText(strText, QClipboard::Clipboard ); + // #else + // clipboard->setText(strText); + // #endif +} + +void articleDialog::onSave() { + + QString filename; + FQTermFileDialog fileDialog(config_); + filename = fileDialog.getSaveName(NULL, ""); + + if (!filename.isNull()) { + QFile f(filename); + if ((f.open(QIODevice::WriteOnly))) { + f.write(articleText_.toLocal8Bit()); + f.close(); + } else { + QMessageBox mb("Access file error:", filename, QMessageBox::Warning, 0, 0, 0, + this, 0); + mb.exec(); + } + } +} + +void articleDialog::onClose() { + done(0); +} + +} // namespace FQTerm + +#include "articledialog.moc" diff --git a/src/ui/articledialog.h b/src/ui/articledialog.h new file mode 100644 index 0000000..0e40cbf --- /dev/null +++ b/src/ui/articledialog.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_ARTICLEDIALOG_H +#define FQTERM_ARTICLEDIALOG_H + +#include "ui_articledialog.h" + +namespace FQTerm { + +class FQTermConfig; +class FQTermFileDialog; + +class articleDialog: public QDialog { + Q_OBJECT; +public: + articleDialog(FQTermConfig *, QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~articleDialog(); + + QString articleText_; + Ui::articleDialog ui_; +protected: + void connectSlots(); +protected slots: + void onClose(); + void onSave(); + void onSelect(); + void onCopy(); +private: + FQTermConfig * config_; +}; + +} // name space FQTerm + +#endif // FQTERM_ARTICLEDIALOG_H diff --git a/src/ui/articledialog.ui b/src/ui/articledialog.ui new file mode 100644 index 0000000..436671f --- /dev/null +++ b/src/ui/articledialog.ui @@ -0,0 +1,132 @@ + + articleDialog + + + + 0 + 0 + 542 + 487 + + + + Article Viewer + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 50 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 410 + 20 + + + + + + + + Close + + + + + + + Select All + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 60 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 60 + 20 + + + + + + + + Save... + + + + + + + Copy + + + + + + + + + diff --git a/src/ui/defineescape.cpp b/src/ui/defineescape.cpp new file mode 100644 index 0000000..e9dd655 --- /dev/null +++ b/src/ui/defineescape.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#include "defineescape.h" +#include "fqterm.h" + +namespace FQTerm { + +DefineEscapeDialog::~DefineEscapeDialog() +{ +} + +DefineEscapeDialog::DefineEscapeDialog(QString& strEsc, QWidget *parent_ /*= 0*/, Qt::WFlags fl /*= 0*/) +: QDialog(parent_, fl), strEsc_(strEsc) +{ + ui_.setupUi(this); + ui_.edtEscape->setText(strEsc_); + FQ_VERIFY(connect(ui_.btnOK, SIGNAL(clicked()), this, SLOT(onOK()))); + FQ_VERIFY(connect(ui_.btnCancel, SIGNAL(clicked()), this, SLOT(onCancel()))); +} + +void DefineEscapeDialog::onOK() +{ + strEsc_ = ui_.edtEscape->text(); + done(1); +} + +void DefineEscapeDialog::onCancel() +{ + done(0); +} +} //namespace FQTerm + +#include "defineescape.moc" diff --git a/src/ui/defineescape.h b/src/ui/defineescape.h new file mode 100644 index 0000000..0083603 --- /dev/null +++ b/src/ui/defineescape.h @@ -0,0 +1,44 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#ifndef __FQTERM_DEFINEESCAPE__ +#define __FQTERM_DEFINEESCAPE__ + +#include +#include "ui_defineescape.h" +namespace FQTerm { + +class DefineEscapeDialog : public QDialog { + Q_OBJECT; +public: + DefineEscapeDialog(QString& strEsc, QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~DefineEscapeDialog(); + +protected slots: + void onOK(); + void onCancel(); +private: + QString& strEsc_; + Ui::dlgDefineEscape ui_; +}; + +} //namespace FQTerm + +#endif //__FQTERM_DEFINEESCAPE__ \ No newline at end of file diff --git a/src/ui/defineescape.ui b/src/ui/defineescape.ui new file mode 100644 index 0000000..6549610 --- /dev/null +++ b/src/ui/defineescape.ui @@ -0,0 +1,68 @@ + + + dlgDefineEscape + + + + 0 + 0 + 213 + 121 + + + + Define Escape + + + + + 20 + 10 + 81 + 16 + + + + Escape String *[ + + + + + + 20 + 40 + 171 + 20 + + + + + + + 20 + 76 + 171 + 31 + + + + + + + OK + + + + + + + Cancel + + + + + + + + + diff --git a/src/ui/fqterm_canvas.cpp b/src/ui/fqterm_canvas.cpp new file mode 100644 index 0000000..f17ee58 --- /dev/null +++ b/src/ui/fqterm_canvas.cpp @@ -0,0 +1,537 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fqterm_canvas.h" +#include "fqterm.h" +#include "fqterm_config.h" +#include "fqterm_path.h" +#include "fqterm_filedialog.h" + +namespace FQTerm { + +FQTermCanvas::FQTermCanvas(FQTermConfig * config, QWidget *parent, Qt::WFlags f) + : QScrollArea(parent), + adjustMode_(Fit), + aspectRatioMode_(Qt::KeepAspectRatio){ + // TODO: dirty trick + + if (f == 0) { + isEmbedded = true; + } else { + isEmbedded = false; + } + + config_ = config; + + menu_ = new QMenu(parent); + menu_->addAction(tr("zoom 1:1"), this, SLOT(oriSize()), tr("Ctrl+Z")); + menu_->addAction(tr("adjust size"), this, SLOT(autoAdjust()), tr("Ctrl+X")); + menu_->addSeparator(); + QAction* zoomInAction = menu_->addAction(tr("zoom in"), this, + SLOT(zoomIn()), tr("Ctrl+=")); + QAction* zoomOutAction = menu_->addAction(tr("zoom out"), this, + SLOT(zoomOut()), tr("Ctrl+-")); + if (!isEmbedded) { + menu_->addAction(tr("fullscreen"), this, SLOT(fullScreen()), tr("Ctrl+F")); + } + menu_->addSeparator(); + menu_->addAction(tr("rotate CW 90"), this, SLOT(cwRotate()), + tr("Ctrl+]")); + menu_->addAction(tr("rotate CCW 90"), this, SLOT(ccwRotate()), + tr("Ctrl+[")); + menu_->addSeparator(); + gifPlayAction_ = menu_->addAction(tr("play gif"), this, + SLOT(playGIF()), tr("Ctrl+/")); + menu_->addSeparator(); + menu_->addAction(tr("save as"), this, SLOT(saveImage()), tr("Ctrl+S")); + menu_->addAction(tr("copy to"), this, SLOT(copyImage()), tr("Ctrl+C")); + menu_->addAction(tr("silent copy"), this, SLOT(silentCopy()), + tr("Shift+S")); + + if (!isEmbedded) { + menu_->addAction(tr("delete"), this, SLOT(deleteImage()), tr("Ctrl+D")); + + menu_->addSeparator(); + menu_->addAction(tr("exit"), this, SLOT(close()), tr("Ctrl+Q")); + } + + toolBar_ = new QToolBar(this); + + toolBar_->addAction(QIcon(getPath(RESOURCE) + "pic/ViewerButtons/open.png"), + tr("Open Dir"), this, SLOT(openDir())); + + zoomInAction->setIcon( + QIcon(getPath(RESOURCE) + "pic/ViewerButtons/zoomin.png")); + zoomOutAction->setIcon( + QIcon(getPath(RESOURCE) + "pic/ViewerButtons/zoomout.png")); + + toolBar_->addAction(zoomInAction); + toolBar_->addAction(zoomOutAction); + + QActionGroup* gifGroup = new QActionGroup(this); + gifPlayAction_->setIcon( + QIcon(getPath(RESOURCE) + "pic/ViewerButtons/play_gif.png")); + toolBar_->addAction(gifPlayAction_); + + QActionGroup* showSettingGroup = new QActionGroup(this); + QMenu* showSettingMenu = new QMenu(this); + + QAction* showSettingFitAction = + showSettingMenu->addAction(tr("show Fit"), this, SLOT(SetAdjustMode())); + showSettingFitAction->setCheckable(true); + showSettingFitAction->setData(Fit); + showSettingGroup->addAction(showSettingFitAction); + + QAction* showSettingMaxFitAction = + showSettingMenu->addAction(tr("show MaxFit"), + this, SLOT(SetAdjustMode())); + showSettingMaxFitAction->setCheckable(true); + showSettingMaxFitAction->setData(MaxFit); + showSettingGroup->addAction(showSettingMaxFitAction); + + QAction* showSettingOriginAction = + showSettingMenu->addAction(tr("show Origin"), + this, SLOT(SetAdjustMode())); + showSettingOriginAction->setCheckable(true); + showSettingOriginAction->setData(Origin); + showSettingGroup->addAction(showSettingOriginAction); + + QAction* showSettingStrechAction = + showSettingMenu->addAction(tr("show Stretch"), + this, SLOT(SetAdjustMode())); + showSettingStrechAction->setCheckable(true); + showSettingStrechAction->setData(Stretch); + showSettingGroup->addAction(showSettingStrechAction); + + QToolButton* showSettingButton = new QToolButton(this); + QAction* dummyAction = new QAction( + QIcon(getPath(RESOURCE) + "pic/ViewerButtons/adjustsize.png"), + tr("Adjust Mode"), showSettingButton); + showSettingButton->setDefaultAction(dummyAction); + showSettingButton->setMenu(showSettingMenu); + showSettingButton->setPopupMode(QToolButton::InstantPopup); + + showSettingFitAction->setChecked(true); + + toolBar_->addWidget(showSettingButton); + + + +#if QT_VERSION >= 0x040200 + setAlignment(Qt::AlignCenter); +#endif + label_ = new QLabel(viewport()); + label_->setScaledContents(true); + label_->setAlignment(Qt::AlignCenter); + label_->setText(tr("No Preview Available")); + setWidget(label_); + // resize(200, 100); +} + +FQTermCanvas::~FQTermCanvas() { + //delete label; + //delete m_pMenu; +} + +void FQTermCanvas::oriSize() { + useAdjustMode_ = false; + imageSize_ = image_.size(); + adjustSize(size()); +} + +void FQTermCanvas::zoomIn() { + useAdjustMode_ = false; + resizeImage(0.05f); +} + +void FQTermCanvas::zoomOut() { + useAdjustMode_ = false; + resizeImage(-0.05f); +} + +void FQTermCanvas::autoAdjust() { + useAdjustMode_ = true; + adjustSize(size()); +} + +void FQTermCanvas::cwRotate() { + rotateImage(90); +} + +void FQTermCanvas::ccwRotate() { + rotateImage(-90); +} + +void FQTermCanvas::fullScreen() { + if (!isFullScreen()) { + showFullScreen(); + } else { + showNormal(); + } +} + +void FQTermCanvas::loadImage(const QString& name, bool performAdjust) { + if (label_->movie()) { + label_->movie()->stop(); + label_->setMovie(NULL); + } + + gifPlayAction_->setEnabled(name.endsWith("gif")); + + + bool res = image_.load(name); + if (!res) { + QList formats = QImageReader::supportedImageFormats(); + for (QList::iterator it = formats.begin(); + !res && it != formats.end(); + ++it) { + res = image_.load(name, it->data()); + } + } + if (!image_.isNull()) { + fileName_ = QFileInfo(name).absoluteFilePath(); + setWindowTitle(QFileInfo(name).fileName()); + + useAdjustMode_ = true; + + if (!isEmbedded) { + QSize szView(image_.size()); + szView.scale(640, 480, aspectRatioMode_); + + if (szView.width() < image_.width()) { + imageSize_ = szView; + label_->resize(imageSize_); + label_->clear(); + label_->setAlignment(Qt::AlignCenter); + label_->setPixmap(scaleImage(imageSize_)); + + if (!isEmbedded) { + resize(szView *1.1); + } + } else { + imageSize_ = image_.size(); + label_->resize(imageSize_); + label_->setPixmap(QPixmap::fromImage(image_)); + if (!isEmbedded) { + resize(imageSize_ + QSize(5, 5)); + } + } + } + if (isEmbedded) { + label_->hide(); + if (performAdjust) autoAdjust(); + else label_->setPixmap(QPixmap::fromImage(image_)); + + label_->show(); + } + + } else { + FQ_TRACE("canvas", 1) << "Can't load the image: " << name; + } +} + +void FQTermCanvas::playGIF() { + if (fileName_.endsWith("gif")) { + gifPlayer_.setFileName(fileName_); + if (gifPlayer_.isValid()) { + label_->setMovie(&gifPlayer_); + gifPlayer_.stop(); + gifPlayer_.start(); + return; + } + } +} + +void FQTermCanvas::resizeImage(float ratio) { + QSize szImg = imageSize_; + szImg *= (1+ratio); + //we dont need so big + if (szImg.width() > 10000 || szImg.height() > 10000 || + szImg.width() < 1 || szImg.height() < 1) { + return ; + } + imageSize_ = szImg; + + if (!isFullScreen() && !isEmbedded) { + resize(imageSize_ *1.1); + } else { + adjustSize(size()); + } +} + +void FQTermCanvas::rotateImage(float ang) { + QMatrix wm; + + wm.rotate(ang); + + image_ = image_.transformed(wm, Qt::SmoothTransformation); + + imageSize_ = image_.size(); + + adjustSize(size()); +} + +void FQTermCanvas::copyImage() { + QFileInfo fi(fileName_); +// QString strSave = +// QFileDialog::getSaveFileName( +// this,tr("Choose a filename to save under"), +// QDir::currentPath() + fi.fileName()); + FQTermFileDialog fileDialog(config_); + QString strSave = fileDialog.getSaveName(fi.fileName(), ""); + if (strSave.isEmpty()) { + return ; + } + QFile file(fileName_); + if (file.open(QIODevice::ReadOnly)) { + QFile save(strSave); + if (save.open(QIODevice::WriteOnly)) { + QByteArray ba = file.readAll(); + QDataStream ds(&save); + ds.writeRawData(ba, ba.size()); + save.close(); + } + file.close(); + } +} + +void FQTermCanvas::silentCopy() { + // save it to $savefiledialog + QString strPath = config_->getItemValue("global", "savefiledialog"); + + QFileInfo fi(fileName_); + QString strSave = strPath + "/" + fi.fileName(); + + fi.setFile(strSave); + + // add (%d) if exist + int i = 1; + while (fi.exists()) { + strSave = QString("%1/%2(%3).%4").arg(fi.dir().path()).arg + (fi.completeBaseName()).arg(i).arg(fi.suffix()); + fi.setFile(strSave); + } + + // copy it + QFile file(fileName_); + if (file.open(QIODevice::ReadOnly)) { + QFile save(strSave); + if (save.open(QIODevice::WriteOnly)) { + QByteArray ba = file.readAll(); + QDataStream ds(&save); + ds.writeRawData(ba, ba.size()); + save.close(); + } + file.close(); + } +} + +QPixmap FQTermCanvas::scaleImage(const QSize &sz) { + return QPixmap::fromImage( + image_.scaled(sz, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); +} + +void FQTermCanvas::moveImage(float dx, float dy) { + scrollContentsBy(int(widget()->width()*dx), int(widget()->height() *dy)); +} + +void FQTermCanvas::saveImage() { + + QFileInfo fi(fileName_); + FQTermFileDialog fileDialog(config_); + QString strSave = fileDialog.getSaveName(fi.fileName(), ""); + if (strSave.isEmpty()) { + return ; + } + QString fmt = fi.suffix().toUpper(); + if (!image_.save(strSave, fmt.toLatin1())) { + QMessageBox::warning(this, tr("Failed to save file"), + tr("Cant save file, maybe format not supported")); + } +} + +void FQTermCanvas::deleteImage() { + QFile::remove(fileName_); + close(); +} + +void FQTermCanvas::closeEvent(QCloseEvent *ce) { + if (!isEmbedded) { + delete this; + } +} + +void FQTermCanvas::viewportResizeEvent(QResizeEvent *re) { + adjustSize(re->size()); +} + +void FQTermCanvas::mousePressEvent(QMouseEvent *me) { + /* remove this to avoid click by mistake + if(me->button()&LeftButton) + { + close(); + return; + } + */ + if (me->button() &Qt::RightButton) { + menu_->popup(me->globalPos()); + } +} + +void FQTermCanvas::keyPressEvent(QKeyEvent *ke) { + switch (ke->key()) { + case Qt::Key_Escape: + if (!isEmbedded) { + if (isFullScreen()) { + showNormal(); + } else { + close(); + } + } + + break; + case Qt::Key_D: + if (!isEmbedded){ + deleteImage(); + } + break; + case Qt::Key_Q: + if (!isEmbedded){ + close(); + } + break; + } +} + +void FQTermCanvas::adjustSize(QSize szView) { + szView -= QSize(2 * frameWidth(), 2 * frameWidth()); + if (label_->pixmap() == NULL && image_.isNull()) { + label_->resize(szView); + return ; + } + + QSize szImg = imageSize_; + + if (useAdjustMode_) { + szImg = image_.size(); + switch(adjustMode_) + { + case MaxFit: + szImg.scale(szView, aspectRatioMode_); + break; + case Fit: + if (szImg.width() > szView.width() || szImg.height() > szView.height() || + szImg.width() < image_.width()) { + szImg.scale(szView, aspectRatioMode_); + } + szImg = szImg.boundedTo(image_.size()); + if (szImg.width() < 1 || szImg.height() < 1) { + return; + } + break; + case Origin: + break; + case Stretch: + szImg = szView; + break; + } + } + + imageSize_ = szImg; + label_->resize(imageSize_); + label_->setPixmap(scaleImage(imageSize_)); +} + +void FQTermCanvas::resizeEvent(QResizeEvent * event) { + if (useAdjustMode_){ + autoAdjust(); + } + else adjustSize(size()); + QScrollArea::resizeEvent(event); +} + +QMenu* FQTermCanvas::menu() { + return menu_; +} + + +QToolBar* FQTermCanvas::ToolBar() { + return toolBar_; +} + +void FQTermCanvas::SetAdjustMode(AdjustMode am) { + adjustMode_ = am; + if (adjustMode_ == Stretch) { + aspectRatioMode_ = Qt::IgnoreAspectRatio; + } + else { + aspectRatioMode_ = Qt::KeepAspectRatio; + } + autoAdjust(); +} + +void FQTermCanvas::SetAdjustMode() { + SetAdjustMode(AdjustMode((((QAction*)sender())->data()).toInt())); +} + +void FQTermCanvas::openDir() { + QString poolPath = config_->getItemValue("preference", "pool"); + if (poolPath.isEmpty()) { + poolPath = getPath(USER_CONFIG) + "pool/"; + } +#ifdef WIN32 + QString path = "file:///" + poolPath; +#else + QString path = "file://" + poolPath; +#endif + QDesktopServices::openUrl(path); +} + +void FQTermCanvas::updateImage(const QString& filename) +{ + if (QFileInfo(filename).absoluteFilePath().toLower() == fileName_) { + loadImage(fileName_); + } + +} + + +} // namespace FQTerm + +#include "fqterm_canvas.moc" diff --git a/src/ui/fqterm_canvas.h b/src/ui/fqterm_canvas.h new file mode 100644 index 0000000..be15879 --- /dev/null +++ b/src/ui/fqterm_canvas.h @@ -0,0 +1,105 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_CANVAS_H +#define FQTERM_CANVAS_H + +#include +#include +#include + +class QAction; +class QLabel; +class QMenu; +class QCloseEvent; +class QMouseEvent; +class QKeyEvent; +class QResizeEvent; +class QToolBar; +class QImage; + +namespace FQTerm { + +class FQTermConfig; +class ExifExtractor; +class FQTermFileDialog; + +class FQTermCanvas: public QScrollArea { + Q_OBJECT; + public: + FQTermCanvas(FQTermConfig *, QWidget *parent_ = NULL, Qt::WFlags f = Qt::Window); + ~FQTermCanvas(); + + enum AdjustMode{Origin, Fit, Stretch, MaxFit}; + + void updateImage(const QString& filename); + void loadImage(const QString&, bool = true); + QMenu* menu(); + QToolBar* ToolBar(); + public slots: + void oriSize(); + void zoomIn(); + void zoomOut(); + void autoAdjust(); + void fullScreen(); + void saveImage(); + void copyImage(); + void silentCopy(); + void cwRotate(); + void ccwRotate(); + void deleteImage(); + void SetAdjustMode(AdjustMode am); + void openDir(); + void playGIF(); + protected slots: + void SetAdjustMode(); + protected: + void resizeEvent (QResizeEvent * event); + void moveImage(float, float); + void resizeImage(float); + void rotateImage(float); + + void closeEvent(QCloseEvent*); + void mousePressEvent(QMouseEvent*); + void keyPressEvent(QKeyEvent *ke); + void viewportResizeEvent(QResizeEvent *re); + void adjustSize(QSize); + QPixmap scaleImage(const QSize &); + protected: + QLabel *label_; + bool useAdjustMode_; + QSize imageSize_; + QString fileName_; + QImage image_; + QMovie gifPlayer_; + QMenu *menu_; + QToolBar *toolBar_; + FQTermConfig * config_; + QAction* gifPlayAction_; + + AdjustMode adjustMode_; + Qt::AspectRatioMode aspectRatioMode_; + // TODO: Very dirty trick, I hate it + bool isEmbedded; +}; + +} // namespace FQTerm + +#endif // FQTERM_CANVAS_H diff --git a/src/ui/fqterm_time_label.cpp b/src/ui/fqterm_time_label.cpp new file mode 100644 index 0000000..1d05b0e --- /dev/null +++ b/src/ui/fqterm_time_label.cpp @@ -0,0 +1,50 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_time_label.h" + +#include +#include +#include + +namespace FQTerm { + +//constructor +FQTermTimeLabel::FQTermTimeLabel(QWidget *parent, const char *name, Qt::WFlags f) + : QLabel(parent, f) { + setAlignment(Qt::AlignHCenter); + currentTime_ = new QTime(); + currentTime_->start(); + startTimer(1000); +} + +//destructor +FQTermTimeLabel::~FQTermTimeLabel() { + delete currentTime_; +} + +//timer to display the current time +void FQTermTimeLabel::timerEvent(QTimerEvent*) { + setText(currentTime_->currentTime().toString()); +} + +} // namespace FQTerm + +#include "fqterm_time_label.moc" diff --git a/src/ui/fqterm_time_label.h b/src/ui/fqterm_time_label.h new file mode 100644 index 0000000..ac510b6 --- /dev/null +++ b/src/ui/fqterm_time_label.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_TIME_LABEL_H +#define FQTERM_TIME_LABEL_H + +#include +#include + +class QTime; + +namespace FQTerm { + +class FQTermTimeLabel: public QLabel { + Q_OBJECT; + public: + FQTermTimeLabel(QWidget *parent, const char *name = 0, Qt::WFlags f = 0); + ~FQTermTimeLabel(); + + protected: + QTime *currentTime_; + void timerEvent(QTimerEvent*); +}; + +} // namespace FQTerm + +#endif // FQTERM_TIME_LABEL_H diff --git a/src/ui/fqterm_tool_button.cpp b/src/ui/fqterm_tool_button.cpp new file mode 100644 index 0000000..4680e6f --- /dev/null +++ b/src/ui/fqterm_tool_button.cpp @@ -0,0 +1,41 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_tool_button.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +FQTermToolButton::FQTermToolButton(QWidget *parent_, int id, QString name) + : QToolButton(parent_) { + setObjectName(name); + this->id_ = id; + FQ_VERIFY(connect(this, SIGNAL(clicked()), this, SLOT(slotClicked()))); +} + +FQTermToolButton::~FQTermToolButton(){} + +void FQTermToolButton::slotClicked() { + emit(buttonClicked(id_)); +} + +} // namespace FQTerm + +#include "fqterm_tool_button.moc" diff --git a/src/ui/fqterm_tool_button.h b/src/ui/fqterm_tool_button.h new file mode 100644 index 0000000..56f5626 --- /dev/null +++ b/src/ui/fqterm_tool_button.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_TOOL_BUTTON_H +#define FQTERM_TOOL_BUTTON_H + +#include + +namespace FQTerm { + +class FQTermToolButton: public QToolButton { + Q_OBJECT; + public: + FQTermToolButton(QWidget *parent_, int id, QString name = ""); + ~FQTermToolButton(); + + signals: + void buttonClicked(int); + + protected slots: + void slotClicked(); + + protected: + int id_; +}; + +} // namespace FQTerm + +#endif // FQTERM_TOOL_BUTTON_H diff --git a/src/ui/imageviewer.cpp b/src/ui/imageviewer.cpp new file mode 100644 index 0000000..296c5a8 --- /dev/null +++ b/src/ui/imageviewer.cpp @@ -0,0 +1,1749 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fqterm_canvas.h" +#include "fqterm_config.h" +#include "fqterm_exif_extractor.h" +#include "fqterm_filedialog.h" +#include "fqterm_path.h" +#include "fqterm_trace.h" +#include "imageviewer.h" + + +namespace FQTerm { + + typedef enum { + V_UNKNOWN = -1, + V_ORIGINAL = 0, + V_SHADOW, + V_BESTFIT, + V_ZOOMIN, + V_ZOOMOUT, + V_ROTLEFT, + V_ROTRIGHT, + V_FULLSCREEN + } slideViewModes; + + typedef enum { + SORT_UNSORTED = -1, + SORT_LIKE, + SORT_NEW, + SORT_TRASH, + SORT_RECOVER, + SORT_TITLE + } slideSortFlags; + + + typedef enum { + STAT_UNKNOWN = -1, + STAT_LIKE, + STAT_NEW, + STAT_TRASH, + STAT_RECOVER, + STAT_TITLE, + STAT_ALL + } slideStatus; + + typedef enum { + GEN_UNKNOWN = -1, + GEN_CANCEL, + GEN_NOCHANGE, + GEN_RESHUFFLE, + GEN_NOTAG, + GEN_INTRASH, + GEN_INTRASHES, + GEN_TOSAVE, + GEN_TOSAVES, + GEN_TRASH, + GEN_TRASHES, + GEN_NOTRASH, + GEN_RECOVER, + GEN_RECOVERS, + GEN_NORECOVER, + GEN_SAVE, + GEN_SAVES, + GEN_DELETE, + GEN_DELETES, + GEN_SEARCHWRAP, + GEN_SEARCHNOMATCH + } generalStatus; + + static const char *fqloraTagStatus[] = { + "Like", + "New", + "Trash", + "Recover", + "Title" + }; + + static const char *fqloraGeneralStatus[] = { + "Canceled.", + "No changes for ", + "Reshuffled by ", + "No tags by ", + "item in the trash.", + "items in the trash.", + "item to save.", + "items to save.", + "image trashed.", + "images trashed.", + "Nothing to trash.", + "image recovered.", + "images recovered.", + "Nothing to recover.", + "image saved in ", + "images saved in ", + "image deleted.", + "images deleted.", + "Search wrapped.", + "No matches." + }; + + static const int toolBarFixedHeight = 40; + static const int statusBarFixedHeight = 18; + static const QSize sortBoxFixedSize(110, 25); + + static const QString &iconPath(const QString &fileName) { + + static QString p = ""; + + if (!fileName.isEmpty()) { + p = getPath(RESOURCE) + ICON_SOURCE + fileName; + } + + return p; + } + + const QString &isPlural(const int num, const int status) { + + static QString m = ""; + + if (num == 1) { + return (m = fqloraGeneralStatus[status]); + } else if (num > 1 && status > GEN_UNKNOWN && status < GEN_DELETES) { + return (m = fqloraGeneralStatus[status + 1]); + } + + return (m = fqloraGeneralStatus[GEN_UNKNOWN]); + } + + // get user's desktop rectangle + static const QRect &desktopSize() { + + static QRect size; + QDesktopWidget myDesktop; + return ((size = myDesktop.screenGeometry(myDesktop.primaryScreen()))); + } + + // FQTermImageFlow + FQTermImageFlow::~FQTermImageFlow() { + + delete statusBar_; + delete imageMenu_; + delete imageFlow_; + + statusBar_ = NULL; + imageMenu_ = NULL; + imageFlow_ = NULL; + } + + FQTermImageFlow::FQTermImageFlow(FQTermConfig * config, QWidget *parent, + Qt::WindowFlags wflag) : + FQTermImage(parent, wflag), + imageFlow_(new ImageFlow(this)), + imageMenu_(new ImageMenu(this)), + statusBar_(new QStatusBar(this)), + config_(config) { + + setWindowTitle(IMAGE_BROWSER_NAME); + setAutoFillBackground(true); + setBackgroundRole(QPalette::Midlight); + setFixedSize(desktopSize().width() / 1.3, desktopSize().height() / 1.9); + + FQ_VERIFY(connect(this, SIGNAL(isTrashEmpty()), this, SLOT(checkTrashState()))); + + // emblem state + FQ_VERIFY(connect(imageFlow_, SIGNAL(emblemStatus(const int)), imageMenu_, SLOT(updateEmblems(const int)))); + FQ_VERIFY(connect(imageMenu_, SIGNAL(toggleFlowStatus(const int)), imageFlow_, SLOT(toggleStatus(const int)))); + + // clear state + FQ_VERIFY(connect(imageFlow_, SIGNAL(clearStatus(const bool)), imageMenu_, SLOT(updateClear(const bool)))); + FQ_VERIFY(connect(imageMenu_, SIGNAL(clearImages()), this, SLOT(clearImages()))); + + // save state + FQ_VERIFY(connect(imageFlow_, SIGNAL(saveStatus(const bool)), imageMenu_, SLOT(updateSave(const bool)))); + FQ_VERIFY(connect(imageMenu_, SIGNAL(saveImages()), this, SLOT(saveImages()))); + + // trash state + FQ_VERIFY(connect(this, SIGNAL(trashStatus(const bool)), imageMenu_, SLOT(updateDustbin(const bool)))); + FQ_VERIFY(connect(imageMenu_, SIGNAL(recoverImages()), this, SLOT(recoverImages()))); + + // constructs a tool bar and its tool buttons + QAction *closeBrowserAct = new QAction(QIcon(iconPath("window-close.png")), tr("Close"), this); + closeBrowserAct->setShortcut(QKeySequence(Qt::Key_Q)); + FQ_VERIFY(connect(closeBrowserAct, SIGNAL(triggered()), this, SLOT(close()))); + + QAction *trashAllAct = new QAction(QIcon(iconPath("trash-empty.png")), tr("Trash All"), this); + trashAllAct->setShortcut(QKeySequence(Qt::Key_Delete)); + FQ_VERIFY(connect(trashAllAct, SIGNAL(triggered()), this, SLOT(trashAllImages()))); + + QLabel *sortLabel = new QLabel(this); + sortLabel->setMargin(5); + sortLabel->setToolTip("Reshuffle images by tags"); + sortLabel->setPixmap(QPixmap(iconPath("edit-shuffle.png"))); + + QComboBox *sortBox = new QComboBox(this); + sortBox->setFocusPolicy(Qt::ClickFocus); + sortBox->setFont(QFont("Serif", 12)); + sortBox->setFrame(false); + sortBox->setFixedSize(sortBoxFixedSize); + sortBox->insertItem(0, QIcon(iconPath("emblem-like-16x16.png")), tr("Like ")); + sortBox->insertItem(1, QIcon(iconPath("emblem-new-16x16.png")), tr("New ")); + sortBox->insertItem(2, QIcon(iconPath("emblem-trash-16x16.png")), tr("Trash ")); + sortBox->insertItem(3, QIcon(iconPath("emblem-recover-16x16.png")), tr("Recover ")); + sortBox->insertItem(4, QIcon(iconPath("emblem-title-16x16.png")), tr("Title ")); + FQ_VERIFY(connect(sortBox, SIGNAL(currentIndexChanged(int)), this, SLOT(reshuffleImages(int)))); + + QToolBar *toolBar = new QToolBar(this); + toolBar->setFixedHeight(toolBarFixedHeight); + toolBar->setIconSize(QSize(32, 32)); + toolBar->addAction(closeBrowserAct); + toolBar->addSeparator(); + toolBar->addWidget(sortLabel); + toolBar->addWidget(sortBox); + toolBar->addSeparator(); + toolBar->addAction(trashAllAct); + + // constructs a status bar to show instant messages + statusBar_->setSizeGripEnabled(false); + statusBar_->setFixedHeight(statusBarFixedHeight); + statusBar_->setFont(QFont("Serif", 10, QFont::Bold)); + FQ_VERIFY(connect(imageFlow_, SIGNAL(statusMessage(const QString &)), this, SLOT(showStatusMessage(const QString &)))); + FQ_VERIFY(connect(this, SIGNAL(statusMessage(const QString &)), this, SLOT(showStatusMessage(const QString &)))); + // constructs a horizontal layout + QVBoxLayout *vBox = new QVBoxLayout(this); + vBox->setMargin(0); + vBox->setSpacing(0); + vBox->addWidget(toolBar); + vBox->addWidget(imageFlow_); + vBox->addWidget(imageMenu_); + vBox->addWidget(statusBar_); + vBox->setEnabled(true); + setLayout(vBox); + } + + const QString &FQTermImageFlow::poolSource(void) const { + + static QString p = ""; + + p = config_->getItemValue("preference", "pool"); + + if (p.isEmpty()) { + p = getPath(USER_CONFIG) + POOL_SOURCE; + } + + return p; + } + + const QString &FQTermImageFlow::trashSource(void) const { + + static QString p = ""; + + p = poolSource() + TRASH_SOURCE; + return p; + } + + // these three functions below are kept for + // API compatibility. + void FQTermImageFlow::adjustItemSize() { + + } + + void FQTermImageFlow::scrollTo(const QString &filePath) { + + } + + void FQTermImageFlow::updateImage(const QString &filePath) { + + } + + // slots and functions + void FQTermImageFlow::loadImages(const int status) { + + int i; + int itemStatus = (status == STAT_RECOVER) ? status : STAT_UNKNOWN; + QString comment; + QFileInfoList sourceList = sortedList(poolSource()); + QFileInfoList targetList = imageFlow_->digest(STAT_ALL); + + for (i = 0; i < sourceList.count(); i++) { + + if (!targetList.contains(sourceList[i])) { + + QImage image; + + if (!image.load(sourceList[i].absoluteFilePath())) { + QFileIconProvider iconProvider; + image = iconProvider.icon(sourceList[i]).pixmap(desktopSize().height() / 6.0).toImage(); + } else { + image = image.scaled(desktopSize().width() / 6.0, desktopSize().height() / 6.0, + Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + + /* TODO */ + /* there should be a more flexible */ + /* method to deal with items' status */ + if (status == STAT_ALL) { + itemStatus = STAT_NEW; + } + + ImageFlowItem newItem(image, sourceList[i], comment,itemStatus); + imageFlow_->add(newItem); + } + } + } + + void FQTermImageFlow::reshuffleImages(const int status) { + + // there are images in the pool directory + QList itemKeys = imageFlow_->sort(status); + + if (imageFlow_->reorder(itemKeys)) { + imageFlow_->setCurrentSlide(0); + emit statusMessage(tr(fqloraGeneralStatus[GEN_RESHUFFLE]) + tr(fqloraTagStatus[status])); + } else { + emit statusMessage(tr(fqloraGeneralStatus[GEN_NOCHANGE]) + tr(fqloraTagStatus[status])); + } + } + + void FQTermImageFlow::saveImages() { + + QFileInfoList toSave = imageFlow_->digest(STAT_LIKE); + + if (!toSave.isEmpty()) { + + QMessageBox box; + box.setWindowModality(Qt::NonModal); + box.setWindowTitle("Information"); + box.setIconPixmap(QPixmap(iconPath("emblem-info.png"))); + box.setTextFormat(Qt::RichText); + box.setText(QString("%1 ").arg(toSave.count()) + isPlural(toSave.count(), GEN_TOSAVE)); + QPushButton *cancelButton = box.addButton(QMessageBox::Cancel); + QPushButton *saveAllButton = box.addButton(QMessageBox::SaveAll); + box.setDefaultButton(cancelButton); + box.exec(); + + if (box.clickedButton() == saveAllButton) { + + FQTermFileDialog fileDialog(config_); + QString savePath = + fileDialog.getExistingDirectory(tr("Save your likes under"), "*"); + + if (savePath.isEmpty()) { + emit statusMessage(tr(fqloraGeneralStatus[GEN_CANCEL])); + return; + } + + int i; + for (i = 0; i < toSave.count(); i++) { + QFile::rename(toSave[i].absoluteFilePath(), savePath + toSave[i].fileName()); + } + + imageFlow_->strip(STAT_LIKE); + emit statusMessage(QString("%1 ").arg(i) + isPlural(i, GEN_SAVE) + savePath); + } else { + emit statusMessage(tr(fqloraGeneralStatus[GEN_CANCEL])); + } + } else { + emit statusMessage(tr(fqloraGeneralStatus[GEN_NOTAG]) + tr(fqloraTagStatus[STAT_LIKE])); + } + } + + void FQTermImageFlow::checkTrashState() { + + QDir trashPath(trashSource()); + + if (trashPath.count() <= 2) { + emit trashStatus(false); + } else { + emit trashStatus(true); + } + } + + void FQTermImageFlow::clearImages() { + + int i; + QString trashPath = trashSource(); + QDir trashDir(trashPath); + QFileInfoList toRemove = imageFlow_->digest(STAT_TRASH); + + if (!trashDir.exists()) { + trashDir.mkdir(trashPath); + } + + if (!toRemove.isEmpty()) { + + for (i = 0; i < toRemove.count(); i++) { + if (QFile::exists(toRemove[i].absoluteFilePath())) { + QFile::rename(toRemove[i].absoluteFilePath(), trashPath + toRemove[i].fileName()); + } + } + + imageFlow_->strip(STAT_TRASH); + emit statusMessage(QString("%1 ").arg(i) + isPlural(i, GEN_TRASH)); + emit isTrashEmpty(); + } else { + emit statusMessage(tr(fqloraGeneralStatus[GEN_NOTAG]) + tr(fqloraTagStatus[STAT_TRASH])); + } + } + + void FQTermImageFlow::trashAllImages() { + + int i; + QString trashPath = trashSource(); + QDir trashDir(trashPath); + QFileInfoList toRemove = imageFlow_->digest(STAT_ALL); + + if (!trashDir.exists()) { + trashDir.mkdir(trashPath); + } + + if (imageFlow_->count() > 0) { + for (i = 0; i < imageFlow_->count(); i++) { + if (QFile::exists(toRemove[i].absoluteFilePath())) { + QFile::rename(toRemove[i].absoluteFilePath(), trashPath + toRemove[i].fileName()); + } + } + + imageFlow_->clear(); + emit statusMessage(QString("%1 ").arg(i) + isPlural(i, GEN_TRASH)); + emit isTrashEmpty(); + } else { + emit statusMessage(tr(fqloraGeneralStatus[GEN_NOTAG]) + tr(fqloraTagStatus[STAT_TRASH])); + } + } + + void FQTermImageFlow::recoverImages() { + + QString trashPath = trashSource(); + QDir trashDir(trashPath); + + if (!trashDir.exists()) { + trashDir.mkdir(trashPath); + } else if (trashDir.count() > 2) { + + int action = -1;; + QFileInfoList toRecover = sortedList(trashPath); + + if (!toRecover.isEmpty()) { + + QMessageBox box; + box.setWindowModality(Qt::NonModal); + box.setWindowTitle("Take action"); + box.setIconPixmap(QPixmap(iconPath("emblem-info.png"))); + box.setTextFormat(Qt::RichText); + box.setText(QString("%1 ").arg(toRecover.count()) + isPlural(toRecover.count(), GEN_INTRASH)); + QPushButton *cancelButton = box.addButton(QMessageBox::Cancel); + QPushButton *recoverButton = box.addButton(tr("Recover"), QMessageBox::ApplyRole); + recoverButton->setIcon(QIcon(iconPath("button-recover.png"))); + QPushButton *deleteButton = box.addButton(tr("Delete"), QMessageBox::ApplyRole); + deleteButton->setIcon(QIcon(iconPath("button-delete.png"))); + box.setDefaultButton(cancelButton); + box.exec(); + + if (box.clickedButton() == cancelButton) { + emit statusMessage(tr(fqloraGeneralStatus[GEN_CANCEL])); + return; + } else if (box.clickedButton() == recoverButton) { + action = 1; + } else if (box.clickedButton() == deleteButton) { + action = 0; + } + + int i; + QFile imageFile; + QString poolPath = poolSource(); + + for (i = 0; i < toRecover.count(); i++) { + if (action == 1) { + QFile::rename(toRecover[i].absoluteFilePath(), poolPath + toRecover[i].fileName()); + } else if (action == 0) { + imageFile.setFileName(toRecover[i].absoluteFilePath()); + imageFile.remove(); + } + } + + if (action == 1) { + loadImages(STAT_RECOVER); + emit statusMessage(QString("%1 ").arg(i) + isPlural(i, GEN_RECOVER)); + } else if (action == 0) { + emit statusMessage(QString("%1 ").arg(i) + isPlural(i, GEN_DELETE)); + } + } + } else { + + emit statusMessage(tr(fqloraGeneralStatus[GEN_NORECOVER])); + } + + emit isTrashEmpty(); + } + + + void FQTermImageFlow::showStatusMessage(const QString &message) { + + if (statusBar_) { + statusBar_->showMessage(message, 3000); + } + } + + QFileInfoList FQTermImageFlow::sortedList(const QString &path) { + + QDir sortPath(path); + + if (!sortPath.exists()) { + sortPath.mkdir(path); + } + + QStringList filters; + QList formats = QImageReader::supportedImageFormats(); + for (QList::iterator it = formats.begin(); + it != formats.end(); + ++it) { + QString filter("*."); + filter.append(it->data()); + filters << filter; + } + sortPath.setNameFilters(filters); + + return (sortPath.entryInfoList(QDir::Files | QDir::Readable | QDir::NoSymLinks, QDir::Time)); + } + + // FQTermImageFlow events. + void FQTermImageFlow::showEvent(QShowEvent *event) { + + emit isTrashEmpty(); + + if (imageFlow_->count() <= 0) { + loadImages(STAT_UNKNOWN); + move((desktopSize().width() - width()) / 2.0, (desktopSize().height() - height()) / 2.0); + } else { + // TODO: insert new images + loadImages(STAT_ALL); + } + } + + void FQTermImageFlow::closeEvent(QCloseEvent *event) { + + hide(); + } + + class ImageMenu::Private { + public: + int emblemStatus; + bool dustbinStatus; + bool saveStatus; + bool clearStatus; + + QString tipMessage; + + QRect rectLike; + QRect rectTrash; + QRect rectNew; + QRect rectRecover; + QRect rectEmblems; + + QRect rectClear; + QRect rectSave; + QRect rectDustbin; + + QPixmap pixmapLike, pixmapLikeGray; + QPixmap pixmapTrash, pixmapTrashGray; + QPixmap pixmapNew, pixmapNewGray; + QPixmap pixmapRecover, pixmapRecoverGray; + + QPixmap pixmapClear, pixmapClearGray; + QPixmap pixmapSave, pixmapSaveGray; + QPixmap pixmapDustbin, pixmapDustbinGray; + }; + + //ImageMenu + ImageMenu::ImageMenu(QWidget *parent) + : fh(new ImageMenu::Private) { + + setAutoFillBackground(true); + setBackgroundRole(QPalette::Shadow); + setFocusPolicy(Qt::NoFocus); + setMouseTracking(true); + setFixedHeight(60); + + fh->emblemStatus = -2; + fh->dustbinStatus = false; + fh->saveStatus = false; + fh->clearStatus = false; + + fh->tipMessage = ""; + + fh->rectLike = QRect(50, 14, 32, 32); + fh->rectTrash = QRect(100, 14, 32, 32); + fh->rectNew = QRect(150, 14, 32, 32); + fh->rectRecover = QRect(200, 14, 32, 32); + fh->rectEmblems = QRect(50, 14, 232, 32); + + fh->rectClear = QRect(300, 14, 32, 32); + fh->rectSave = QRect(350, 14, 32, 32); + fh->rectDustbin = QRect(400, 14, 32, 32); + + fh->pixmapLike = QPixmap(iconPath("emblem-like.png")); + fh->pixmapLikeGray = QPixmap(iconPath("emblem-like-gray.png")); + + fh->pixmapTrash = QPixmap(iconPath("emblem-trash.png")); + fh->pixmapTrashGray = QPixmap(iconPath("emblem-trash-gray.png")); + + fh->pixmapNew = QPixmap(iconPath("emblem-new.png")); + fh->pixmapNewGray = QPixmap(iconPath("emblem-new-gray.png")); + + fh->pixmapRecover = QPixmap(iconPath("emblem-recover.png")); + fh->pixmapRecoverGray = QPixmap(iconPath("emblem-recover-gray.png")); + + fh->pixmapClear = QPixmap(iconPath("clear-state.png")); + fh->pixmapClearGray = QPixmap(iconPath("clear-state-gray.png")); + + fh->pixmapSave = QPixmap(iconPath("save-state.png")); + fh->pixmapSaveGray = QPixmap(iconPath("save-state-gray.png")); + + fh->pixmapDustbin = QPixmap(iconPath("trash-state.png")); + fh->pixmapDustbinGray = QPixmap(iconPath("trash-state-gray.png")); + } + + ImageMenu::~ImageMenu() { + + delete fh; + fh = NULL; + } + + void ImageMenu::updateEmblems(const int status) { + + if (fh->emblemStatus != status) { + update(fh->rectEmblems); + } + + fh->emblemStatus = status; + } + + void ImageMenu::updateClear(const bool hasOrNot) { + + if (fh->clearStatus != hasOrNot) { + update(fh->rectClear); + } + + fh->clearStatus = hasOrNot; + } + + void ImageMenu::updateSave(const bool hasOrNot) { + + if (fh->saveStatus != hasOrNot) { + update(fh->rectSave); + } + + fh->saveStatus = hasOrNot; + } + + void ImageMenu::updateDustbin(const bool fullOrNot) { + + if (fh->dustbinStatus != fullOrNot) { + update(fh->rectDustbin); + } + + fh->dustbinStatus = fullOrNot; + } + + void ImageMenu::paintEvent(QPaintEvent *event) { + + QPainter p(this); + + p.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing); + + if (fh->emblemStatus == STAT_LIKE) { + p.drawPixmap(fh->rectLike, fh->pixmapLike); + } else { + p.drawPixmap(fh->rectLike, fh->pixmapLikeGray); + } + + if (fh->emblemStatus == STAT_TRASH) { + p.drawPixmap(fh->rectTrash, fh->pixmapTrash); + } else { + p.drawPixmap(fh->rectTrash, fh->pixmapTrashGray); + } + + if (fh->emblemStatus == STAT_NEW) { + p.drawPixmap(fh->rectNew, fh->pixmapNew); + } else { + p.drawPixmap(fh->rectNew, fh->pixmapNewGray); + } + + if (fh->emblemStatus == STAT_RECOVER) { + p.drawPixmap(fh->rectRecover, fh->pixmapRecover); + } else { + p.drawPixmap(fh->rectRecover, fh->pixmapRecoverGray); + } + + if (fh->clearStatus == true) { + p.drawPixmap(fh->rectClear, fh->pixmapClear); + } else { + p.drawPixmap(fh->rectClear, fh->pixmapClearGray); + } + + if (fh->saveStatus == true) { + p.drawPixmap(fh->rectSave, fh->pixmapSave); + } else { + p.drawPixmap(fh->rectSave, fh->pixmapSaveGray); + } + + if (fh->dustbinStatus == true) { + p.drawPixmap(fh->rectDustbin, fh->pixmapDustbin); + } else { + p.drawPixmap(fh->rectDustbin, fh->pixmapDustbinGray); + } + + p.end(); + } + + void ImageMenu::mouseReleaseEvent(QMouseEvent *event) { + + if (event->button() == Qt::LeftButton + || event->button() == Qt::RightButton) { + + if (fh->rectLike.contains(event->pos())) { + emit toggleFlowStatus(STAT_LIKE); + } + + if (fh->rectTrash.contains(event->pos())) { + emit toggleFlowStatus(STAT_TRASH); + } + + if (fh->rectClear.contains(event->pos())) { + emit clearImages(); + } + + if (fh->rectSave.contains(event->pos())) { + emit saveImages(); + } + + if (fh->rectDustbin.contains(event->pos())) { + emit recoverImages(); + } + } + } + + // ImageFlow: this subclasses PictureFlow + class ImageFlow::Private { + public: + int emblemStatus; + int likeCount; + int clearCount; + + QList itemsTitles; + QHash itemsTitleKeyPairs; + QList items; + }; + + ImageFlow::~ImageFlow() { + + delete m; + m = NULL; + } + + // construct an emptry pictureflow. + ImageFlow::ImageFlow(QWidget *parent) + : PictureFlow(parent), m(new ImageFlow::Private) { + + // initial setup + setFocusPolicy(Qt::StrongFocus); + setZoomFactor(120); + setSlideCount(0); + m->emblemStatus = -1; + m->likeCount = 0; + m->clearCount = 0; + } + + const ImageFlowItem& ImageFlow::operator[](int index) const { + + return (m->items[index]); + } + + ImageFlowItem& ImageFlow::operator[](int index) { + + return (m->items[index]); + } + + const ImageFlowItem& ImageFlow::at(int index) const { + + return (m->items[index]); + } + + void ImageFlow::add(const ImageFlowItem &item) { + + QByteArray title = item.info().fileName().toLocal8Bit(); + + m->items.append(item); + m->itemsTitles.append(title); + m->itemsTitleKeyPairs.insert(title, item.key()); + + // set the status pixmap + int index = m->items.indexOf(item); + m->items[index].setStatus(item.status()); + + int count = m->items.count(); + setSlideCount(count); + setSlide(count - 1, item.image()); + } + + QList& ImageFlow::itemsTitles() const { + + return (m->itemsTitles); + } + + void ImageFlow::clear() { + + m->items.clear(); + setSlideCount(0); + setCurrentSlide(0); + PictureFlow::clear(); + } + + int ImageFlow::count() const { + + return (m->items.count()); + } + + int ImageFlow::size() const { + + return (m->items.size()); + } + + QFileInfoList& ImageFlow::digest(const int status) { + + int i; + int count = m->items.size(); + static QFileInfoList result; + + result.clear(); + + for (i = 0; i < count; i++) { + switch (status) { + case STAT_ALL: + result.append(m->items[i].info()); + break; + default: + if (m->items[i].status() == status) { + result.append(m->items[i].info()); + } + break; + } + } + + return result; + } + + void ImageFlow::strip(const int status) { + + int i; + int count = m->items.count(); + QList dirtyIndexes; + + // We cannot delete items in a loop because + // items count will change while deleting. + // A better method is to use another list + // to record 'dirty' items, and by looping this + // dirty list, we can correctly delete those + // dirty items successfully. + for (i = 0; i < count; i++) { + if (m->items[i].status() == status) { + dirtyIndexes.append(i); + } + } + + if (!dirtyIndexes.isEmpty()) { + + for (i = 0; i < dirtyIndexes.count(); i++) { + // Note: dirtyIndexes[i] - i: the actual + // position of the dirty item. + m->items.removeAt(dirtyIndexes[i] - i); + } + + dirtyIndexes.clear(); + reorder(sort(STAT_ALL)); + + for (i = 0; i < m->items.count(); i++) { + setSlide(i, m->items[i].image()); + } + + setSlideCount(i); + setCurrentSlide(0); + + switch(status) { + case STAT_LIKE: + m->likeCount = 0; + emit saveStatus(false); + emit emblemStatus(STAT_UNKNOWN); + break; + case STAT_TRASH: + m->clearCount = 0; + emit clearStatus(false); + emit emblemStatus(STAT_UNKNOWN); + break; + default: + break; + } + } + } + + QList ImageFlow::sort(const int status) { + + int i; + int count = m->items.count(); + QList itemKeys; + + switch (status) { + case STAT_TITLE: + qStableSort(m->itemsTitles.begin(), m->itemsTitles.end(), qLess()); + for (i = 0; i < m->itemsTitles.count(); i++) { + itemKeys.append(m->itemsTitleKeyPairs.value(m->itemsTitles[i])); + } + break; + default: + for (i = 0; i < count; i++) { + if (m->items[i].status() == status) { + itemKeys.prepend(m->items[i].key()); + } else { + itemKeys.append(m->items[i].key()); + } + } + break; + } + + // this might be unnecessary here. + return itemKeys; + } + + bool ImageFlow::reorder(const QList& itemsKey) { + + int items_count = m->items.size(); + + if (itemsKey.size() != items_count) { + + return (false); + } + + // Collect Items Key + QList currentItemsKey; + for (int i = 0; i < items_count; i++) { + + currentItemsKey.append(m->items.at(i).key()); + } + + if (currentItemsKey == itemsKey) { + // if identical, we don't sort. + return (false); + } + + // Swap Items + for (int i=0; i < items_count; i++) { + + int index = currentItemsKey.indexOf(itemsKey.at(i)); + if (i == index) { + continue; + } + + QImage imgA = m->items[i].image(); + QImage imgB = m->items[index].image(); + + setSlide(index, imgA); + setSlide(i, imgB); + + m->items.swap(i, index); + currentItemsKey.swap(i, index); + } + + update(); + rehash(); + return(true); + } + + void ImageFlow::rehash(void) { + + int count = m->items.count(); + + if (count <= 0) { + return; + } + + int i; + + m->itemsTitles.clear(); + m->itemsTitleKeyPairs.clear(); + + qint64 k; + QByteArray b; + + for (i = 0; i < count; i++) { + k = m->items[i].key(); + b = m->items[i].info().fileName().toLocal8Bit(); + m->itemsTitles.append(b); + m->itemsTitleKeyPairs.insert(b, k); + } + } + + void ImageFlow::toggleStatus(const int status) { + + int index = currentSlide(); + int count = m->items.count(); + + if (index >= 0 && index < count) { + + setUpdatesEnabled(false); + if (m->items[index].status() != status) { + + switch (status) { + case STAT_LIKE: + m->likeCount++; + if (m->items[index].status() == STAT_TRASH) { + m->clearCount--; + } + emit saveStatus(true); + break; + case STAT_TRASH: + m->clearCount++; + if (m->items[index].status() == STAT_LIKE) { + m->likeCount--; + } + emit clearStatus(true); + break; + default: + break; + } + + m->items[index].setStatus(status); + emit statusMessage(tr("Tagged as ") + tr(fqloraTagStatus[status])); + + } else { + + switch (status) { + case STAT_LIKE: + m->likeCount--; + break; + case STAT_TRASH: + m->clearCount--; + break; + default: + break; + } + + m->items[index].setStatus(STAT_UNKNOWN); + emit statusMessage("Tag cleared"); + } + + if (m->likeCount <= 0) { + emit saveStatus(false); + } else { + emit saveStatus(true); + } + + if (m->clearCount <= 0) { + emit clearStatus(false); + } else { + emit clearStatus(true); + } + + setUpdatesEnabled(true); + } + } + + void ImageFlow::setCurrentImage(const int index) { + + int count = size(); + + if (count > 0 && index > 0 && index < count) { + + setCurrentSlide(index); + } + } + +// events + void ImageFlow::paintEvent(QPaintEvent *event) { + + PictureFlow::paintEvent(event); + + if (slideCount() < 1) { + return; + } + + QPainter p(this); + + // White Pen for File Info + p.setPen(Qt::gray); + + int cw = width() / 2; + int wh = height(); + + ImageFlowItem& item = m->items[currentSlide()]; + + // Draw File Name if it's not empty + QString title = item.info().fileName(); + if (!title.isEmpty()) { + + p.setFont(QFont(p.font().family(), p.font().pointSize() + 1, QFont::Bold)); + p.drawText(cw - (QFontMetrics(p.font()).width(title) / 2), wh - 20, title); + } + + p.end(); + + if (m->emblemStatus != item.status()) { + emit emblemStatus(item.status()); + } + + m->emblemStatus = item.status(); + } + + // ImageFlowItem + class ImageFlowItem::Private { + public: + QString filePath; + QFileInfo info; + QString comment; + QImage image; + int status; + qint64 key; + + }; + + ImageFlowItem::~ImageFlowItem() { + + delete m; + m = NULL; + } + + // constructs an empty item + ImageFlowItem::ImageFlowItem(QObject *parent) + : QObject(parent), m(new ImageFlowItem::Private) { + + m->key = qHash(QString::number(m->image.cacheKey()) + m->info.fileName() + m->comment); + } + + ImageFlowItem::ImageFlowItem(const ImageFlowItem &item) + : QObject(item.parent()), m(new ImageFlowItem::Private) { + + operator=(item); + } + + // constructs an item with a given image + ImageFlowItem::ImageFlowItem(const QImage &image, QObject *parent) + : QObject(parent), m(new ImageFlowItem::Private) { + + m->image = image; + m->key = qHash(QString::number(m->image.cacheKey()) + m->info.fileName() + m->comment); + } + + // constructs an image with given image and title + ImageFlowItem::ImageFlowItem(const QImage &image, const QFileInfo &info, QObject *parent) + : QObject(parent), m(new ImageFlowItem::Private) { + + m->image = image; + m->info = info; + m->key = qHash(QString::number(m->image.cacheKey()) + m->info.fileName() + m->comment); + } + + // constructs an image with given image, title and comment + ImageFlowItem::ImageFlowItem(const QImage &image, const QFileInfo &info, const QString &comment, QObject *parent) + : QObject(parent), m(new ImageFlowItem::Private) { + + m->image = image; + m->info = info; + m->comment = comment; + m->key = qHash(QString::number(m->image.cacheKey()) + m->info.fileName() + m->comment); + } + + // constructs an image with given image, title, type, size, time and state + ImageFlowItem::ImageFlowItem(const QImage &image, const QFileInfo &info, const QString& comment, const int status, QObject *parent) + : QObject(parent), m(new ImageFlowItem::Private) { + + m->image = image; + m->info = info; + m->comment = comment; + m->status = status; + + m->key = qHash(QString::number(m->image.cacheKey()) + m->info.fileName() + m->comment); + } + + // funcs and slots + ImageFlowItem& ImageFlowItem::operator=(const ImageFlowItem &item) { + + m->info = item.m->info; + m->comment = item.m->comment; + m->key = item.m->key; + + if (item.m->filePath.isEmpty()) { + m->image = item.m->image; + } else { + setImage(item.m->filePath, m->key); + } + + return (*this); + } + + bool ImageFlowItem::operator==(const ImageFlowItem& item) const { + + return (item.m->key == m->key); + } + + bool ImageFlowItem::operator!=(const ImageFlowItem& item) const { + + return (item.m->key != m->key); + } + + const QString& ImageFlowItem::comment() const { + + return (m->comment); + } + + const QImage& ImageFlowItem::image() const { + + return (m->image); + } + + int ImageFlowItem::status(void) const { + + return (m->status); + } + + const QFileInfo& ImageFlowItem::info(void) const { + + return (m->info); + } + + qint64 ImageFlowItem::key() const { + + return (m->key); + } + + void ImageFlowItem::setInfo(const QFileInfo& info) { + + m->info = info; + m->key = qHash(QString::number(m->image.cacheKey()) + m->info.fileName() + m->comment); + } + + void ImageFlowItem::setComment(const QString &comment) { + + m->comment = comment; + m->key = qHash(QString::number(m->image.cacheKey()) + m->info.fileName() + m->comment); + } + + void ImageFlowItem::setImage(const QImage &image) { + + m->image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + m->key = qHash(QString::number(m->image.cacheKey()) + m->info.fileName() + m->comment); + } + + void ImageFlowItem::setImage(const QString &filePath, int size) { + + m->filePath = filePath; + m->key = size; + + QTimer::singleShot(1000, this, SLOT(loadImage())); + } + + void ImageFlowItem::setStatus(const int status) { + + m->status = status; + } + + void ImageFlowItem::loadImage() { + + int imageHeight = m->key; + + if (!m->image.load(m->filePath)) { + QFileIconProvider iconProvider; + m->image = iconProvider.icon(QFileInfo(m->filePath)).pixmap(imageHeight).toImage(); + } else { + m->image = resizeImage(m->image, imageHeight); + } + + m->filePath.clear(); + m->key = qHash(QString::number(m->image.cacheKey()) + m->info.fileName() + m->comment); + } + + QImage ImageFlowItem::resizeImage(const QImage &image, int size) { + + if (size == image.width() && size == image.height()) { + return image; + } + + double scaleWidth = size / (double)image.width(); + double scaleHeight = size / (double)image.height(); + double smaller = qMin(scaleWidth, scaleHeight); + + int w = (int) qRound(smaller * image.width()); + int h = (int) qRound(smaller * image.height()); + + return (image.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } + + // original viewer + void FQTermImageOrigin::onChange(const QModelIndex & index) { + + if (!model_->isDir(index)) { + + if (!isHidden()) + canvas_->hide(); + + QString exifInfo = QString::fromStdString(exifExtractor_->extractExifInfo(model_->filePath(tree_->currentIndex()).toLocal8Bit().data())); + bool resized = false; + + if (exifInfo != "") { + + if (!isExifTableShown_) { + adjustLayout(true); + isExifTableShown_ = true; + resized = true; + } + + updateExifInfo(); + } else { + + if (isExifTableShown_) { + adjustLayout(false); + isExifTableShown_ = false; + resized = true; + } + } + + QString path = QDir::toNativeSeparators(model_->filePath(index)); + + if (path.endsWith(QDir::separator())) + path.chop(1); + + canvas_->loadImage(path, !resized); + + // canvas_->autoAdjust(); + if (!isHidden()) + canvas_->show(); + } + } + + FQTermImageOrigin::~FQTermImageOrigin() { + delete menuBar_; + delete canvas_; + delete tree_; + delete model_; + } + + FQTermImageOrigin::FQTermImageOrigin(FQTermConfig * config, QWidget *parent, + Qt::WindowFlags wflag) : + FQTermImage(parent, wflag), + config_(config), + isExifTableShown_(false) { + + setWindowTitle(tr("FQTerm Image Viewer")); + ItemDelegate* itemDelegate = new ItemDelegate; + exifExtractor_ = new ExifExtractor; + exifTable_ = new ExifTable(this); + exifTable_->setTextFormat(Qt::RichText); + exifTable_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + canvas_ = new FQTermCanvas(config, this, 0); + canvas_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + model_ = new ImageViewerDirModel; + tree_ = new QTreeView; + + + tree_->setModel(model_); + tree_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + adjustItemSize(); + tree_->setItemDelegate(itemDelegate); + tree_->setColumnWidth(0, 150); + tree_->setColumnWidth(1, 0); + + tree_->hideColumn(0); + + tree_->setUniformRowHeights(true); + tree_->setWordWrap(true); + //tree_->header()->setResizeMode(0, QHeaderView::Fixed); + //tree_->header()->setResizeMode(1, QHeaderView::ResizeToContents); + //tree_->header()->resizeSection(0, 150); + //tree_->header()->resizeSection(1, 1); + comboBox_ = new QComboBox(this); + comboBox_->addItem(tr("Sort by name"), QDir::Name); + comboBox_->addItem(tr("Sort by time"), QDir::Time); + comboBox_->addItem(tr("Sort by size"), QDir::Size); + comboBox_->addItem(tr("Sort by type"), QDir::Type); + + FQ_VERIFY(connect(comboBox_, SIGNAL(currentIndexChanged(int)), this, SLOT(sortFileList(int)))); + + comboBox_->setCurrentIndex(1); + + layout_ = new QGridLayout; + menuBar_ = new QMenuBar(this); + menuBar_->addMenu(canvas_->menu()); + menuBar_->resize(1,1); + + canvas_->ToolBar()->addAction( + QIcon(getPath(RESOURCE) + ICON_SOURCE + "prev.png"), tr("Previous"), + this, SLOT(previous())); + canvas_->ToolBar()->addAction( + QIcon(getPath(RESOURCE) + ICON_SOURCE + "next.png"), tr("Next"), + this, SLOT(next())); + + layout_->addWidget(tree_, 0, 0, 12, 1); + layout_->addWidget(comboBox_, 12, 0, 1, 1); + layout_->addWidget(canvas_, 0, 1, 12, 10); + // layout_->addWidget(exifTable_, 10, 1, 2, 10); + layout_->addWidget(canvas_->ToolBar(), 12, 1, 1, 10, Qt::AlignHCenter); + layout_->setColumnMinimumWidth(0, tree_->columnWidth(0) + 150); + setLayout(layout_); + + /* + FQ_VERIFY(connect(tree_, SIGNAL(clicked(const QModelIndex &)), + this, SLOT(onChange(const QModelIndex &)))); + */ + FQ_VERIFY(connect(tree_, SIGNAL(activated(const QModelIndex &)), + this, SLOT(onChange(const QModelIndex &)))); + FQ_VERIFY(connect(tree_->selectionModel(), + SIGNAL(selectionChanged(const QItemSelection&, + const QItemSelection&)), + this, SLOT(selectionChanged(const QItemSelection&, + const QItemSelection&)))); + FQ_VERIFY(connect(exifTable_, SIGNAL(showExifDetails()), + this, SLOT(showFullExifInfo()))); + } + + void FQTermImageOrigin::scrollTo(const QString& filename) { + + QString path = QFileInfo(filename).absolutePath(); + model_->refresh(); + tree_->setRootIndex(model_->index(path)); + canvas_->loadImage(filename); + + if (canvas_->isHidden() && !isHidden()) { + canvas_->show(); + } + + const QModelIndex& index = model_->index(filename); + tree_->scrollTo(index); + tree_->setCurrentIndex(index); + } + + void FQTermImageOrigin::updateImage(const QString& filename) { + + static int i = 0; + if (++i == 10) { + model_->refresh(model_->index(filename)); + i = 0; + } + canvas_->updateImage(filename); + } + + void FQTermImageOrigin::previous() { + + const QModelIndex& index = tree_->indexAbove(tree_->currentIndex()); + if (index.isValid()) { + tree_->setCurrentIndex(index); + canvas_->loadImage(QDir::toNativeSeparators(model_->filePath(index))); + } + } + + void FQTermImageOrigin::next() { + + const QModelIndex& index = tree_->indexBelow(tree_->currentIndex()); + if (index.isValid()) { + tree_->setCurrentIndex(index); + canvas_->loadImage(QDir::toNativeSeparators(model_->filePath(index))); + } + } + + void FQTermImageOrigin::adjustItemSize() { + + QFontMetrics fm(font()); + ItemDelegate::size_.setWidth(qMax(128, fm.width("WWWWWWWW.WWW"))); + ItemDelegate::size_.setHeight(fm.height() + 150); + } + + void FQTermImageOrigin::selectionChanged(const QItemSelection & selected, + const QItemSelection & deselected) { + + onChange(tree_->selectionModel()->currentIndex()); + } + + void FQTermImageOrigin::sortFileList(int index) { + + model_->setSorting(QDir::SortFlag(comboBox_->itemData(index).toInt())); + QString poolPath = config_->getItemValue("preference", "pool"); + + if (poolPath.isEmpty()) { + poolPath = getPath(USER_CONFIG) + "pool/"; + } + + tree_->setRootIndex(model_->index(poolPath)); + } + + void FQTermImageOrigin::showFullExifInfo() { + + QString exifInfo = QString::fromStdString(exifExtractor_->extractExifInfo(model_->filePath(tree_->currentIndex()).toLocal8Bit().data())); + QString comment; + + if ((*exifExtractor_)["UserComment"].length() > 8) { + + QString commentEncoding = QString::fromStdString((*exifExtractor_)["UserComment"].substr(0, 8)); + + if (commentEncoding.startsWith("UNICODE")) { + //UTF-16 + QTextCodec* c = QTextCodec::codecForName("UTF-16"); + comment = c->toUnicode((*exifExtractor_)["UserComment"].substr(8).c_str()); + } else if (commentEncoding.startsWith("JIS")) { + //JIS X 0208 + QTextCodec* c = QTextCodec::codecForName("JIS X 0208"); + comment = c->toUnicode((*exifExtractor_)["UserComment"].substr(8).c_str()); + } else { + comment = QString::fromStdString((*exifExtractor_)["UserComment"].substr(8)); + } + } + + + QTextEdit* info = new QTextEdit; + info->setText(exifInfo + tr("Comment : ") + comment + "\n"); + info->setWindowFlags(Qt::Dialog); + info->setAttribute(Qt::WA_DeleteOnClose); + info->setAttribute(Qt::WA_ShowModal); + // info->setLineWrapMode(QTextEdit::NoWrap); + info->setReadOnly(true); + QFontMetrics fm(font()); + info->resize(fm.width("Orientation : 1st row - 1st col : top - left side "), fm.height() * 20); + info->show(); + } + + void FQTermImageOrigin::adjustLayout(bool withExifTable) { + + if (withExifTable) { + + layout_->addWidget(canvas_, 0, 1, 11, 10); + layout_->addWidget(exifTable_, 11, 1, 1, 10, Qt::AlignHCenter); + if (!isHidden() && exifTable_->isHidden()) { + exifTable_->show(); + } + + layout_->addWidget(canvas_->ToolBar(), 12, 1, 1, 10, Qt::AlignHCenter); + } else { + layout_->addWidget(canvas_, 0, 1, 12, 10); + layout_->removeWidget(exifTable_); + exifTable_->hide(); + layout_->addWidget(canvas_->ToolBar(), 12, 1, 1, 10, Qt::AlignHCenter); + } + } + + void FQTermImageOrigin::updateExifInfo() { + + exifTable_->clear(); + + QString exifInfoToShow = "" + + "" + + ""; + + exifTable_->setText(exifInfoToShow); + if (!isHidden() && exifTable_->isHidden()) { + exifTable_->show(); + } + } + + void FQTermImageOrigin::closeEvent( QCloseEvent *clse ) { + + hide(); + clse->ignore(); + return ; + } + + ImageViewerDirModel::ImageViewerDirModel(QObject *parent /*= 0*/) + : QDirModel(parent) { + + //insertColumn(1); + QStringList nameFilterList; + QList formats = QImageReader::supportedImageFormats(); + for (QList::iterator it = formats.begin(); + it != formats.end(); + ++it) { + QString filter("*."); + filter.append(it->data()); + nameFilterList << filter; + } + setNameFilters(nameFilterList); + setFilter(QDir::Files); + } + + int ImageViewerDirModel::columnCount(const QModelIndex &/*parent*/) const { + + return 2; + } + + QVariant ImageViewerDirModel::headerData( + int section, Qt::Orientation orientation, int role) const { + //if (section == 0) return QVariant(); + if (role == Qt::DisplayRole) { + // if (section == 1) { + return QString(tr("Image Preview")); + //} + } + return QDirModel::headerData(section, orientation, role); + } + + QVariant ImageViewerDirModel::data(const QModelIndex &index, int role) const { + //if (index.column() == 0) return QVariant(); + if (role == Qt::DecorationRole) { + if (isDir(index)) { + return QVariant(); + } + + QString path = QDir::toNativeSeparators(filePath(index)); + if (path.endsWith(QDir::separator())) + path.chop(1); + + QPixmap pixmap; + bool res = pixmap.load(path); + if (!res) { + QList formats = QImageReader::supportedImageFormats(); + for (QList::iterator it = formats.begin(); + !res && it != formats.end(); + ++it) { + res = pixmap.load(path, it->data()); + } + } + + if (pixmap.height() > 128 || pixmap.width() > 128) { + return pixmap.scaled(128, 128, + Qt::KeepAspectRatio, Qt::SmoothTransformation); + } + + return pixmap; + } else if (role == Qt::DisplayRole) { + return fileName(index); + }/* + else if (role == Qt::TextAlignmentRole) { + return Qt::Qt::AlignBottom; + }*/ + return QVariant(); + } + + QSize ItemDelegate::size_; + + void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & option, + const QModelIndex & index ) const { + //if (index.column() == 0) return; + QStyleOptionViewItemV3 opt = setOptions(index, option); + + // prepare + painter->save(); + + // get the data and the rectangles + const QPixmap& pixmap + = qvariant_cast(index.data(Qt::DecorationRole)); + QRect decorationRect = QRect(opt.rect.topLeft(), pixmap.size()); + decorationRect.moveTo(decorationRect.left(), decorationRect.top() + 10); + const QString& text = index.data(Qt::DisplayRole).toString(); + QFontMetrics fm(painter->font()); + QRect displayRect = QRect(decorationRect.bottomLeft(), + QSize(fm.width(text),fm.height())); + + QRect checkRect; + Qt::CheckState checkState = Qt::Unchecked; + QVariant value = index.data(Qt::CheckStateRole); + + if (value.isValid()) { + checkState = static_cast(value.toInt()); + checkRect = check(opt, opt.rect, value); + } + + // do the layout + + // doLayout(opt, &checkRect, &decorationRect, &displayRect, false); + + // draw the item + + drawBackground(painter, opt, index); + painter->drawPixmap(decorationRect, pixmap); + painter->drawText(displayRect, text); + + drawFocus(painter, opt, displayRect); + + // done + painter->restore(); + } + + void ExifTable::mouseReleaseEvent(QMouseEvent *pEvent) { + + if (pEvent->button() == Qt::LeftButton) { + emit(showExifDetails()); + } + } + + ExifTable::ExifTable(QWidget *parent) : QLabel(parent) { + + } + + FQTermImage::FQTermImage( QWidget * parent, Qt::WindowFlags f ) : QWidget(parent, f) { + } + +} // namespace FQTerm + +#include "imageviewer.moc" diff --git a/src/ui/imageviewer.h b/src/ui/imageviewer.h new file mode 100644 index 0000000..ba98559 --- /dev/null +++ b/src/ui/imageviewer.h @@ -0,0 +1,336 @@ + +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef IMAGE_VIERWER_H +#define IMAGE_VIERWER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class QString; +class QPushButton; +class QVBoxLayout; +class QHBoxLayout; +class QMenuBar; +class QTreeView; +class QComboBox; + +#include "pictureflow.h" + +namespace FQTerm { + +#define DISP_MARGIN (10.0) // show a margin +#define PIXMAP_CACHESIZE (5120) // in KBytes +#define ZOOMIN_FACTOR (1.15) +#define ZOOMOUT_FACTOR (0.85) +#define ROTLEFT_DEG (-90.0) +#define ROTRIGHT_DEG (90.0) +#define IMG_CHUNK (16384) // in bytes + +#define IMAGE_BROWSER_NAME "FQLora [Image Companion for FQTerm]" +#define ICON_SOURCE "pic/ViewerButtons/" +#define POOL_SOURCE "pool/" +#define SHADOW_SOURCE "shadow-cache/" +#define TRASH_SOURCE ".Trash/" + +#define EMBLEM_LIKE "emblem-like.png" +#define EMBLEM_NEW "emblem-new.png" +#define EMBLEM_RECOVER "emblem-recover.png" +#define EMBLEM_TRASH "emblem-trash.png" +#define EMBLEM_TITLE "emblem-title.png" + + class FQTermConfig; + class FQTermFileDialog; + + + class FQTermImage : public QWidget { + Q_OBJECT; + public: + FQTermImage(QWidget * parent, Qt::WindowFlags f); + virtual void adjustItemSize() = 0; + virtual void scrollTo(const QString &) = 0; + virtual void updateImage(const QString &) = 0; + }; + + class ImageFlow; + class ImageMenu; + class ImageFlowItem; + + class FQTermImageFlow: public FQTermImage { + Q_OBJECT; + + public: + FQTermImageFlow(FQTermConfig *, QWidget *, Qt::WindowFlags); + ~FQTermImageFlow(); + + /* don't modify the funcs below */ + /* they are for API compatibiliy */ + void adjustItemSize(); + void scrollTo(const QString &); + void updateImage(const QString &); + /*********************************/ + + public slots: + void saveImages(void); + void clearImages(void); + void trashAllImages(void); + void recoverImages(void); + void showStatusMessage(const QString &message); + + private: + ImageFlow *imageFlow_; + ImageMenu *imageMenu_; + QStatusBar *statusBar_; + FQTermConfig *config_; + + QFileInfoList sortedList(const QString &path); + const QString& poolSource(void) const; + const QString& trashSource(void) const; + + private slots: + void loadImages(const int status); + void reshuffleImages(const int status); + void checkTrashState(void); + + signals: + void statusMessage(const QString &message); + void isTrashEmpty(void); + void trashStatus(const bool fullOrNot); + void saveStatus(const bool hasOrNot); + void clearStatus(const bool hasOrNot); + + protected: + void showEvent(QShowEvent *event); + void closeEvent(QCloseEvent *event); + }; + + class ImageMenu: public QLabel { + Q_OBJECT; + + public: + ImageMenu(QWidget *parent = 0); + ~ImageMenu(); + + public slots: + void updateEmblems(const int status); + void updateDustbin(const bool fullOrNot); + void updateSave(const bool hasOrNot); + void updateClear(const bool hasOrNot); + + signals: + void toggleFlowStatus(const int status); + void recoverImages(void); + void saveImages(void); + void clearImages(void); + + private: + class Private; + Private *fh; + + protected: + void paintEvent(QPaintEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + }; + + class ImageFlow: public PictureFlow { + Q_OBJECT; + Q_PROPERTY(QList itemsTitles READ itemsTitles); + + public: + ImageFlow(QWidget *parent); + ~ImageFlow(); + + const ImageFlowItem& operator[](int index) const; + ImageFlowItem& operator[](int index); + const ImageFlowItem& at(int index) const; + + QList& itemsTitles(void) const; + + QFileInfoList& digest(const int status); + void strip(const int status); + QList sort(const int status); + bool reorder(const QList& itemsKey); + + public slots: + void add(const ImageFlowItem &item); + void clear(void); + int count(void) const; + int size(void) const; + void rehash(void); + void toggleStatus(const int status); + void setCurrentImage(const int index); + + private: + class Private; + Private *m; + + signals: + void statusMessage(const QString &message); + void emblemStatus(const int status); + void saveStatus(const bool hasOrNot); + void clearStatus(const bool hasOrNot); + void titlesChanged(QList &titles); + + protected: + void paintEvent(QPaintEvent *event); + }; + + class ImageFlowItem: public QObject { + Q_OBJECT; + + Q_PROPERTY(qint64 key READ key); + Q_PROPERTY(int status READ status WRITE setStatus); + Q_PROPERTY(QImage image READ image WRITE setImage); + Q_PROPERTY(QFileInfo info READ info WRITE setInfo); + Q_PROPERTY(QString comment READ comment WRITE setComment); + + public: + ImageFlowItem(QObject *parent = 0); + ImageFlowItem(const ImageFlowItem &item); + ImageFlowItem(const QImage &image, QObject *parent = 0); + ImageFlowItem(const QImage &image, const QFileInfo &info, QObject *parent = 0); + ImageFlowItem(const QImage &image, const QFileInfo &info, const int state, QObject *parent = 0); + ImageFlowItem(const QImage &image, const QFileInfo &info, const QString &comment, QObject *parent = 0); + ImageFlowItem(const QImage &image, const QFileInfo &info, const QString& comment, const int status, QObject *parent = 0); + ~ImageFlowItem(); + + const QFileInfo& info(void) const; + const QString& comment(void) const; + const QImage& image(void) const; + int status(void) const; + qint64 key(void) const; + + ImageFlowItem& operator=(const ImageFlowItem &item); + bool operator==(const ImageFlowItem &item) const; + bool operator!=(const ImageFlowItem &item) const; + + public slots: + void setStatus(const int status); + void setInfo(const QFileInfo &info); + void setComment(const QString &comment); + void setImage(const QImage &image); + void setImage(const QString &filePath, int size); + + private slots: + void loadImage(void); + + private: + QImage resizeImage(const QImage &image, int size); + class Private; + Private *m; + + }; + +/////////////////////////////////////////////////////// +//////// the origin image viewer ////////////////////// +/////////////////////////////////////////////////////// + + class FQTermCanvas; + class ExifExtractor; + + class ItemDelegate : public QItemDelegate { + public: + ItemDelegate() { + size_ = QSize(250,200); + } + + QSize sizeHint (const QStyleOptionViewItem & option, const QModelIndex & index) const { + //if (index.column() == 0) return QSize(1, 1); + return size_; + } + + void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const; + static QSize size_; + }; + + class ExifTable : public QLabel { + Q_OBJECT; + + public: + ExifTable(QWidget *parent); + + signals: + void showExifDetails(); + + protected: + void mouseReleaseEvent(QMouseEvent *pEvent); + }; + + class ImageViewerDirModel : public QDirModel { + public: + ImageViewerDirModel(QObject *parent = 0); + + int columnCount(const QModelIndex & = QModelIndex()) const; + QVariant headerData ( int section, Qt::Orientation orientation, int role) const; + QVariant data(const QModelIndex &index, int role) const; + }; + + + class FQTermImageOrigin: public FQTermImage { + Q_OBJECT; + + public: + FQTermImageOrigin(FQTermConfig * config, QWidget *parent, Qt::WindowFlags wflag); + ~FQTermImageOrigin(); + void scrollTo(const QString& filename); + void updateImage(const QString& filename); + + public slots: + void onChange(const QModelIndex & index); + void next(); + void previous(); + void adjustItemSize(); + void selectionChanged(const QItemSelection & selected, const QItemSelection & deselected); + void sortFileList(int index); + void showFullExifInfo(); + void adjustLayout(bool withExifTable); + void updateExifInfo(); + + protected: + void closeEvent(QCloseEvent *clse); + + private: + FQTermCanvas* canvas_; + QTreeView* tree_; + ImageViewerDirModel* model_; + QMenuBar* menuBar_; + QComboBox* comboBox_; + FQTermConfig* config_; + ExifExtractor* exifExtractor_; + ExifTable* exifTable_; + QGridLayout* layout_; + bool isExifTableShown_; + }; + + +} // namespace FQTerm + +#endif // IMAGE_VIERWER_H diff --git a/src/ui/iplookup.cpp b/src/ui/iplookup.cpp new file mode 100644 index 0000000..e84c126 --- /dev/null +++ b/src/ui/iplookup.cpp @@ -0,0 +1,56 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#include "iplookup.h" +#include "fqterm_ip_location.h" +#include "fqterm.h" +namespace FQTerm { + + + +IPLookupDialog::~IPLookupDialog(){ + +} + +IPLookupDialog::IPLookupDialog( QWidget *parent_ /*= 0*/, Qt::WFlags fl /*= 0*/ ) : QDialog(parent_, fl) { + ui_.setupUi(this); + FQ_VERIFY(connect(ui_.lookupPushButton, SIGNAL(clicked()), this, SLOT(onLookup()))); + FQ_VERIFY(connect(ui_.finishedPushButton, SIGNAL(clicked()), this, SLOT(onFinished()))); +} + +void IPLookupDialog::onLookup() { + QString country, city; + QString ip = ui_.ipLineEdit->text(); + FQTermIPLocation *ipLocation = FQTermIPLocation::getInstance(); + if (ipLocation == NULL) { + ui_.addressLineEdit->setText(QApplication::translate("IPLookupDialog", "IP database file does NOT exist", 0, QApplication::UnicodeUTF8)); + } else if (!ipLocation->getLocation(ip, country, city)) { + ui_.addressLineEdit->setText(QApplication::translate("IPLookupDialog", "Invalid IP", 0, QApplication::UnicodeUTF8)); + } else { + ui_.addressLineEdit->setText(country + " " + city); + } +} + +void IPLookupDialog::onFinished() { + done(0); +} +} //namespace FQTerm + +#include "iplookup.moc" \ No newline at end of file diff --git a/src/ui/iplookup.h b/src/ui/iplookup.h new file mode 100644 index 0000000..4f38a5a --- /dev/null +++ b/src/ui/iplookup.h @@ -0,0 +1,43 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#ifndef __FQTERM_IPLOOKUP__ +#define __FQTERM_IPLOOKUP__ + +#include +#include "ui_iplookup.h" +namespace FQTerm { + +class IPLookupDialog : public QDialog { + Q_OBJECT; +public: + IPLookupDialog(QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~IPLookupDialog(); + +protected slots: + void onLookup(); + void onFinished(); +private: + Ui::IPLookupDialog ui_; +}; + +} //namespace FQTerm + +#endif //__FQTERM_IPLOOKUP__ \ No newline at end of file diff --git a/src/ui/iplookup.ui b/src/ui/iplookup.ui new file mode 100644 index 0000000..507a456 --- /dev/null +++ b/src/ui/iplookup.ui @@ -0,0 +1,76 @@ + + + IPLookupDialog + + + + 0 + 0 + 319 + 112 + + + + IP Lookup + + + + + + IP Address + + + + + + + + + + Physical Address + + + + + + + true + + + + + + + + + Lookup + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Finished + + + + + + + + + + diff --git a/src/ui/keydialog.cpp b/src/ui/keydialog.cpp new file mode 100644 index 0000000..2e3aadb --- /dev/null +++ b/src/ui/keydialog.cpp @@ -0,0 +1,285 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#include "fqterm_config.h" +#include "fqterm_path.h" +#include "fqterm_trace.h" + +#include "keydialog.h" + +namespace FQTerm { + +/* + * Constructs a keyDialog as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +keyDialog::keyDialog(FQTermConfig * config, QWidget *parent, Qt::WFlags fl) + : QDialog(parent, fl), + keyButtonGroup_(this), + config_(config) { + ui_.setupUi(this); + + keyButtonGroup_.addButton(ui_.radioButton1, 0); + keyButtonGroup_.addButton(ui_.radioButton2, 1); + keyButtonGroup_.addButton(ui_.radioButton3, 2); + + connectSlots(); + + loadName(); +} + +keyDialog::~keyDialog() { + // no need to delete child widgets, Qt does it all for us +} + + +void keyDialog::connectSlots() { + FQ_VERIFY(connect(ui_.nameListWidget, SIGNAL(currentRowChanged(int)), + this, SLOT(onNamechange(int)))); + FQ_VERIFY(connect(ui_.addButton, SIGNAL(clicked()), this, SLOT(onAdd()))); + FQ_VERIFY(connect(ui_.deleteButton, SIGNAL(clicked()), this, SLOT(onDelete()))); + FQ_VERIFY(connect(ui_.updateButton, SIGNAL(clicked()), this, SLOT(onUpdate()))); + FQ_VERIFY(connect(ui_.closeButton, SIGNAL(clicked()), this, SLOT(onClose()))); + FQ_VERIFY(connect(ui_.upButton, SIGNAL(clicked()), this, SLOT(onUp()))); + FQ_VERIFY(connect(ui_.downButton, SIGNAL(clicked()), this, SLOT(onDown()))); + FQ_VERIFY(connect(ui_.leftButton, SIGNAL(clicked()), this, SLOT(onLeft()))); + FQ_VERIFY(connect(ui_.rightButton, SIGNAL(clicked()), this, SLOT(onRight()))); + FQ_VERIFY(connect(ui_.enterButton, SIGNAL(clicked()), this, SLOT(onEnter()))); +// FQ_VERIFY(connect(&keyButtonGroup_, SIGNAL(buttonClicked(int)), this, SLOT(onSelect(int)))); + FQ_VERIFY(connect(ui_.scriptButton, SIGNAL(clicked()), this, SLOT(onChooseScript()))); + FQ_VERIFY(connect(ui_.programButton, SIGNAL(clicked()), this, SLOT(onProgram()))); + +} + +void keyDialog::onNamechange(int item) { + loadKey(item); +} + +void keyDialog::onAdd() { + QString strTmp = config_->getItemValue("key", "num"); + int num = strTmp.toInt(); + + strTmp.setNum(num + 1); + config_->setItemValue("key", "num", strTmp); + + QString strValue; + switch (keyButtonGroup_.checkedId()) { + case 0: + strValue = "0" + ui_.keyEdit->text(); + break; + case 1: + strValue = "1" + ui_.scriptEdit->text(); + break; + case 2: + strValue = "2" + ui_.programEdit->text(); + break; + } + strTmp = QString("key%1").arg(num); + config_->setItemValue("key", strTmp, strValue); + + strTmp = QString("name%1").arg(num); + config_->setItemValue("key", strTmp, ui_.nameEdit->text()); + + strTmp = QString("shortcut%1").arg(num); + config_->setItemValue("key", strTmp, ui_.shortcutEdit->text()); + + ui_.nameListWidget->addItem(ui_.nameEdit->text()); + ui_.nameListWidget->setCurrentRow(ui_.nameListWidget->count() -1); +} + +void keyDialog::onDelete() { + QString strTmp = config_->getItemValue("key", "num"); + int num = strTmp.toInt(); + if (num == 0) { + return ; + } + strTmp.setNum(num -1); + config_->setItemValue("key", "num", strTmp); + + int index = ui_.nameListWidget->currentRow(); + QString strItem1, strItem2; + for (int i = index; i < num -1; i++) { + strItem1 = QString("key%1").arg(i); + strItem2 = QString("key%1").arg(i + 1); + config_->setItemValue("key", strItem1, config_->getItemValue("key", strItem2)); + strItem1 = QString("name%1").arg(i); + strItem2 = QString("name%1").arg(i + 1); + config_->setItemValue("key", strItem1, config_->getItemValue("key", strItem2)); + } + + ui_.nameListWidget->takeItem(index); + ui_.nameListWidget->setCurrentRow(qMin(index, ui_.nameListWidget->count() -1)); +} + +void keyDialog::onUpdate() { + int index = ui_.nameListWidget->currentRow(); + if (index < 0) { + return ; + } + + QString strValue; + switch (keyButtonGroup_.checkedId()) { + case 0: + strValue = "0" + ui_.keyEdit->text(); + break; + case 1: + strValue = "1" + ui_.scriptEdit->text(); + break; + case 2: + strValue = "2" + ui_.programEdit->text(); + break; + } + + QString strTmp; + + strTmp = QString("key%1").arg(index); + config_->setItemValue("key", strTmp, strValue); + + strTmp = QString("name%1").arg(index); + config_->setItemValue("key", strTmp, ui_.nameEdit->text()); + + strTmp = QString("shortcut%1").arg(index); + config_->setItemValue("key", strTmp, ui_.shortcutEdit->text()); + + ui_.nameListWidget->item(index)->setText(ui_.nameEdit->text()); +} + +void keyDialog::onClose() { + config_->save(getPath(USER_CONFIG) + "fqterm.cfg"); + done(1); +} + +void keyDialog::onUp() { + ui_.keyEdit->insert("^[[A"); +} + +void keyDialog::onDown() { + ui_.keyEdit->insert("^[[B"); +} + +void keyDialog::onLeft() { + ui_.keyEdit->insert("^[[D"); +} + +void keyDialog::onRight() { + ui_.keyEdit->insert("^[[C"); +} + +void keyDialog::onEnter() { + ui_.keyEdit->insert("^M"); +} + +// void keyDialog::onSelect(int id) +// { +// switch(id) +// { +// case 0: // key +// ui.keyEdit->setEnabled(true); +// ui.scriptEdit->setEnabled(false); +// ui.scriptButton->setEnabled(false); +// ui.programEdit->setEnabled(false); +// ui.programButton->setEnabled(false); +// break; +// case 1: // script +// ui.keyEdit->setEnabled(false); +// ui.scriptEdit->setEnabled(true); +// ui.scriptButton->setEnabled(true); +// ui.programEdit->setEnabled(false); +// ui.programButton->setEnabled(false); +// break; +// case 2: // program +// ui.scriptEdit->setEnabled(false); +// ui.scriptButton->setEnabled(false); +// ui.keyEdit->setEnabled(false); +// ui.programEdit->setEnabled(true); +// ui.programButton->setEnabled(true); +// break; +// } +// } +void keyDialog::onChooseScript() { + QString script = QFileDialog::getOpenFileName( + this, "Select a script", QDir::currentPath(), "JavaScript File (*.js)"); + if (!script.isEmpty()) { + ui_.scriptEdit->setText(script); + } +} + +void keyDialog::onProgram() { + QString program = QFileDialog::getOpenFileName( + this, "Select a program", QDir::currentPath(), "*"); + if (!program.isNull()) { + ui_.programEdit->setText(program); + } +} + +void keyDialog::loadName() { + QString strTmp = config_->getItemValue("key", "num"); + int num = strTmp.toInt(); + for (int i = 0; i < num; i++) { + strTmp = QString("name%1").arg(i); + ui_.nameListWidget->addItem(config_->getItemValue("key", strTmp)); + } + if (num > 0) { + ui_.nameListWidget->setCurrentRow(0); + } else { + ui_.radioButton1->setChecked(true); + //onSelect(0); + } +} + +void keyDialog::loadKey(int n) { + QString strTmp = config_->getItemValue("key", "num"); + if (n >= strTmp.toInt()) { + return ; + } + + QString strItem; + + strItem = QString("name%1").arg(n); + ui_.nameEdit->setText(config_->getItemValue("key", strItem)); + + strItem = QString("key%1").arg(n); + strTmp = config_->getItemValue("key", strItem); + if (strTmp[0] == '0') { + ui_.keyEdit->setText(strTmp.mid(1)); + ui_.radioButton1->setChecked(true); + //onSelect(0); + } else if (strTmp[0] == '1') { + ui_.scriptEdit->setText(strTmp.mid(1)); + ui_.radioButton2->setChecked(true); + //onSelect(7); + } else if (strTmp[0] == '2') { + ui_.programEdit->setText(strTmp.mid(1)); + ui_.radioButton3->setChecked(true); + //onSelect(6); + } + strItem = QString("shortcut%1").arg(n); + strTmp = config_->getItemValue("key", strItem); + ui_.shortcutEdit->setText(strTmp); +} + +} // namespace FQTerm + +#include "keydialog.moc" diff --git a/src/ui/keydialog.h b/src/ui/keydialog.h new file mode 100644 index 0000000..fa087c3 --- /dev/null +++ b/src/ui/keydialog.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_KEY_DIALOG_H +#define FQTERM_KEY_DIALOG_H + +#include "ui_keydialog.h" + +namespace FQTerm { + +class FQTermConfig; + +class keyDialog: public QDialog { + Q_OBJECT; + public: + keyDialog(FQTermConfig *, QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~keyDialog(); + + protected: + void connectSlots(); + void loadKey(int); + void loadName(); + + protected slots: + void onNamechange(int); + void onClose(); + void onAdd(); + void onDelete(); + void onUpdate(); + void onChooseScript(); + void onProgram(); + void onUp(); + void onDown(); + void onLeft(); + void onRight(); + void onEnter(); + // void onSelect(int); + private: + Ui::keyDialog ui_; + QButtonGroup keyButtonGroup_; + FQTermConfig * config_; +}; + +} // namespace FQTerm + +#endif // FQTERM_KEY_DIALOG_H diff --git a/src/ui/keydialog.ui b/src/ui/keydialog.ui new file mode 100644 index 0000000..34b8124 --- /dev/null +++ b/src/ui/keydialog.ui @@ -0,0 +1,665 @@ + + keyDialog + + + + 0 + 0 + 545 + 463 + + + + Key Setup + + + + + + + + Add + + + + + + + Delete + + + + + + + Update + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + + + + + + Name + + + + + + + + + + Short Cut + + + + + + + + + + Define + + + + + + Key + + + + + + + + + + General Keys + + + + + + + Up + + + + + + + Down + + + + + + + Left + + + + + + + Right + + + + + + + Enter + + + + + + + Script + + + + + + + + + + Browse... + + + + + + + Program + + + + + + + + + + Browse... + + + + + + + + + + + + + radioButton1 + toggled(bool) + keyEdit + setEnabled(bool) + + + 69 + 230 + + + 109 + 230 + + + + + radioButton1 + toggled(bool) + upButton + setEnabled(bool) + + + 66 + 230 + + + 151 + 266 + + + + + radioButton1 + toggled(bool) + downButton + setEnabled(bool) + + + 20 + 237 + + + 234 + 267 + + + + + radioButton1 + toggled(bool) + leftButton + setEnabled(bool) + + + 69 + 230 + + + 299 + 263 + + + + + radioButton1 + toggled(bool) + rightButton + setEnabled(bool) + + + 50 + 230 + + + 359 + 265 + + + + + radioButton1 + toggled(bool) + enterButton + setEnabled(bool) + + + 64 + 230 + + + 417 + 264 + + + + + radioButton1 + toggled(bool) + scriptEdit + setDisabled(bool) + + + 20 + 246 + + + 124 + 314 + + + + + radioButton1 + toggled(bool) + scriptButton + setDisabled(bool) + + + 41 + 230 + + + 362 + 293 + + + + + radioButton1 + toggled(bool) + programEdit + setDisabled(bool) + + + 20 + 245 + + + 111 + 354 + + + + + radioButton1 + toggled(bool) + programButton + setDisabled(bool) + + + 64 + 230 + + + 409 + 343 + + + + + radioButton2 + toggled(bool) + keyEdit + setDisabled(bool) + + + 20 + 296 + + + 101 + 230 + + + + + radioButton2 + toggled(bool) + upButton + setDisabled(bool) + + + 85 + 290 + + + 142 + 284 + + + + + radioButton2 + toggled(bool) + downButton + setDisabled(bool) + + + 20 + 307 + + + 205 + 277 + + + + + radioButton2 + toggled(bool) + leftButton + setDisabled(bool) + + + 21 + 290 + + + 299 + 277 + + + + + radioButton2 + toggled(bool) + rightButton + setDisabled(bool) + + + 25 + 290 + + + 359 + 284 + + + + + radioButton2 + toggled(bool) + enterButton + setDisabled(bool) + + + 81 + 290 + + + 419 + 266 + + + + + radioButton2 + toggled(bool) + scriptEdit + setEnabled(bool) + + + 76 + 290 + + + 119 + 290 + + + + + radioButton2 + toggled(bool) + scriptButton + setEnabled(bool) + + + 82 + 290 + + + 341 + 290 + + + + + radioButton2 + toggled(bool) + programEdit + setDisabled(bool) + + + 20 + 294 + + + 113 + 354 + + + + + radioButton2 + toggled(bool) + programButton + setDisabled(bool) + + + 83 + 305 + + + 346 + 354 + + + + + radioButton3 + toggled(bool) + keyEdit + setDisabled(bool) + + + 20 + 339 + + + 116 + 248 + + + + + radioButton3 + toggled(bool) + upButton + setDisabled(bool) + + + 20 + 349 + + + 173 + 271 + + + + + radioButton3 + toggled(bool) + downButton + setDisabled(bool) + + + 96 + 349 + + + 200 + 284 + + + + + radioButton3 + toggled(bool) + leftButton + setDisabled(bool) + + + 20 + 349 + + + 299 + 270 + + + + + radioButton3 + toggled(bool) + rightButton + setDisabled(bool) + + + 20 + 349 + + + 359 + 275 + + + + + radioButton3 + toggled(bool) + enterButton + setDisabled(bool) + + + 90 + 349 + + + 419 + 277 + + + + + radioButton3 + toggled(bool) + scriptEdit + setDisabled(bool) + + + 77 + 349 + + + 269 + 312 + + + + + radioButton3 + toggled(bool) + scriptButton + setDisabled(bool) + + + 98 + 333 + + + 346 + 309 + + + + + radioButton3 + toggled(bool) + programEdit + setEnabled(bool) + + + 72 + 349 + + + 128 + 349 + + + + + radioButton3 + toggled(bool) + programButton + setEnabled(bool) + + + 73 + 335 + + + 342 + 335 + + + + + diff --git a/src/ui/msgdialog.cpp b/src/ui/msgdialog.cpp new file mode 100644 index 0000000..1db7495 --- /dev/null +++ b/src/ui/msgdialog.cpp @@ -0,0 +1,43 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#include "msgdialog.h" + +msgDialog::msgDialog(QWidget *parent, Qt::WFlags fl) + : QDialog(parent, fl) { + ui_.setupUi(this); + // signals and slots connections + //QVERIFY(connect( okButton, SIGNAL( clicked() ), this, SLOT( accept() ) )); +} + +/* + * Destroys the object and frees any allocated resources + */ +msgDialog::~msgDialog() { + // no need to delete child widgets, Qt does it all for us +} + +void msgDialog::setMessageText(const QString& message) { + ui_.msgBrowser->setPlainText(message); +} + +#include "msgdialog.moc" diff --git a/src/ui/msgdialog.h b/src/ui/msgdialog.h new file mode 100644 index 0000000..e3c5185 --- /dev/null +++ b/src/ui/msgdialog.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_MSGDIALOG_H +#define FQTERM_MSGDIALOG_H + +#include "ui_msgdialog.h" + +class msgDialog: public QDialog { + Q_OBJECT; +public: + msgDialog(QWidget *parent = 0, Qt::WFlags fl = 0); + ~msgDialog(); + void setMessageText(const QString& message); + Ui::msgDialog ui_; +}; + +#endif // FQTERM_MSGDIALOG_H diff --git a/src/ui/msgdialog.ui b/src/ui/msgdialog.ui new file mode 100644 index 0000000..93ff1c4 --- /dev/null +++ b/src/ui/msgdialog.ui @@ -0,0 +1,86 @@ + + msgDialog + + + + 0 + 0 + 586 + 393 + + + + Messages Viewer + + + + 9 + + + 6 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + OK + + + + + + + + + + okButton + clicked() + msgDialog + accept() + + + 311 + 403 + + + 396 + 403 + + + + + diff --git a/src/ui/osdmessage.cpp b/src/ui/osdmessage.cpp new file mode 100644 index 0000000..1b0883f --- /dev/null +++ b/src/ui/osdmessage.cpp @@ -0,0 +1,210 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "fqterm_trace.h" +#include "fqterm_path.h" + +#include "osdmessage.h" + +namespace FQTerm { + +PageViewMessage::PageViewMessage(QWidget *parent_) + : QWidget(parent_), + timer_(0), + message_() { + setFocusPolicy(Qt::NoFocus); + //setBackgroundMode( Qt::NoBackground ); + QPalette palette; + palette.setColor(backgroundRole(), qApp->palette().color(QPalette::Active, + QPalette::Background)); + setPalette(palette); + // setPaletteBackgroundColor(qApp->palette().color(QPalette::Active, QPalette::Background)); + setCursor(QCursor(Qt::ArrowCursor)); + move(10, 10); + resize(0, 0); + hide(); +} + +// give to Caesar what Caesar owns: code taken from Amarok's osd.h/.cpp +// "redde (reddite, pl.) cesari quae sunt cesaris", just btw. ;) +void PageViewMessage::display(const QString &message, Icon icon, int durationMs, QPoint pos, PageViewMessage::Alignment ali) +{ + displayImpl(message, icon, false, durationMs, pos, ali); +} + +void PageViewMessage::display(const QString &message, QPoint pos, Icon icon) +{ + displayImpl(message, icon, false, 4000, pos, TopLeft); +} + +QRect PageViewMessage::displayCheck(const QString &message, Icon icon) +{ + return displayImpl(message, icon, true); +} + +QRect PageViewMessage::displayImpl(const QString &message, Icon icon, bool check, int durationMs, QPoint pos, Alignment ali) +{ + //FIXME: add a option in fqterm too. + /* + if ( !KpdfSettings::showOSD() ) + { + hide(); + return; + } + */ + // determine text rectangle + + if (!isHidden() && message == message_) { + timer_->setSingleShot(true); + timer_->start(durationMs); + return QRect(QPoint(0, 0), size()); + } + message_ = message; + QRect textRect = fontMetrics().boundingRect(message); + textRect.translate(-textRect.left(), -textRect.top()); + textRect.adjust(0, 0, 2, 2); + int width = textRect.width(), height = textRect.height(), textXOffset = 0, + shadowOffset = message.isRightToLeft() ? -1: 1; + + // load icon (if set) and update geometry + // [FQTerm], we don't have a icon at this time. + + QPixmap symbol; + if (icon != None) { + switch (icon) { + //case Find: + //symbol = SmallIcon( "viewmag" ); + //break; + case Error: + symbol = QPixmap(getPath(RESOURCE) + "pic/messagebox_critical.png"); + break; + case Warning: + symbol = QPixmap(getPath(RESOURCE) + "pic/messagebox_warning.png"); + break; + default: + symbol = QPixmap(getPath(RESOURCE) + "pic/messagebox_info.png"); + break; + } + textXOffset = 2+symbol.width(); + width += textXOffset; + height = qMax(height, symbol.height()); + } + + QRect geometry(0, 0, width + 10, height + 8); + + if (check) + return geometry; + + // resize pixmap, mask and widget + static QPixmap mask; + mask = QPixmap(geometry.size()); + pixmap_ = QPixmap(geometry.size()); + resize(geometry.size()); + + switch(ali) + { + case TopLeft: + move(pos); + break; + case TopRight: + move(pos - geometry.topRight()); + break; + case BottomLeft: + move(pos - geometry.bottomLeft()); + break; + case BottomRight: + move(pos - geometry.bottomRight()); + break; + } + + // create and set transparency mask + QPainter maskPainter(&mask); + mask.fill(Qt::black); + maskPainter.setBrush(Qt::white); + maskPainter.drawRoundRect(geometry, 1600 / geometry.width(), 1600 / + geometry.height()); + setMask(mask.createHeuristicMask()); + + // draw background + QPainter bufferPainter(&pixmap_); + bufferPainter.setPen(Qt::black); + bufferPainter.setBrush(palette().brush(QPalette::Window)); + bufferPainter.drawRoundRect(geometry, 1600 / geometry.width(), 1600 / + geometry.height()); + + // draw icon if present + if (!symbol.isNull()) { + bufferPainter.drawPixmap(5, 4, symbol, 0, 0, symbol.width(), symbol.height()); + } + + // draw shadow and text + int yText = geometry.height() - height / 2; + bufferPainter.setPen(palette().color(QPalette::Window).dark(115)); + bufferPainter.drawText(5+textXOffset + shadowOffset, yText + 1, message); + bufferPainter.setPen(palette().color(QPalette::WindowText)); + bufferPainter.drawText(5+textXOffset, yText, message); + + // show widget and schedule a repaint + show(); + update(); + + // close the message window after given mS + if (durationMs > 0) { + if (!timer_) { + timer_ = new QTimer(this); + timer_->setSingleShot(true); + FQ_VERIFY(connect(timer_, SIGNAL(timeout()), SLOT(hide()))); + } + timer_->start(durationMs); + } else if (timer_) { + timer_->stop(); + } + + return QRect(QPoint(0, 0), size()); +} + +void PageViewMessage::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.drawPixmap(e->rect().topLeft(), pixmap_, e->rect()); +} + +void PageViewMessage::mousePressEvent(QMouseEvent * /*e*/) { + if (timer_) { + timer_->stop(); + } + hide(); +} + +void PageViewMessage::hideEvent( QHideEvent * event ) { + emit hideAt(geometry ()); + QWidget::hideEvent(event); +} + +} // namespace FQTerm + +#include "osdmessage.moc" diff --git a/src/ui/osdmessage.h b/src/ui/osdmessage.h new file mode 100644 index 0000000..fe29d4d --- /dev/null +++ b/src/ui/osdmessage.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_OSD_MESSAGE_H +#define FQTERM_OSD_MESSAGE_H + +#include +#include +#include + +namespace FQTerm { + +/** + * A widget that displays messages in the top-left corner. + */ +class PageViewMessage: public QWidget { + Q_OBJECT; + public: + PageViewMessage(QWidget *parent_); + + enum Alignment { + TopLeft, TopRight, BottomLeft, BottomRight + }; + enum Icon { + None, Info, Warning, Error, Find + }; + void display(const QString &message, Icon icon = Info, int durationMs = 4000, + QPoint pos = QPoint(10, 10), Alignment ali = TopLeft); + void display(const QString &message, QPoint pos, Icon icon = Info); + QRect displayCheck(const QString &message, Icon icon = Info); + public slots: + void showText(const QString &message){ + display(message); + } + protected: + void paintEvent(QPaintEvent *e); + void mousePressEvent(QMouseEvent *e); + QRect displayImpl(const QString &message, Icon icon = Info, + bool check = false, int durationMs = 4000, + QPoint pos = QPoint(10, 10), Alignment ali = TopLeft); + void hideEvent(QHideEvent * event); + private: + QPixmap pixmap_; + QTimer *timer_; + QString message_; +signals: + void hideAt(const QRect& rect); +}; + +} // namespace FQTerm + +#endif // FQTERM_OSD_MESSAGE_H diff --git a/src/ui/overlayWidget.cpp b/src/ui/overlayWidget.cpp new file mode 100644 index 0000000..74f0659 --- /dev/null +++ b/src/ui/overlayWidget.cpp @@ -0,0 +1,84 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "overlayWidget.h" + +namespace FQTerm { + +OverlayWidget::OverlayWidget(QWidget *parent, QWidget *anchor) + : QFrame(parent->parentWidget()->parentWidget()), + anchor_(anchor), + parent_(parent) { + parent->installEventFilter(this); + + hide(); +} + +void OverlayWidget::reposition() { + setMaximumSize(parentWidget()->size()); + adjustSize(); + + // p is in the alignWidget's coordinates + QPoint p; + + p.setX(anchor_->width() - width()); + p.setY(-height()); + + // Position in the toplevelwidget's coordinates + QPoint pTopLevel = anchor_->mapTo(topLevelWidget(), p); + + // Position in the widget's parentWidget coordinates + QPoint pParent = parentWidget()->mapFrom(topLevelWidget(), pTopLevel); + // keep it on the screen + if (pParent.x() < 0) { + pParent.rx() = 0; + } + + // Move 'this' to that position. + move(pParent); +} + +bool OverlayWidget::eventFilter(QObject *o, QEvent *e) { + if (e->type() == QEvent::Move || e->type() == QEvent::Resize) { + reposition(); + } + + return QFrame::eventFilter(o, e); +} + +void OverlayWidget::resizeEvent(QResizeEvent *ev) { + reposition(); + QFrame::resizeEvent(ev); +} + +bool OverlayWidget::event(QEvent *e) { + if (e->type() == QEvent::ChildAdded) { + adjustSize(); + } + + return QFrame::event(e); +} + +} diff --git a/src/ui/overlayWidget.h b/src/ui/overlayWidget.h new file mode 100644 index 0000000..edab3f6 --- /dev/null +++ b/src/ui/overlayWidget.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERMOVERLAYWIDGET_H +#define FQTERMOVERLAYWIDGET_H + +#include +#include +#include +#include + +namespace FQTerm { +class OverlayWidget: public QFrame { + public: + /** + * The widget is parented to the toplevelwidget of alignWidget, + * this could be an issue if that widget has an autoAdd Layout + */ + OverlayWidget(QWidget *parent, QWidget *anchor); + virtual void reposition(); + + protected: + virtual void resizeEvent(QResizeEvent*); + virtual bool eventFilter(QObject *, QEvent*); + virtual bool event(QEvent*); + + private: + QWidget *anchor_; + QWidget *parent_; +}; + +} // namespace FQTerm + +#endif // FQTERMOVERLAYWIDGET_H diff --git a/src/ui/pictureflow.cpp b/src/ui/pictureflow.cpp new file mode 100644 index 0000000..cd749f0 --- /dev/null +++ b/src/ui/pictureflow.cpp @@ -0,0 +1,1201 @@ + +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* + PictureFlow - animated image show widget + http://pictureflow.googlecode.com + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "pictureflow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// uncomment this to enable bilinear filtering for texture mapping +// gives much better rendering, at the cost of memory space +// #define PICTUREFLOW_BILINEAR_FILTER + +// for fixed-point arithmetic, we need minimum 32-bit long +// long long (64-bit) might be useful for multiplication and division +typedef long PFreal; +#define PFREAL_SHIFT 10 +#define PFREAL_FACTOR (1 << PFREAL_SHIFT) +#define PFREAL_ONE (1 << PFREAL_SHIFT) +#define PFREAL_HALF (PFREAL_ONE >> 1) + +inline PFreal fmul(PFreal a, PFreal b) +{ + return ((long long)(a))*((long long)(b)) >> PFREAL_SHIFT; +} + +inline PFreal fdiv(PFreal num, PFreal den) +{ + long long p = (long long)(num) << (PFREAL_SHIFT*2); + long long q = p / (long long)den; + long long r = q >> PFREAL_SHIFT; + + return r; +} + +#define IANGLE_MAX 1024 +#define IANGLE_MASK 1023 + +// warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed! +static const PFreal sinTable[IANGLE_MAX] = { + 3, 9, 15, 21, 28, 34, 40, 47, + 53, 59, 65, 72, 78, 84, 90, 97, + 103, 109, 115, 122, 128, 134, 140, 147, + 153, 159, 165, 171, 178, 184, 190, 196, + 202, 209, 215, 221, 227, 233, 239, 245, + 251, 257, 264, 270, 276, 282, 288, 294, + 300, 306, 312, 318, 324, 330, 336, 342, + 347, 353, 359, 365, 371, 377, 383, 388, + 394, 400, 406, 412, 417, 423, 429, 434, + 440, 446, 451, 457, 463, 468, 474, 479, + 485, 491, 496, 501, 507, 512, 518, 523, + 529, 534, 539, 545, 550, 555, 561, 566, + 571, 576, 581, 587, 592, 597, 602, 607, + 612, 617, 622, 627, 632, 637, 642, 647, + 652, 656, 661, 666, 671, 675, 680, 685, + 690, 694, 699, 703, 708, 712, 717, 721, + 726, 730, 735, 739, 743, 748, 752, 756, + 760, 765, 769, 773, 777, 781, 785, 789, + 793, 797, 801, 805, 809, 813, 816, 820, + 824, 828, 831, 835, 839, 842, 846, 849, + 853, 856, 860, 863, 866, 870, 873, 876, + 879, 883, 886, 889, 892, 895, 898, 901, + 904, 907, 910, 913, 916, 918, 921, 924, + 927, 929, 932, 934, 937, 939, 942, 944, + 947, 949, 951, 954, 956, 958, 960, 963, + 965, 967, 969, 971, 973, 975, 977, 978, + 980, 982, 984, 986, 987, 989, 990, 992, + 994, 995, 997, 998, 999, 1001, 1002, 1003, + 1004, 1006, 1007, 1008, 1009, 1010, 1011, 1012, + 1013, 1014, 1015, 1015, 1016, 1017, 1018, 1018, + 1019, 1019, 1020, 1020, 1021, 1021, 1022, 1022, + 1022, 1023, 1023, 1023, 1023, 1023, 1023, 1023, + 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1022, + 1022, 1022, 1021, 1021, 1020, 1020, 1019, 1019, + 1018, 1018, 1017, 1016, 1015, 1015, 1014, 1013, + 1012, 1011, 1010, 1009, 1008, 1007, 1006, 1004, + 1003, 1002, 1001, 999, 998, 997, 995, 994, + 992, 990, 989, 987, 986, 984, 982, 980, + 978, 977, 975, 973, 971, 969, 967, 965, + 963, 960, 958, 956, 954, 951, 949, 947, + 944, 942, 939, 937, 934, 932, 929, 927, + 924, 921, 918, 916, 913, 910, 907, 904, + 901, 898, 895, 892, 889, 886, 883, 879, + 876, 873, 870, 866, 863, 860, 856, 853, + 849, 846, 842, 839, 835, 831, 828, 824, + 820, 816, 813, 809, 805, 801, 797, 793, + 789, 785, 781, 777, 773, 769, 765, 760, + 756, 752, 748, 743, 739, 735, 730, 726, + 721, 717, 712, 708, 703, 699, 694, 690, + 685, 680, 675, 671, 666, 661, 656, 652, + 647, 642, 637, 632, 627, 622, 617, 612, + 607, 602, 597, 592, 587, 581, 576, 571, + 566, 561, 555, 550, 545, 539, 534, 529, + 523, 518, 512, 507, 501, 496, 491, 485, + 479, 474, 468, 463, 457, 451, 446, 440, + 434, 429, 423, 417, 412, 406, 400, 394, + 388, 383, 377, 371, 365, 359, 353, 347, + 342, 336, 330, 324, 318, 312, 306, 300, + 294, 288, 282, 276, 270, 264, 257, 251, + 245, 239, 233, 227, 221, 215, 209, 202, + 196, 190, 184, 178, 171, 165, 159, 153, + 147, 140, 134, 128, 122, 115, 109, 103, + 97, 90, 84, 78, 72, 65, 59, 53, + 47, 40, 34, 28, 21, 15, 9, 3, + -4, -10, -16, -22, -29, -35, -41, -48, + -54, -60, -66, -73, -79, -85, -91, -98, + -104, -110, -116, -123, -129, -135, -141, -148, + -154, -160, -166, -172, -179, -185, -191, -197, + -203, -210, -216, -222, -228, -234, -240, -246, + -252, -258, -265, -271, -277, -283, -289, -295, + -301, -307, -313, -319, -325, -331, -337, -343, + -348, -354, -360, -366, -372, -378, -384, -389, + -395, -401, -407, -413, -418, -424, -430, -435, + -441, -447, -452, -458, -464, -469, -475, -480, + -486, -492, -497, -502, -508, -513, -519, -524, + -530, -535, -540, -546, -551, -556, -562, -567, + -572, -577, -582, -588, -593, -598, -603, -608, + -613, -618, -623, -628, -633, -638, -643, -648, + -653, -657, -662, -667, -672, -676, -681, -686, + -691, -695, -700, -704, -709, -713, -718, -722, + -727, -731, -736, -740, -744, -749, -753, -757, + -761, -766, -770, -774, -778, -782, -786, -790, + -794, -798, -802, -806, -810, -814, -817, -821, + -825, -829, -832, -836, -840, -843, -847, -850, + -854, -857, -861, -864, -867, -871, -874, -877, + -880, -884, -887, -890, -893, -896, -899, -902, + -905, -908, -911, -914, -917, -919, -922, -925, + -928, -930, -933, -935, -938, -940, -943, -945, + -948, -950, -952, -955, -957, -959, -961, -964, + -966, -968, -970, -972, -974, -976, -978, -979, + -981, -983, -985, -987, -988, -990, -991, -993, + -995, -996, -998, -999, -1000, -1002, -1003, -1004, + -1005, -1007, -1008, -1009, -1010, -1011, -1012, -1013, + -1014, -1015, -1016, -1016, -1017, -1018, -1019, -1019, + -1020, -1020, -1021, -1021, -1022, -1022, -1023, -1023, + -1023, -1024, -1024, -1024, -1024, -1024, -1024, -1024, + -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1023, + -1023, -1023, -1022, -1022, -1021, -1021, -1020, -1020, + -1019, -1019, -1018, -1017, -1016, -1016, -1015, -1014, + -1013, -1012, -1011, -1010, -1009, -1008, -1007, -1005, + -1004, -1003, -1002, -1000, -999, -998, -996, -995, + -993, -991, -990, -988, -987, -985, -983, -981, + -979, -978, -976, -974, -972, -970, -968, -966, + -964, -961, -959, -957, -955, -952, -950, -948, + -945, -943, -940, -938, -935, -933, -930, -928, + -925, -922, -919, -917, -914, -911, -908, -905, + -902, -899, -896, -893, -890, -887, -884, -880, + -877, -874, -871, -867, -864, -861, -857, -854, + -850, -847, -843, -840, -836, -832, -829, -825, + -821, -817, -814, -810, -806, -802, -798, -794, + -790, -786, -782, -778, -774, -770, -766, -761, + -757, -753, -749, -744, -740, -736, -731, -727, + -722, -718, -713, -709, -704, -700, -695, -691, + -686, -681, -676, -672, -667, -662, -657, -653, + -648, -643, -638, -633, -628, -623, -618, -613, + -608, -603, -598, -593, -588, -582, -577, -572, + -567, -562, -556, -551, -546, -540, -535, -530, + -524, -519, -513, -508, -502, -497, -492, -486, + -480, -475, -469, -464, -458, -452, -447, -441, + -435, -430, -424, -418, -413, -407, -401, -395, + -389, -384, -378, -372, -366, -360, -354, -348, + -343, -337, -331, -325, -319, -313, -307, -301, + -295, -289, -283, -277, -271, -265, -258, -252, + -246, -240, -234, -228, -222, -216, -210, -203, + -197, -191, -185, -179, -172, -166, -160, -154, + -148, -141, -135, -129, -123, -116, -110, -104, + -98, -91, -85, -79, -73, -66, -60, -54, + -48, -41, -35, -29, -22, -16, -10, -4 +}; + +// this is the program the generate the above table +#if 0 +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define PFREAL_ONE 1024 +#define IANGLE_MAX 1024 + +int main(int, char**) +{ + FILE*f = fopen("table.c","wt"); + fprintf(f,"PFreal sinTable[] = {\n"); + for(int i = 0; i < 128; ++i) + { + for(int j = 0; j < 8; ++j) + { + int iang = j+i*8; + double ii = (double)iang + 0.5; + double angle = ii * 2 * M_PI / IANGLE_MAX; + double sinAngle = sin(angle); + fprintf(f,"%6d, ", (int)(floor(PFREAL_ONE*sinAngle))); + } + fprintf(f,"\n"); + } + fprintf(f,"};\n"); + fclose(f); + + return 0; +} +#endif + +inline PFreal fsin(int iangle) +{ + while(iangle < 0) + iangle += IANGLE_MAX; + return sinTable[iangle & IANGLE_MASK]; +} + +inline PFreal fcos(int iangle) +{ + // quarter phase shift + return fsin(iangle + (IANGLE_MAX >> 2)); +} + +namespace FQTerm { + +struct SlideInfo +{ + int slideIndex; + int angle; + PFreal cx; + PFreal cy; +}; + +class PictureFlowPrivate +{ +public: + PictureFlowPrivate(PictureFlow* widget); + + int slideCount() const; + void setSlideCount(int count); + + QSize slideSize() const; + void setSlideSize(QSize size); + + int zoomFactor() const; + void setZoomFactor(int z); + + QImage slide(int index) const; + void setSlide(int index, const QImage& image); + + int currentSlide() const; + void setCurrentSlide(int index); + + void showPrevious(); + void showNext(); + void showSlide(int index); + + void resize(int w, int h); + + void render(); + void startAnimation(); + void updateAnimation(); + + QImage buffer; + QBasicTimer animateTimer; + QVector slidesRect; + +private: + PictureFlow* widget; + + int slideWidth; + int slideHeight; + int zoom; + + QVector slideImages; + int centerIndex; + + SlideInfo centerSlide; + QVector leftSlides; + QVector rightSlides; + + QVector rays; + int itilt; + int spacing; + PFreal offsetX; + PFreal offsetY; + + QImage blankSurface; + QCache surfaceCache; + QTimer triggerTimer; + + int slideFrame; + int step; + int target; + int fade; + + void recalc(int w, int h); + QRect renderSlide(const SlideInfo &slide, int alpha=256, int col1=-1, int col=-1); + QImage* surface(int slideIndex); + void triggerRender(); + void resetSlides(); +}; + +PictureFlowPrivate::PictureFlowPrivate(PictureFlow* w) +{ + widget = w; + + slideWidth = 200; + slideHeight = 200; + zoom = 100; + + centerIndex = 0; + + slideFrame = 0; + step = 0; + target = 0; + fade = 256; + + triggerTimer.setSingleShot(true); + triggerTimer.setInterval(0); + QObject::connect(&triggerTimer, SIGNAL(timeout()), widget, SLOT(render())); + + recalc(200, 200); + resetSlides(); +} + +int PictureFlowPrivate::slideCount() const +{ + return slideImages.count(); +} + +void PictureFlowPrivate::setSlideCount(int count) +{ + slideImages.resize(count); + surfaceCache.clear(); + resetSlides(); + triggerRender(); +} + +QSize PictureFlowPrivate::slideSize() const +{ + return QSize(slideWidth, slideHeight); +} + +void PictureFlowPrivate::setSlideSize(QSize size) +{ + slideWidth = size.width(); + slideHeight = size.height(); + recalc(buffer.width(), buffer.height()); + triggerRender(); +} + +int PictureFlowPrivate::zoomFactor() const +{ + return zoom; +} + +void PictureFlowPrivate::setZoomFactor(int z) +{ + if(z <= 0) + return; + + zoom = z; + recalc(buffer.width(), buffer.height()); + triggerRender(); +} + +QImage PictureFlowPrivate::slide(int index) const +{ + return slideImages[index]; +} + +void PictureFlowPrivate::setSlide(int index, const QImage& image) +{ + if((index >= 0) && (index < slideImages.count())) + { + slideImages[index] = image; + surfaceCache.remove(index); + triggerRender(); + } +} + +int PictureFlowPrivate::currentSlide() const +{ + return centerIndex; +} + +void PictureFlowPrivate::setCurrentSlide(int index) +{ + step = 0; + centerIndex = qBound(index, 0, slideImages.count()-1); + target = centerIndex; + slideFrame = index << 16; + resetSlides(); + triggerRender(); +} + +void PictureFlowPrivate::showPrevious() +{ + if(step >= 0) + { + if(centerIndex > 0) + { + target = centerIndex - 1; + startAnimation(); + } + } + else + { + target = qMax(0, centerIndex - 2); + } +} + +void PictureFlowPrivate::showNext() +{ + if(step <= 0) + { + if(centerIndex < slideImages.count()-1) + { + target = centerIndex + 1; + startAnimation(); + } + } + else + { + target = qMin(centerIndex + 2, slideImages.count()-1); + } +} + +void PictureFlowPrivate::showSlide(int index) +{ + index = qMax(index, 0); + index = qMin(slideImages.count()-1, index); + + target = index; + startAnimation(); +} + +void PictureFlowPrivate::resize(int w, int h) +{ + recalc(w, h); + resetSlides(); + triggerRender(); +} + + +// adjust slides so that they are in "steady state" position +void PictureFlowPrivate::resetSlides() +{ + centerSlide.angle = 0; + centerSlide.cx = 0; + centerSlide.cy = 0; + centerSlide.slideIndex = centerIndex; + + leftSlides.clear(); + leftSlides.resize(6); + for(int i = 0; i < leftSlides.count(); ++i) + { + SlideInfo& si = leftSlides[i]; + si.angle = itilt; + si.cx = -(offsetX + spacing*i*PFREAL_ONE); + si.cy = offsetY; + si.slideIndex = centerIndex-1-i; + } + + rightSlides.clear(); + rightSlides.resize(6); + for(int i = 0; i < rightSlides.count(); ++i) + { + SlideInfo& si = rightSlides[i]; + si.angle = -itilt; + si.cx = offsetX + spacing*i*PFREAL_ONE; + si.cy = offsetY; + si.slideIndex = centerIndex+1+i; + } +} + +#define BILINEAR_STRETCH_HOR 4 +#define BILINEAR_STRETCH_VER 4 + +static QImage scaleImage (QImage image, int w, int h) { + // I don't have to scale it + if (w == image.width() && h == image.height()) + return(image); + + QImage output(w, h, QImage::Format_ARGB32_Premultiplied); + output.fill(0); + + double scaleHeight = w / (double) image.height(); + double scaleWidth = h / (double) image.width(); + + double s = qMin(scaleWidth, scaleHeight); + + int sw = (int) qRound(s * image.width()); + int sh = (int) qRound(s * image.height()); + + // Scale Image + QImage imgScaled = image.scaled(sw, sh, Qt::KeepAspectRatio, Qt::SmoothTransformation); + + int _x = (w - sw) / 2; + int _y = (h - sh); + + for (int x = 0; x < imgScaled.width(); ++x) { + for (int y = 0; y < imgScaled.height(); ++y) { + output.setPixel(x + _x, y + _y, imgScaled.pixel(x, y)); + } + } + + return(output); +} + +static QImage prepareSurface(QImage img, int w, int h) +{ + img = scaleImage(img, w, h); + + // slightly larger, to accomodate for the reflection + int hs = h * 2; + int hofs = h / 3; + + // offscreen buffer: black is sweet + QImage result(hs, w, QImage::Format_RGB32); + result.fill(0); + + // transpose the image, this is to speed-up the rendering + // because we process one column at a time + // (and much better and faster to work row-wise, i.e in one scanline) + for(int x = 0; x < w; x++) + for(int y = 0; y < h; y++) + result.setPixel(hofs + y, x, img.pixel(x, y)); + + // create the reflection + int ht = hs - h - hofs; + int hte = ht; + for(int x = 0; x < w; x++) + for(int y = 0; y < ht; y++) + { + QRgb color = img.pixel(x, img.height()-y-1); + int a = qAlpha(color); + int r = qRed(color) * a / 256 * (hte - y) / hte * 3/5; + int g = qGreen(color) * a / 256 * (hte - y) / hte * 3/5; + int b = qBlue(color) * a / 256 * (hte - y) / hte * 3/5; + result.setPixel(h+hofs+y, x, qRgb(r, g, b)); + } + +#ifdef PICTUREFLOW_BILINEAR_FILTER + int hh = BILINEAR_STRETCH_VER*hs; + int ww = BILINEAR_STRETCH_HOR*w; + result = scaleImage(result, hh, ww); +#endif + + return result; +} + + +// get transformed image for specified slide +// if it does not exist, create it and place it in the cache +QImage* PictureFlowPrivate::surface(int slideIndex) +{ + if(slideIndex < 0) + return 0; + if(slideIndex >= slideImages.count()) + return 0; + + if(surfaceCache.contains(slideIndex)) + return surfaceCache[slideIndex]; + + QImage img = widget->slide(slideIndex); + if(img.isNull()) + { + if(blankSurface.isNull()) + { + blankSurface = QImage(slideWidth, slideHeight, QImage::Format_RGB32); + + QPainter painter(&blankSurface); + QPoint p1(slideWidth*4/10, 0); + QPoint p2(slideWidth*6/10, slideHeight); + QLinearGradient linearGrad(p1, p2); + linearGrad.setColorAt(0, Qt::black); + linearGrad.setColorAt(1, Qt::white); + painter.setBrush(linearGrad); + painter.fillRect(0, 0, slideWidth, slideHeight, QBrush(linearGrad)); + + painter.setPen(QPen(QColor(64,64,64), 4)); + painter.setBrush(QBrush()); + painter.drawRect(2, 2, slideWidth-3, slideHeight-3); + painter.end(); + blankSurface = prepareSurface(blankSurface, slideWidth, slideHeight); + } + return &blankSurface; + } + + surfaceCache.insert(slideIndex, new QImage(prepareSurface(img, slideWidth, slideHeight))); + return surfaceCache[slideIndex]; +} + + +// Schedules rendering the slides. Call this function to avoid immediate +// render and thus cause less flicker. +void PictureFlowPrivate::triggerRender() +{ + triggerTimer.start(); +} + +// Render the slides. Updates only the offscreen buffer. +void PictureFlowPrivate::render() +{ + buffer.fill(Qt::black); + + int nleft = leftSlides.count(); + int nright = rightSlides.count(); + + QRect r = renderSlide(centerSlide); + int c1 = r.left(); + int c2 = r.right(); + + if(step == 0) + { + slidesRect.clear(); + slidesRect.resize(11); + + // no animation, boring plain rendering + for(int index = 0; index < nleft-1; index++) + { + int alpha = (index < nleft-2) ? 256 : 128; + QRect rs = renderSlide(leftSlides[index], alpha, 0, c1-1); + slidesRect[index] = rs; + if(!rs.isEmpty()) + c1 = rs.left(); + } + slidesRect[5] = r; + for(int index = 0; index < nright-1; index++) + { + int alpha = (index < nright-2) ? 256 : 128; + QRect rs = renderSlide(rightSlides[index], alpha, c2+1, buffer.width()); + slidesRect[6 + index] = rs; + if(!rs.isEmpty()) + c2 = rs.right(); + } + } + else + { + // the first and last slide must fade in/fade out + for(int index = 0; index < nleft; index++) + { + int alpha = 256; + if(index == nleft-1) + alpha = (step > 0) ? 0 : 128-fade/2; + if(index == nleft-2) + alpha = (step > 0) ? 128-fade/2 : 256-fade/2; + if(index == nleft-3) + alpha = (step > 0) ? 256-fade/2 : 256; + QRect rs = renderSlide(leftSlides[index], alpha, 0, c1-1); + if(!rs.isEmpty()) + c1 = rs.left(); + } + for(int index = 0; index < nright; index++) + { + int alpha = (index < nright-2) ? 256 : 128; + if(index == nright-1) + alpha = (step > 0) ? fade/2 : 0; + if(index == nright-2) + alpha = (step > 0) ? 128+fade/2 : fade/2; + if(index == nright-3) + alpha = (step > 0) ? 256 : 128+fade/2; + QRect rs = renderSlide(rightSlides[index], alpha, c2+1, buffer.width()); + if(!rs.isEmpty()) + c2 = rs.right(); + } + } +} + +// Renders a slide to offscreen buffer. Returns a rect of the rendered area. +// alpha=256 means normal, alpha=0 is fully black, alpha=128 half transparent +// col1 and col2 limit the column for rendering. +QRect PictureFlowPrivate::renderSlide(const SlideInfo &slide, int alpha, +int col1, int col2) +{ + QImage* src = surface(slide.slideIndex); + if(!src) + return QRect(); + + QRect rect(0, 0, 0, 0); + +#ifdef PICTUREFLOW_BILINEAR_FILTER + int sw = src->height() / BILINEAR_STRETCH_HOR; + int sh = src->width() / BILINEAR_STRETCH_VER; +#else + int sw = src->height(); + int sh = src->width(); +#endif + int h = buffer.height(); + int w = buffer.width(); + + if(col1 > col2) + { + int c = col2; + col2 = col1; + col1 = c; + } + + col1 = (col1 >= 0) ? col1 : 0; + col2 = (col2 >= 0) ? col2 : w-1; + col1 = qMin(col1, w-1); + col2 = qMin(col2, w-1); + + int distance = h * 100 / zoom; + PFreal sdx = fcos(slide.angle); + PFreal sdy = fsin(slide.angle); + PFreal xs = slide.cx - slideWidth * sdx/2; + PFreal ys = slide.cy - slideWidth * sdy/2; + PFreal dist = distance * PFREAL_ONE; + + int xi = qMax((PFreal)0, ((w*PFREAL_ONE/2) + fdiv(xs*h, dist+ys)) >> PFREAL_SHIFT); + if(xi >= w) + return rect; + + bool flag = false; + rect.setLeft(xi); + + for(int x = qMax(xi, col1); x <= col2; x++) + { + PFreal hity = 0; + PFreal fk = rays[x]; + if(sdy) + { + fk = fk - fdiv(sdx,sdy); + hity = -fdiv((rays[x]*distance - slide.cx + slide.cy*sdx/sdy), fk); + } + + dist = distance*PFREAL_ONE + hity; + if(dist < 0) + continue; + + PFreal hitx = fmul(dist, rays[x]); + PFreal hitdist = fdiv(hitx - slide.cx, sdx); + +#ifdef PICTUREFLOW_BILINEAR_FILTER + int column = sw*BILINEAR_STRETCH_HOR/2 + (hitdist*BILINEAR_STRETCH_HOR >> PFREAL_SHIFT); + if(column >= sw*BILINEAR_STRETCH_HOR) + break; +#else + int column = sw/2 + (hitdist >> PFREAL_SHIFT); + if(column >= sw) + break; +#endif + if(column < 0) + continue; + + rect.setRight(x); + if(!flag) + rect.setLeft(x); + flag = true; + + int y1 = h/2; + int y2 = y1+ 1; + QRgb* pixel1 = (QRgb*)(buffer.scanLine(y1)) + x; + QRgb* pixel2 = (QRgb*)(buffer.scanLine(y2)) + x; + QRgb pixelstep = pixel2 - pixel1; + +#ifdef PICTUREFLOW_BILINEAR_FILTER + int center = (sh*BILINEAR_STRETCH_VER/2); + int dy = dist*BILINEAR_STRETCH_VER / h; +#else + int center = (sh/2); + int dy = dist / h; +#endif + int p1 = center*PFREAL_ONE - dy/2; + int p2 = center*PFREAL_ONE + dy/2; + + const QRgb *ptr = (const QRgb*)(src->scanLine(column)); + if(alpha == 256) + while((y1 >= 0) && (y2 < h) && (p1 >= 0)) + { + *pixel1 = ptr[p1 >> PFREAL_SHIFT]; + *pixel2 = ptr[p2 >> PFREAL_SHIFT]; + p1 -= dy; + p2 += dy; + y1--; + y2++; + pixel1 -= pixelstep; + pixel2 += pixelstep; + } + else + while((y1 >= 0) && (y2 < h) && (p1 >= 0)) + { + QRgb c1 = ptr[p1 >> PFREAL_SHIFT]; + QRgb c2 = ptr[p2 >> PFREAL_SHIFT]; + + int r1 = qRed(c1) * alpha/256; + int g1 = qGreen(c1) * alpha/256; + int b1 = qBlue(c1) * alpha/256; + int r2 = qRed(c2) * alpha/256; + int g2 = qGreen(c2) * alpha/256; + int b2 = qBlue(c2) * alpha/256; + + *pixel1 = qRgb(r1, g1, b1); + *pixel2 = qRgb(r2, g2, b2); + p1 -= dy; + p2 += dy; + y1--; + y2++; + pixel1 -= pixelstep; + pixel2 += pixelstep; + } + } + + rect.setTop(0); + rect.setBottom(h-1); + return rect; +} + +// Updates look-up table and other stuff necessary for the rendering. +// Call this when the viewport size or slide dimension is changed. +void PictureFlowPrivate::recalc(int ww, int wh) +{ + int w = (ww+1)/2; + int h = (wh+1)/2; + buffer = QImage(ww, wh, QImage::Format_RGB32); + buffer.fill(0); + + rays.resize(w*2); + + for(int i = 0; i < w; ++i) + { + PFreal gg = (PFREAL_HALF + i * PFREAL_ONE) / (2*h); + rays[w-i-1] = -gg; + rays[w+i] = gg; + } + + + itilt = 70 * IANGLE_MAX / 360; // approx. 70 degrees tilted + + offsetX = slideWidth/2 * (PFREAL_ONE-fcos(itilt)); + offsetY = slideWidth/2 * fsin(itilt); + offsetX += slideWidth * PFREAL_ONE; + offsetY += slideWidth * PFREAL_ONE / 4; + spacing = 40; + + surfaceCache.clear(); + blankSurface = QImage(); +} + +void PictureFlowPrivate::startAnimation() +{ +#if 1 + if(!animateTimer.isActive()) + { + step = (target < centerSlide.slideIndex) ? -1 : 1; + animateTimer.start(30, widget); + } +#else + if (animateTimer.isActive()) + animateTimer.stop(); + + step = (target < centerSlide.slideIndex) ? -1 : 1; + animateTimer.start(30, widget); +#endif +} + +// Updates the animation effect. Call this periodically from a timer. +void PictureFlowPrivate::updateAnimation() +{ + if(!animateTimer.isActive()) + return; + if(step == 0) + return; + + int speed = 16384; + + // deaccelerate when approaching the target + if(true) + { + const int max = 2 * 65536; + + int fi = slideFrame; + fi -= (target << 16); + if(fi < 0) + fi = -fi; + fi = qMin(fi, max); + + int ia = IANGLE_MAX * (fi-max/2) / (max*2); + speed = 512 + 16384 * (PFREAL_ONE+fsin(ia))/PFREAL_ONE; + } + + slideFrame += speed*step; + + int index = slideFrame >> 16; + int pos = slideFrame & 0xffff; + int neg = 65536 - pos; + int tick = (step < 0) ? neg : pos; + PFreal ftick = (tick * PFREAL_ONE) >> 16; + + // the leftmost and rightmost slide must fade away + fade = pos / 256; + + if(step < 0) + index++; + if(centerIndex != index) + { + centerIndex = index; + slideFrame = index << 16; + centerSlide.slideIndex = centerIndex; + for(int i = 0; i < leftSlides.count(); ++i) + leftSlides[i].slideIndex = centerIndex-1-i; + for(int i = 0; i < rightSlides.count(); ++i) + rightSlides[i].slideIndex = centerIndex+1+i; + } + + centerSlide.angle = (step * tick * itilt) >> 16; + centerSlide.cx = -step * fmul(offsetX, ftick); + centerSlide.cy = fmul(offsetY, ftick); + + if(centerIndex == target) + { + resetSlides(); + animateTimer.stop(); + triggerRender(); + step = 0; + fade = 256; + return; + } + + for(int i = 0; i < leftSlides.count(); ++i) + { + SlideInfo& si = leftSlides[i]; + si.angle = itilt; + si.cx = -(offsetX + spacing*i*PFREAL_ONE + step*spacing*ftick); + si.cy = offsetY; + } + + for(int i = 0; i < rightSlides.count(); ++i) + { + SlideInfo& si = rightSlides[i]; + si.angle = -itilt; + si.cx = offsetX + spacing*i*PFREAL_ONE - step*spacing*ftick; + si.cy = offsetY; + } + + if(step > 0) + { + PFreal ftick = (neg * PFREAL_ONE) >> 16; + rightSlides[0].angle = -(neg * itilt) >> 16; + rightSlides[0].cx = fmul(offsetX, ftick); + rightSlides[0].cy = fmul(offsetY, ftick); + } + else + { + PFreal ftick = (pos * PFREAL_ONE) >> 16; + leftSlides[0].angle = (pos * itilt) >> 16; + leftSlides[0].cx = -fmul(offsetX, ftick); + leftSlides[0].cy = fmul(offsetY, ftick); + } + + // must change direction ? + if(target < index) if(step > 0) + step = -1; + if(target > index) if(step < 0) + step = 1; + + triggerRender(); +} + +// ----------------------------------------- + +PictureFlow::PictureFlow(QWidget* parent): QWidget(parent) +{ + d = new PictureFlowPrivate(this); + + setAttribute(Qt::WA_StaticContents, true); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); +} + +PictureFlow::~PictureFlow() +{ + delete d; +} + +int PictureFlow::slideCount() const +{ + return d->slideCount(); +} + +void PictureFlow::setSlideCount(int count) +{ + d->setSlideCount(count); +} + +QSize PictureFlow::slideSize() const +{ + return d->slideSize(); +} + +void PictureFlow::setSlideSize(QSize size) +{ + d->setSlideSize(size); +} + +int PictureFlow::zoomFactor() const +{ + return d->zoomFactor(); +} + +void PictureFlow::setZoomFactor(int z) +{ + d->setZoomFactor(z); +} + +QImage PictureFlow::slide(int index) const +{ + return d->slide(index); +} + +void PictureFlow::setSlide(int index, const QImage& image) +{ + d->setSlide(index, image); +} + +void PictureFlow::setSlide(int index, const QPixmap& pixmap) +{ + d->setSlide(index, pixmap.toImage()); +} + +int PictureFlow::currentSlide() const +{ + return d->currentSlide(); +} + +void PictureFlow::setCurrentSlide(int index) +{ + d->setCurrentSlide(index); +} + +void PictureFlow::clear() +{ + d->setSlideCount(0); +} + +void PictureFlow::render() +{ + d->render(); + update(); +} + +void PictureFlow::showPrevious() +{ + d->showPrevious(); +} + +void PictureFlow::showNext() +{ + d->showNext(); +} + +void PictureFlow::showSlide(int index) +{ + d->showSlide(index); +} + +void PictureFlow::showSlideAt (int x, int y) { + if (d->slidesRect[5].contains(x, y)) + return; + + if (x < d->slidesRect[5].x()) { + for (int i=0; i < 5; ++i) { + if (d->slidesRect[i].contains(x, y)) { + showSlide(d->currentSlide() - (i + 1)); + return; + } + } + } else { + for (int i=6; i < 11; ++i) { + if (d->slidesRect[i].contains(x, y)) { + showSlide(d->currentSlide() + (i - 5)); + return; + } + } + } +} + +void PictureFlow::keyPressEvent(QKeyEvent* event) +{ + + switch (event->key()) { + case Qt::Key_Left: + if(event->modifiers() == Qt::AltModifier) { + showSlide(currentSlide() - 5); + } else { + showPrevious(); + } + event->accept(); + return; + case Qt::Key_Right: + if(event->modifiers() == Qt::AltModifier) { + showSlide(currentSlide() + 5); + } else { + showNext(); + } + event->accept(); + return; + case Qt::Key_Up: + showSlide(currentSlide() + 10); + event->accept(); + return; + case Qt::Key_Down: + showSlide(currentSlide() - 10); + event->accept(); + return; + default: + break; + } + + event->ignore(); +} + +void PictureFlow::mouseReleaseEvent (QMouseEvent *event) { + showSlideAt(event->x(), event->y()); +} + +void PictureFlow::mouseMoveEvent (QMouseEvent *event) { + showSlideAt(event->x(), event->y()); +} + +void PictureFlow::wheelEvent (QWheelEvent *event) { + int numDegrees = event->delta() / 8; + int numSteps = numDegrees / 15; + + d->showSlide(d->currentSlide() + numSteps); + event->accept(); +} + +void PictureFlow::paintEvent(QPaintEvent* event) +{ + Q_UNUSED(event); + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, false); + painter.drawImage(QPoint(0,0), d->buffer); +} + +void PictureFlow::resizeEvent(QResizeEvent* event) +{ + d->resize(width(), height()); + QWidget::resizeEvent(event); +} + +void PictureFlow::timerEvent(QTimerEvent* event) +{ + if(event->timerId() == d->animateTimer.timerId()) + d->updateAnimation(); + else + QWidget::timerEvent(event); +} + +} // namespace FQTerm + +#include "pictureflow.moc" diff --git a/src/ui/pictureflow.h b/src/ui/pictureflow.h new file mode 100644 index 0000000..c9cf5aa --- /dev/null +++ b/src/ui/pictureflow.h @@ -0,0 +1,198 @@ + +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* + PictureFlow - animated image show widget + http://pictureflow.googlecode.com + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef PICTUREFLOW_H +#define PICTUREFLOW_H + +#include + +namespace FQTerm { + +class PictureFlowPrivate; + +/*! + Class PictureFlow implements an image show widget with animation effect + like Apple's CoverFlow (in iTunes and iPod). Images are arranged in form + of slides, one main slide is shown at the center with few slides on + the left and right sides of the center slide. When the next or previous + slide is brought to the front, the whole slides flow to the right or + the right with smooth animation effect; until the new slide is finally + placed at the center. + + */ +class PictureFlow : public QWidget +{ +Q_OBJECT + + Q_PROPERTY(int slideCount READ slideCount WRITE setSlideCount) + Q_PROPERTY(int currentSlide READ currentSlide WRITE setCurrentSlide) + Q_PROPERTY(QSize slideSize READ slideSize WRITE setSlideSize) + Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor) + +public: + /*! + Creates a new PictureFlow widget. + */ + PictureFlow(QWidget* parent = 0); + + /*! + Destroys the widget. + */ + ~PictureFlow(); + + /*! + Returns the total number of slides. + */ + int slideCount() const; + + /*! + Sets the total number of slides. + */ + void setSlideCount(int count); + + /*! + Returns the dimension of each slide (in pixels). + */ + QSize slideSize() const; + + /*! + Sets the dimension of each slide (in pixels). + */ + void setSlideSize(QSize size); + + /*! + Sets the zoom factor (in percent). + */ + void setZoomFactor(int zoom); + + /*! + Returns the zoom factor (in percent). + */ + int zoomFactor() const; + + /*! + Returns QImage of specified slide. + This function will be called only whenever necessary, e.g. the 100th slide + will not be retrived when only the first few slides are visible. + */ + virtual QImage slide(int index) const; + + /*! + Sets an image for specified slide. If the slide already exists, + it will be replaced. + */ + virtual void setSlide(int index, const QImage& image); + + /*! + Sets a pixmap for specified slide. If the slide already exists, + it will be replaced. + */ + virtual void setSlide(int index, const QPixmap& pixmap); + + /*! + Returns the index of slide currently shown in the middle of the viewport. + */ + int currentSlide() const; + +signals: + void slideSelected (int index); + +public slots: + + /*! + Sets slide to be shown in the middle of the viewport. No animation + effect will be produced, unlike using showSlide. + */ + void setCurrentSlide(int index); + + /*! + Clears images of all slides. + */ + void clear(); + + /*! + Rerender the widget. Normally this function will be automatically invoked + whenever necessary, e.g. during the transition animation. + */ + void render(); + + /*! + Shows previous slide using animation effect. + */ + void showPrevious(); + + /*! + Shows next slide using animation effect. + */ + void showNext(); + + /*! + Go to specified slide using animation effect. + */ + void showSlide(int index); + + + /*! + Go to slide at specified position using animation effect. + */ + void showSlideAt(int x, int y); + +protected: + void mouseReleaseEvent (QMouseEvent *event); + void mouseMoveEvent (QMouseEvent *event); + void wheelEvent (QWheelEvent *event); + void paintEvent(QPaintEvent *event); + void keyPressEvent(QKeyEvent *event); + void resizeEvent(QResizeEvent *event); + void timerEvent(QTimerEvent *event); + +private: + PictureFlowPrivate* d; +}; + +} // namespace FQTerm + +#endif // PICTUREFLOW_H diff --git a/src/ui/popupMessage.cpp b/src/ui/popupMessage.cpp new file mode 100644 index 0000000..6b89b38 --- /dev/null +++ b/src/ui/popupMessage.cpp @@ -0,0 +1,316 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "popupMessage.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +PopupMessage::PopupMessage(QWidget *parent_, QWidget *anchor, int timeout) + : OverlayWidget(parent_, anchor), + anchor_(anchor), + parent_(parent_), + maskEffect_(Slide), + dissolveSize_(0), + dissolveDelta_(-1), + offset_(0), + counter_(0), + stage_(1), + timeout_(timeout), + isCounterShown_(true) { + setFrameStyle(QFrame::Panel | QFrame::Raised); + setFrameShape(QFrame::StyledPanel); + // overrideWindowFlags( Qt::WX11BypassWM ); + + QHBoxLayout *hbox; + QLabel *label; + QLabel *alabel; + //KActiveLabel *alabel; + + layout_ = new QVBoxLayout(this); //, 9 /*margin*/, 6 /*spacing*/ ); + layout_->setMargin(9); + layout_->setSpacing(6); + + hbox = new QHBoxLayout; //( layout_, 12 ); + hbox->setMargin(12); + + layout_->addLayout(hbox); + + hbox->addWidget(countDownFrame_ = new QFrame(this)); //, "counterVisual" ) ); + countDownFrame_->setObjectName("counterVisual"); + countDownFrame_->setFixedWidth(fontMetrics().width("X")); + countDownFrame_->setFrameStyle(QFrame::Plain | QFrame::Box); + QPalette tmp_palette; + tmp_palette.setColor(countDownFrame_->foregroundRole(), palette().color + (QPalette::Window).dark()); + countDownFrame_->setPalette(tmp_palette); + // m_countdownFrame->setPaletteForegroundColor( paletteBackgroundColor().dark() ); + + label = new QLabel(this); //, "image" ); + label->setObjectName("image"); + hbox->addWidget(label); + label->hide(); + + alabel = new QLabel("Details of the tasks: ", this); //, "label"); + alabel->setObjectName("label"); + //alabel = new KActiveLabel( this, "label" ); + //alabel->setTextFormat( Qt::RichText ); + alabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + + hbox->addWidget(alabel); + + hbox = new QHBoxLayout; + + layout_->addLayout(hbox); + + hbox->addItem(new QSpacerItem(4, 4, QSizePolicy::Expanding, + QSizePolicy::Preferred)); + //FIXME: add icon + QPushButton *tmp_button = new QPushButton("Close", this); + tmp_button->setObjectName("closeButton"); + hbox->addWidget(tmp_button); //, "closeButton" ) ); + + FQ_VERIFY(connect(findChild < QPushButton * > ("closeButton"), SIGNAL(clicked()), + SLOT(close()))); +} + +void PopupMessage::addWidget(QWidget *widget) { + layout_->addWidget(widget); + adjustSize(); +} + +void PopupMessage::showCloseButton(const bool show) { + findChild < QPushButton * > ("closeButton")->setShown(show); + adjustSize(); +} + +void PopupMessage::showCounter(const bool show) { + isCounterShown_ = show; + findChild < QFrame * > ("counterVisual")->setShown(show); + adjustSize(); +} + +void PopupMessage::setText(const QString &text) { + findChild < QLabel * > ("label")->setText(text); + adjustSize(); +} + +void PopupMessage::setImage(const QString &location_) { + findChild < QLabel * > ("image")->setPixmap(QPixmap(location_)); + adjustSize(); +} + + +//////////////////////////////////////////////////////////////////////// +// Public Slots +//////////////////////////////////////////////////////////////////////// + +void PopupMessage::close() { //SLOT + stage_ = 3; + killTimer(timerId_); + timerId_ = startTimer(6); +} + +void PopupMessage::display() { //SLOT + dissolveSize_ = 24; + dissolveDelta_ = -1; + + if (maskEffect_ == Dissolve) { + // necessary to create the mask + maskBitmap_ = QBitmap(width(), height()); + // make the mask empty and hence will not show widget with show() called below + dissolveMask(); + timerId_ = startTimer(1000 / 30); + } else { + timerId_ = startTimer(6); + } + show(); +} + +//////////////////////////////////////////////////////////////////////// +// Protected +//////////////////////////////////////////////////////////////////////// + +void PopupMessage::timerEvent(QTimerEvent*) { + switch (maskEffect_) { + case Plain: + plainMask(); + break; + + case Slide: + slideMask(); + break; + + case Dissolve: + dissolveMask(); + break; + } +} + +void PopupMessage::countDown() { + if (!timeout_) { + killTimer(timerId_); + return ; + } + + QFrame * &h = countDownFrame_; + + if (counter_ < h->height() - 3) { + QPainter(h).fillRect(2, 2, h->width() - 4, counter_, palette().color + (QPalette::Active, QPalette::Highlight)); + } + + if (!testAttribute(Qt::WA_UnderMouse)) { + counter_++; + } + + if (counter_ > h->height()) { + stage_ = 3; + killTimer(timerId_); + timerId_ = startTimer(6); + } else { + killTimer(timerId_); + timerId_ = startTimer(timeout_ / h->height()); + } +} + +void PopupMessage::dissolveMask() { + if (stage_ == 1) { + //repaint( false ); + QPainter maskPainter(&maskBitmap_); + + maskBitmap_.fill(Qt::black); + + maskPainter.setBrush(Qt::white); + maskPainter.setPen(Qt::white); + maskPainter.drawRect(maskBitmap_.rect()); + + dissolveSize_ += dissolveDelta_; + + if (dissolveSize_ > 0) { + //maskPainter.setCompositionMode( Qt::EraseROP ); + //FIXME: QRubberBand + + int x, y, s; + const int size = 16; + + for (y = 0; y < height() + size; y += size) { + x = width(); + s = dissolveSize_ * x / 128; + + for (; x > size; x -= size, s -= 2) { + if (s < 0) { + break; + } + + maskPainter.drawEllipse(x - s / 2, y - s / 2, s, s); + } + } + } else if (dissolveSize_ < 0) { + dissolveDelta_ = 1; + killTimer(timerId_); + + if (timeout_) { + timerId_ = startTimer(40); + stage_ = 2; + } + } + + setMask(maskBitmap_); + } else if (stage_ == 2) { + countDown(); + } else { + deleteLater(); + } +} + + +void PopupMessage::plainMask() { + switch (stage_) { + case 1: + // Raise + killTimer(timerId_); + if (timeout_) { + timerId_ = startTimer(40); + stage_ = 2; + } + + break; + + case 2: + // Counter + countDown(); + break; + + case 3: + // Lower/Remove + deleteLater(); + } +} + + +void PopupMessage::slideMask() { + switch (stage_) { + case 1: + //raise + move(0, parent_->y() - offset_); + + offset_++; + if (offset_ > height()) { + killTimer(timerId_); + + if (timeout_) { + timerId_ = startTimer(40); + stage_ = 2; + } + } + + break; + + case 2: + //fill in pause timer bar + countDown(); + break; + + case 3: + //lower + offset_--; + move(0, parent_->y() - offset_); + + if (offset_ < 0) { + deleteLater(); + } + } +} + +} // namespace FQTerm + +#include "popupMessage.moc" diff --git a/src/ui/popupMessage.h b/src/ui/popupMessage.h new file mode 100644 index 0000000..1877b1c --- /dev/null +++ b/src/ui/popupMessage.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +//WARNING this is not meant for use outside this unit! + + +#ifndef FQTERM_POPUP_MESSAGE_H +#define FQTERM_POPUP_MESSAGE_H + +#include "overlayWidget.h" + +// #include +// #include +// #include +//Added by qt3to4: +#include +#include +#include +#include +#include + +namespace FQTerm { +/** + * @class PopupMessage + * @short Widget that animates itself into a position relative to an anchor widget + */ +class PopupMessage: public OverlayWidget { + Q_OBJECT; + public: + /** + * @param anchor : which widget to tie the popup widget to. + * @param timeout : how long to wait before auto closing. A value of 0 means close + * only on pressing the closeButton or close() is called. + */ + PopupMessage(QWidget *parent_, QWidget *anchor, int timeout = 5000 + /*milliseconds*/); + + enum MaskEffect { + Plain, Slide, Dissolve + }; + + void addWidget(QWidget *widget); + void showCloseButton(const bool show); + void showCounter(const bool show); + void setImage(const QString &location_); + void setMaskEffect(const MaskEffect type) { + maskEffect_ = type; + } + void setText(const QString &text); + void setTimeout(const int time) { + timeout_ = time; + } + + public slots: + void close(); + void display(); + + protected: + void timerEvent(QTimerEvent*); + void countDown(); + + /** + * @short Gradually show widget by dissolving from background + */ + void dissolveMask(); + + /** + * @short instantly display widget + */ + void plainMask(); + + /** + * @short animation to slide the widget into view + */ + void slideMask(); + + private: + QVBoxLayout *layout_; + QFrame *countDownFrame_; + QWidget *anchor_; + QWidget *parent_; + QBitmap maskBitmap_; + MaskEffect maskEffect_; + + int dissolveSize_; + int dissolveDelta_; + + int offset_; + int counter_; + int stage_; + int timeout_; + int timerId_; + + bool isCounterShown_; +}; + +} // namespace FQTerm + +#endif // FQTERM_POPUP_MESSAGE_H diff --git a/src/ui/popwidget.cpp b/src/ui/popwidget.cpp new file mode 100644 index 0000000..1c702ed --- /dev/null +++ b/src/ui/popwidget.cpp @@ -0,0 +1,177 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "popwidget.h" + +#include +#include +#include +#include +#include + +#include +#include + +namespace FQTerm { + +extern QString pathLib; + +popWidget::popWidget(FQTermWindow *win, QWidget *parent_, const char *name, + Qt::WFlags f) + : QWidget(parent_, f) { + // QPixmap pxm(QPixmap(pathLib+"pic/popwidget.png") ); + // if(!pxm.isNull()) + // { + // resize(pxm.width(), pxm.height()); + // QPalette palette; + // palette.setBrush(backgroundRole(), QBrush(pxm)); + // setPalette(palette); + // //setBackgroundPixmap(pxm); + // } + // else + // { + // resize(200, 120); + // } + // + // label_ = new QLabel(this); + // label_->setGeometry( QRect( 5, height()/3, width()-10, height()*2/3 ) ); + // label_->setAlignment( Qt::AlignTop ); + // label_->setWordWrap(true); + // if(!pxm.isNull()){ + // QPalette palette; + // palette.setBrush(label_->backgroundRole(), QBrush(pxm)); + // label_->setPalette(palette); + // // label_->setBackgroundPixmap(pxm); + // } + // else { + // QPalette palette; + // palette.setColor(label_->backgroundRole(), QColor(249,250,229)); + // label_->setPalette(palette); + // //label_->setBackgroundColor(QColor(249,250,229)); + // } + // //label_->setBackgroundOrigin( ParentOrigin ); + // label_->setFont(QFont(qApp->font().family(), 12)); + // + // pTimer = new QTimer(this); + // QVERIFY(connect(pTimer, SIGNAL(timeout()), this, SLOT(showTimer()))); + // + // stateID = -1; + // + // stepID_ = 2; + // + // intervalID_ = 500/(height()/stepID_); + // + // setFocusPolicy(Qt::NoFocus); + // + // termWindow_ = win; + // + // hide(); + // + // Display *dsp = QX11Info::display(); + // int screen = DefaultScreen(dsp); + // Window root = RootWindow(dsp, screen); + // + // WId winid = this->winId(); + // + // XEvent ev; + // memset(&ev, 0, sizeof(ev)); + // + // ev.xclient.type = ClientMessage; + // ev.xclient.termWindow_ = winid; + // ev.xclient.message_type = XInternAtom (dsp, "_NET_WM_DESKTOP", False ); + // ev.xclient.format = 32; + // ev.xclient.data.l[0] = -1; + // ev.xclient.data.l[1] = 0l; + // ev.xclient.data.l[2] = 0l; + // ev.xclient.data.l[3] = 0l; + // ev.xclient.data.l[4] = 0l; + // + // XSendEvent(dsp, root, False, SubstructureRedirectMask|SubstructureNotifyMask, &ev); + // XSync(dsp, False); +} + +popWidget::~popWidget() { + // delete pTimer; +} + +void popWidget::mousePressEvent(QMouseEvent *me) { + // QWidgetList list = QApplication::topLevelWidgets(); + // + // //((FQTermFrame *)qApp->mainWidget())->popupFocusIn(termWindow_); + // + // if(stateID==1) + // { + // stateID = 2; + // pTimer->setInterval(intervalID_); + // } +} + + +void popWidget::popup() { + // pTimer->start(intervalID_); + // stateID = 0; + // + // desktopRectangle_ = qApp->desktop()->rect(); + // position_ = QPoint( desktopRectangle_.width()-width()-5, desktopRectangle_.height()-5 ); + // move(position_); + // + // if(!isVisible()) + // show(); +} + +void popWidget::setText(const QString &str) { + // label_->setText(str); +} + +void popWidget::showTimer() { + // switch(stateID) + // { + // case 0: // popup + // if(position_.y()+height()+5>desktopRectangle_.height()) + // position_.setY( position_.y() - stepID_ ); + // else + // { + // stateID = 1; + // pTimer->setInterval(5000); + // } + // break; + // case 1: // wait + // stateID = 2; + // pTimer->setInterval(intervalID_); + // break; + // case 2: // hiding + // if(position_.y()stop(); + // } + // break; + // default: + // + // break; + // } + // move(position_); +} + +} // namespace FQTerm + +#include "popwidget.moc" diff --git a/src/ui/popwidget.h b/src/ui/popwidget.h new file mode 100644 index 0000000..2a02c7d --- /dev/null +++ b/src/ui/popwidget.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_POP_WIDGET_H +#define FQTERM_POP_WIDGET_H + +#include +//Added by qt3to4: +#include +#include + +class QTimer; +class QLabel; + +namespace FQTerm { + +class FQTermWindow; + +class popWidget: public QWidget { + Q_OBJECT; + public: + // #if (QT_VERSION>=310) + // popWidget(FQTermWindow * win, QWidget *parent = 0, const char *name=0, WFlags f=WStyle_Splash); + // #else + popWidget(FQTermWindow *win, QWidget *parent_ = 0, const char *name = 0, + Qt::WFlags f = Qt::WindowStaysOnTopHint + | Qt::X11BypassWindowManagerHint + | Qt::Tool); + // #endif + ~popWidget(); + + void popup(); + void setText(const QString &); + + public slots: + void showTimer(); + + protected: + QTimer *pTimer; + int stateID; // -1 hide, 0 popup, 1 wait, 2 hiding + QPoint position_; + QRect desktopRectangle_; + int stepID_; + int intervalID_; + QLabel *label_; + FQTermWindow *termWindow_; + + void mousePressEvent(QMouseEvent*); +}; + +} // namespace FQTerm + +#endif // FQTERM_POP_WIDGET_H diff --git a/src/ui/prefdialog.cpp b/src/ui/prefdialog.cpp new file mode 100644 index 0000000..9f01a08 --- /dev/null +++ b/src/ui/prefdialog.cpp @@ -0,0 +1,332 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include + +#include "fqterm_config.h" +#include "fqterm_path.h" +#include "fqterm_trace.h" + +#include "prefdialog.h" +#include "soundconf.h" + +namespace FQTerm { + +/* + * Constructs a prefDialog which is a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +prefDialog::prefDialog(FQTermConfig * config, QWidget *parent, Qt::WFlags fl) + : QDialog(parent, fl), + soundButtonGroup_(this), + verticalSettingButtonGroup_(this), + config_(config){ + ui_.setupUi(this); + fileDialog_ = new FQTermFileDialog(config_); + soundButtonGroup_.addButton(ui_.noneRadioButton, 0); + soundButtonGroup_.addButton(ui_.beepRadioButton, 1); + soundButtonGroup_.addButton(ui_.fileRadioButton, 2); + verticalSettingButtonGroup_.addButton(ui_.topRadioButton, 0); + verticalSettingButtonGroup_.addButton(ui_.middleRadioButton, 1); + verticalSettingButtonGroup_.addButton(ui_.bottomRadioButton, 2); + + connectSlots(); + + loadSetting(); + +} + +/* + * Destroys the object and frees any allocated resources + */ +prefDialog::~prefDialog() { + // no need to delete child widgets, Qt does it all for us + delete fileDialog_; +} + +void prefDialog::connectSlots() { + FQ_VERIFY(connect(ui_.okPushButton, SIGNAL(clicked()), this, SLOT(onOK()))); + FQ_VERIFY(connect(ui_.cancelPushButton, SIGNAL(clicked()), this, SLOT(onCancel()))); + FQ_VERIFY(connect(ui_.selectsoundPushButton, SIGNAL(clicked()), this, SLOT(onSound()))); + FQ_VERIFY(connect(ui_.choosehttpPushButton, SIGNAL(clicked()), this, SLOT(onHttp()))); + //FQ_VERIFY(connect(ButtonGroup1 , SIGNAL(clicked(int)), this, SLOT(onBeep(int)) )); + FQ_VERIFY(connect(ui_.browsePushButton, SIGNAL(clicked()), this, SLOT(onBrowse()))); + FQ_VERIFY(connect(ui_.imagePushButton, SIGNAL(clicked()), this, SLOT(onImage()))); + FQ_VERIFY(connect(ui_.poolPushButton, SIGNAL(clicked()), this, SLOT(onPool()))); + FQ_VERIFY(connect(ui_.styleSheetPushButton, SIGNAL(clicked()), this, SLOT(onStyleSheet()))); + FQ_VERIFY(connect(ui_.editorPushButton, SIGNAL(clicked()), this, SLOT(onEditor()))); +} + +void prefDialog::loadSetting() { + + QString strTmp; + + strTmp = config_->getItemValue("preference", "displayoffset"); + ui_.displayOffsetSlider->setSliderPosition(strTmp.toInt()); + + strTmp = config_->getItemValue("preference", "xim"); + ui_.ximComboBox->setCurrentIndex(strTmp.toInt()); + + strTmp = config_->getItemValue("preference", "wordwrap"); + ui_.wordLineEdit3->setText(strTmp); + + strTmp = config_->getItemValue("preference", "smartww"); + ui_.smartCheckBox->setChecked(strTmp != "0"); + + strTmp = config_->getItemValue("preference", "wheel"); + ui_.wheelCheckBox->setChecked(strTmp != "0"); + + strTmp = config_->getItemValue("preference", "url"); + ui_.urlCheckBox->setChecked(strTmp != "0"); + + strTmp = config_->getItemValue("preference", "logmsg"); + ui_.saveCheckBox->setChecked(strTmp != "0"); + + strTmp = config_->getItemValue("preference", "blinktab"); + ui_.blinkCheckBox->setChecked(strTmp != "0"); + + strTmp = config_->getItemValue("preference", "warn"); + ui_.warnCheckBox->setChecked(strTmp != "0"); + + strTmp = config_->getItemValue("preference", "beep"); + qobject_cast(soundButtonGroup_.button(strTmp.toInt()))->setChecked(true); + + strTmp = config_->getItemValue("preference", "vsetting"); + qobject_cast(verticalSettingButtonGroup_.button(strTmp.toInt()))->setChecked(true); + + strTmp = config_->getItemValue("preference", "enq"); + ui_.enqCheckBox->setChecked(strTmp != "0"); + + //ButtonGroup1->find(strTmp.toInt()))->setChecked(true); + + // if(strTmp.toInt()!=2) + // { + // wavefileLineEdit->setEnabled(false); + // selectsoundPushButton->setEnabled(false); + // } + + strTmp = config_->getItemValue("preference", "wavefile"); + ui_.wavefileLineEdit->setText(strTmp); + + strTmp = config_->getItemValue("preference", "antialias"); + ui_.aacheckBox->setChecked(strTmp != "0"); + + + strTmp = config_->getItemValue("preference", "tray"); + ui_.trayCheckBox->setChecked(strTmp != "0"); + + strTmp = config_->getItemValue("preference", "clearpool"); + ui_.clearCheckBox->setChecked(strTmp == "1"); + + strTmp = config_->getItemValue("preference", "pool"); + if (strTmp.isEmpty()) { + strTmp = getPath(USER_CONFIG) + "pool/"; + } + ui_.poolLineEdit->setText(strTmp); + + strTmp = config_->getItemValue("preference", "http"); + ui_.httpLineEdit->setText(strTmp); + + strTmp = config_->getItemValue("preference", "zmodem"); + if (strTmp.isEmpty()) { + strTmp = getPath(USER_CONFIG) + "zmodem/"; + } + ui_.zmodemLineEdit->setText(strTmp); + + strTmp = config_->getItemValue("preference", "image"); + ui_.imageLineEdit->setText(strTmp); + + strTmp = config_->getItemValue("preference", "qssfile"); + ui_.styleSheetLineEdit->setText(strTmp); + + strTmp = config_->getItemValue("preference", "editor"); + ui_.editorLineEdit->setText(strTmp); + + strTmp = config_->getItemValue("preference", "editorarg"); + ui_.editorArgLineEdit->setText(strTmp); + + strTmp = config_->getItemValue("preference", "asciienhance"); + ui_.asciiEnhanceCheckBox->setChecked(strTmp == "1"); +} + +void prefDialog::saveSetting() { + + QString strTmp; + + strTmp.setNum(ui_.displayOffsetSlider->sliderPosition()); + config_->setItemValue("preference", "displayoffset", strTmp); + + strTmp.setNum(ui_.ximComboBox->currentIndex()); + config_->setItemValue("preference", "xim", strTmp); + + + config_->setItemValue("preference", "wordwrap", ui_.wordLineEdit3->text()); + + strTmp.setNum(ui_.smartCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "smartww", strTmp); + + strTmp.setNum(ui_.wheelCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "wheel", strTmp); + + strTmp.setNum(ui_.urlCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "url", strTmp); + + strTmp.setNum(ui_.saveCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "logmsg", strTmp); + + strTmp.setNum(ui_.blinkCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "blinktab", strTmp); + + strTmp.setNum(ui_.warnCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "warn", strTmp); + + strTmp.setNum(ui_.aacheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "antialias", strTmp); + + strTmp.setNum(ui_.trayCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "tray", strTmp); + + strTmp.setNum(ui_.enqCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "enq", strTmp); + + strTmp.setNum(soundButtonGroup_.checkedId()); + config_->setItemValue("preference", "beep", strTmp); + + strTmp.setNum(verticalSettingButtonGroup_.checkedId()); + config_->setItemValue("preference", "vsetting", strTmp); + + if (strTmp == "2") { + config_->setItemValue("preference", "wavefile", ui_.wavefileLineEdit->text()); + } + + strTmp.setNum(ui_.clearCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "clearpool", strTmp); + + strTmp.setNum(ui_.asciiEnhanceCheckBox->isChecked() ? 1 : 0); + config_->setItemValue("preference", "asciienhance", strTmp); + + strTmp = ui_.poolLineEdit->text(); + if (strTmp.isEmpty()) { + strTmp = getPath(USER_CONFIG) + "pool/"; + } + config_->setItemValue("preference", "pool", strTmp); + + strTmp = ui_.zmodemLineEdit->text(); + if (strTmp.isEmpty()) { + strTmp = getPath(USER_CONFIG) + "zmodem/"; + } + config_->setItemValue("preference", "zmodem", strTmp); + config_->setItemValue("preference", "http", ui_.httpLineEdit->text()); + config_->setItemValue("preference", "image", ui_.imageLineEdit->text()); + + config_->setItemValue("preference", "qssfile", ui_.styleSheetLineEdit->text().trimmed()); + + config_->setItemValue("preference", "editor", ui_.editorLineEdit->text()); + config_->setItemValue("preference", "editorarg", ui_.editorArgLineEdit->text()); + + config_->save(getPath(USER_CONFIG) + "fqterm.cfg"); +} + +void prefDialog::closeEvent(QCloseEvent*) { + reject(); +} + +void prefDialog::onOK() { + saveSetting(); + done(1); +} + +void prefDialog::onCancel() { + done(0); +} + +void prefDialog::onSound() { + soundConf soundconf(config_, this); + if (soundconf.exec() == 1) { + loadSetting(); + } + +} + +void prefDialog::onHttp() { + QString http = fileDialog_->getOpenName("Choose a WWW browser", "*"); + if (!http.isEmpty()) { + ui_.httpLineEdit->setText(http); + } + +} + +// void prefDialog::onBeep( int id ) +// { +// if(id==2) +// { +// ui.wavefileLineEdit->setEnabled(true); +// ui.selectsoundPushButton->setEnabled(true); +// } +// else if(id==0 || id==1 ) +// { +// ui.wavefileLineEdit->setEnabled(false); +// ui.selectsoundPushButton->setEnabled(false); +// } +// } + +void prefDialog::onBrowse() { + QString dir = fileDialog_->getExistingDirectory("Choose a directory", ui_.zmodemLineEdit->text()); + if (!dir.isEmpty()) { + ui_.zmodemLineEdit->setText(dir); + } +} + +void prefDialog::onImage() { + QString image = fileDialog_->getOpenName("Choose an Image Viewer", "*"); + if (!image.isEmpty()) { + ui_.imageLineEdit->setText(image); + } +} + +void prefDialog::onPool() { + QString pool = fileDialog_->getExistingDirectory("Choose a directory", ui_.poolLineEdit->text()); + if (!pool.isEmpty()) { + ui_.poolLineEdit->setText(pool); + } +} + +void prefDialog::onStyleSheet() +{ + QString qssFile = fileDialog_->getOpenName("Choose a QSS File", "Qt Style Sheets (*.qss *.QSS)"); + if (!qssFile.isEmpty()) { + ui_.styleSheetLineEdit->setText(qssFile); + } +} + +void prefDialog::onEditor() { + QString editor = fileDialog_->getOpenName("Choose a directory", ui_.editorLineEdit->text()); + if (!editor.isEmpty()) { + ui_.editorLineEdit->setText(editor); + } +} +} // namespace FQTerm + +#include "prefdialog.moc" diff --git a/src/ui/prefdialog.h b/src/ui/prefdialog.h new file mode 100644 index 0000000..99e58c6 --- /dev/null +++ b/src/ui/prefdialog.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_PREF_DIALOG_H +#define FQTERM_PREF_DIALOG_H + +#include "ui_prefdialog.h" +#include "fqterm_filedialog.h" + +class QCloseEvnt; + +namespace FQTerm { + +class FQTermConfig; + +class prefDialog: public QDialog { + Q_OBJECT; + public: + prefDialog(FQTermConfig *, QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~prefDialog(); + + protected slots: + void onOK(); + void onCancel(); + void onSound(); + void onHttp(); + // void onBeep(int); + void onBrowse(); + void onImage(); + void onPool(); + void onStyleSheet(); + void onEditor(); + protected: + void closeEvent(QCloseEvent*); + void connectSlots(); + void loadSetting(); + void saveSetting(); + + private: + Ui::prefDialog ui_; + QButtonGroup soundButtonGroup_; + QButtonGroup verticalSettingButtonGroup_; + FQTermConfig * config_; + FQTermFileDialog *fileDialog_; +}; + +} // namespace FQTerm + +#endif // FQTERM_PREF_DIALOG_H diff --git a/src/ui/prefdialog.ui b/src/ui/prefdialog.ui new file mode 100644 index 0000000..9aaf484 --- /dev/null +++ b/src/ui/prefdialog.ui @@ -0,0 +1,644 @@ + + + prefDialog + + + + 0 + 0 + 619 + 584 + + + + Preference + + + + + + 6 + + + 11 + + + + + Paste Word-Wrap At + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Enable Smart Word-Wrap + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 6 + + + 0 + + + + + Alternative Mouse Wheel Control + + + + + + + Detect URL When Mouse Move + + + + + + + Save Message To File + + + + + + + Blink Tab When Receive Message + + + + + + + Warn When Exit Connected + + + + + + + AntiAlias + + + + + + + Show As Tray When Close + + + + + + + Clear ZModem And HTTP Directory When Exit + + + + + + + Reply when ENQ received + + + + + + + ASCII Art Enhance Mode + + + + + + + + + Qt::Vertical + + + + + + + + + Sound When Receive Messages + + + + 11 + + + 6 + + + + + None + + + + + + + Beep + + + + + + + Sound File + + + + + + + + + + Configure + + + + + + + + + + 6 + + + 11 + + + + + Input Method + + + + + + + + GBK + + + + + BIG5 + + + + + + + + + + + + Display Offset + + + + + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 5 + + + + + + + + + + 0 + 40 + + + + Vertical Display + + + + + 11 + 15 + 84 + 18 + + + + Top + + + + + + 123 + 15 + 84 + 18 + + + + Middle + + + + + + 234 + 15 + 84 + 18 + + + + Bottom + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 287 + 28 + + + + + + + + + + + + + + Zmodem Directory + + + + + + + HTTP Directory + + + + + + + StyleSheet File + + + + + + + HTTP Browser + + + + + + + Image Viewer + + + + + + + Editor & Args + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Browse + + + + + + + Browse + + + + + + + Browse + + + + + + + Choose + + + + + + + Choose + + + + + + + Choose + + + + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + Qt::Horizontal + + + + + + + 6 + + + 11 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + wordLineEdit3 + smartCheckBox + wheelCheckBox + urlCheckBox + saveCheckBox + blinkCheckBox + warnCheckBox + aacheckBox + trayCheckBox + clearCheckBox + noneRadioButton + beepRadioButton + fileRadioButton + selectsoundPushButton + wavefileLineEdit + ximComboBox + zmodemLineEdit + browsePushButton + poolLineEdit + poolPushButton + httpLineEdit + choosehttpPushButton + imageLineEdit + imagePushButton + okPushButton + cancelPushButton + + + + + noneRadioButton + toggled(bool) + wavefileLineEdit + setDisabled(bool) + + + 290 + 95 + + + 290 + 125 + + + + + noneRadioButton + toggled(bool) + selectsoundPushButton + setDisabled(bool) + + + 360 + 80 + + + 420 + 120 + + + + + beepRadioButton + toggled(bool) + wavefileLineEdit + setDisabled(bool) + + + 393 + 90 + + + 366 + 129 + + + + + beepRadioButton + toggled(bool) + selectsoundPushButton + setDisabled(bool) + + + 413 + 92 + + + 449 + 125 + + + + + fileRadioButton + toggled(bool) + wavefileLineEdit + setEnabled(bool) + + + 467 + 97 + + + 380 + 126 + + + + + fileRadioButton + toggled(bool) + selectsoundPushButton + setEnabled(bool) + + + 502 + 86 + + + 493 + 128 + + + + + diff --git a/src/ui/progressBar.cpp b/src/ui/progressBar.cpp new file mode 100644 index 0000000..9da0479 --- /dev/null +++ b/src/ui/progressBar.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "fqterm_trace.h" +#include "fqterm_path.h" +#include "progressBar.h" + +namespace FQTerm { + +ProgressBar::ProgressBar(QWidget *parent, QLabel *label) + : QProgressBar(parent), + label_(label), + isFinished_(false) { + //DEBUG_FUNC_INFO + setMaximum(100); + label_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + abortButton_ = new QPushButton("Abort", parent); + abortButton_->setObjectName("Abort"); + abortButton_->hide(); + //m_abort->setText( tr("Abort") ); + abortButton_->setIcon(QPixmap(getPath(RESOURCE) + "pic/messagebox_critical.png")); + label_->show(); + show(); +} + +ProgressBar::~ProgressBar() { + //DEBUG_FUNC_INFO +} + +ProgressBar &ProgressBar::setDescription(const QString &text) { + description_ = text; + label_->setText(text); + + return *this; +} + +ProgressBar &ProgressBar::setStatus(const QString &text) { + QString s = description_; + s += " ["; + s += text; + s += ']'; + + label_->setText(s); + parentWidget()->adjustSize(); + + return *this; +} + +ProgressBar &ProgressBar::setAbortSlot(QObject *receiver, const char *slot) { + FQ_VERIFY(connect(abortButton_, SIGNAL(clicked()), receiver, slot)); + FQ_VERIFY(connect(abortButton_, SIGNAL(clicked()), this, SLOT(hide()))); + abortButton_->show(); + + parentWidget()->adjustSize(); + + return *this; +} + +void ProgressBar::setDone() { + if (!isFinished_) { + isFinished_ = true; + abortButton_->setEnabled(false); + setStatus(tr("Done")); + } else { + // then we we're aborted + setStatus(tr("Aborted")); + } +} + +void ProgressBar::hide() { + //NOTE naughty + + isFinished_ = true; + abortButton_->setEnabled(false); + setStatus(tr("Aborting...")); +} + +} // namespace FQTerm diff --git a/src/ui/progressBar.h b/src/ui/progressBar.h new file mode 100644 index 0000000..9c2f539 --- /dev/null +++ b/src/ui/progressBar.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +//WARNING this is not meant for use outside this unit! + +#ifndef FQTERM_PROGRESSBAR_H +#define FQTERM_PROGRESSBAR_H + +#include +#include + +class QLabel; +class QPushButton; + +namespace FQTerm { +/** + * @class KDE::ProgressBar + * @short ProgressBar class with some useful additions + */ +class ProgressBar: public QProgressBar { + friend class StatusBar; + + public: + /** @param text a 1-6 word description of the progress operation */ + ProgressBar &setDescription(const QString &text); + + /** @param text eg. Scanning, Reading. The state of the operation */ + ProgressBar &setStatus(const QString &text); + + /** set the recipient slot for the abort button */ + ProgressBar &setAbortSlot(QObject *receiver, const char *slot); + + void setDone(); + + QString description()const { + return description_; + } + + protected: + ProgressBar(QWidget *parent, QLabel *label); + ~ProgressBar(); + + virtual void hide(); + + QLabel *label_; + QString description_; + bool isFinished_; + + QPushButton *abortButton_; +}; + +} // namespace FQTerm + +#endif // FQTERM_PROGRESSBAR_H diff --git a/src/ui/quickdialog.cpp b/src/ui/quickdialog.cpp new file mode 100644 index 0000000..1ac3888 --- /dev/null +++ b/src/ui/quickdialog.cpp @@ -0,0 +1,258 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "fqterm_trace.h" +#include "fqterm_path.h" +#include "fqterm_config.h" +#include "fqterm_param.h" +#include "addrdialog.h" +#include "quickdialog.h" + +namespace FQTerm { + +//extern QString fileCfg; +//extern QString addrCfg; + +extern void saveAddress(FQTermConfig *, int, const FQTermParam &); + +const int quickDialog::ports[3] = {23, 22, 22}; + +quickDialog::quickDialog(FQTermConfig * config, QWidget *parent, Qt::WFlags fl) + : QDialog(parent, fl), + config_(config) { + ui_.setupUi(this); + + ui_.addPushButton->setIcon(QPixmap(getPath(RESOURCE) + "pic/address_book.png")); + + ui_.addPushButton->setToolTip(tr("Add To AddressBook")); + + ui_.connectPushButton->setDefault(true); + + connectSlots(); + + loadHistory(); + +// adjustSize(); +// setFixedSize(size()); + +} + +quickDialog::~quickDialog() { +} + +void quickDialog::closeEvent(QCloseEvent*) { + config_->save(getPath(USER_CONFIG) + "fqterm.cfg"); + reject(); +} + +void quickDialog::loadHistory() { + QString defaultIndex = config_->getItemValue("global", "quickdefaultindex"); + if (defaultIndex.isEmpty()) { + config_->setItemValue("global", "quick default index", "0"); + defaultIndex = "0"; + } + QString strTmp = config_->getItemValue("quick list", "num"); + QString strSection; + for (int i = 0; i < strTmp.toInt(); i++) { + strSection = QString("quick %1").arg(i); + ui_.historyComboBox->addItem(config_->getItemValue(strSection.toLatin1(), "addr")); + } + + int index = defaultIndex.toInt(); + if (strTmp.toInt() > index) { + ui_.historyComboBox->setCurrentIndex(index); + listChanged(index); + } +} + +void quickDialog::connectSlots() { + FQ_VERIFY(connect(ui_.historyComboBox, SIGNAL(activated(int)), this, SLOT(listChanged(int)))); + FQ_VERIFY(connect(ui_.protocolComboBox, SIGNAL(activated(int)), this, SLOT(onSelectProtocol(int)))); + FQ_VERIFY(connect(ui_.addPushButton, SIGNAL(clicked()), this, SLOT(onAdd()))); + FQ_VERIFY(connect(ui_.deletePushButton, SIGNAL(clicked()), this, SLOT(onDelete()))); + FQ_VERIFY(connect(ui_.advPushButton, SIGNAL(clicked()), this, SLOT(onAdvance()))); + FQ_VERIFY(connect(ui_.connectPushButton, SIGNAL(clicked()), this, SLOT(onConnect()))); + FQ_VERIFY(connect(ui_.closePushButton, SIGNAL(clicked()), this, SLOT(onClose()))); +} + +void quickDialog::listChanged(int index) { + QString strTmp = config_->getItemValue("quick list", "num"); + if (strTmp == "0") { + return ; + } + loadParam(index); + setUIFromParam(); +} + +void quickDialog::onAdd() { + setParamFromUI(); + + FQTermConfig *pAddrConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg"); + QString strTmp; + strTmp = pAddrConf->getItemValue("bbs list", "num"); + int num = strTmp.toInt(); + strTmp.setNum(num + 1); + pAddrConf->setItemValue("bbs list", "num", strTmp); + saveAddress(pAddrConf, num, param_); + pAddrConf->save(getPath(USER_CONFIG) + "address.cfg"); +} + +void quickDialog::onDelete() { + int index = ui_.historyComboBox->currentIndex(); + + QString strTmp = config_->getItemValue("quick list", "num"); + int num = strTmp.toInt(); + + if (num != 0 && index != -1) { + QString strSection = QString("quick %1").arg(index); + if (!config_->deleteSection(strSection.toLatin1())) { + return ; + } + ui_.historyComboBox->removeItem(index); + + for (int i = index + 1; i < num; i++) { + strTmp = QString("quick %1").arg(i); + strSection = QString("quick %1").arg(i - 1); + config_->renameSection(strTmp.toLatin1(), strSection.toLatin1()); + } + + strTmp = config_->getItemValue("quick list", "num"); + strTmp.setNum(qMax(0, strTmp.toInt() - 1)); + config_->setItemValue("quick list", "num", strTmp.toLatin1()); + + // update + if (num > 1) { + ui_.historyComboBox->setCurrentIndex(qMin(index, num - 2)); + listChanged(qMin(index, num - 2)); + } + } +} + +void quickDialog::onAdvance() { + setParamFromUI(); + + addrDialog set(this, param_, addrDialog::APPLY); + + if (set.exec() == 1) { + param_ = set.param(); + setUIFromParam(); + } +} + +void quickDialog::onConnect() { + if (ui_.historyComboBox->currentText().isEmpty() || ui_.portEdit->text().isEmpty()) { + QMessageBox mb("FQTerm", "address or port cant be blank", QMessageBox::Warning, + QMessageBox::Ok | QMessageBox::Default, 0, 0); + mb.exec(); + return ; + } + + setParamFromUI(); + FQTermParam newParam = param_; + loadParam(ui_.historyComboBox->currentIndex()); + + QString strTmp = config_->getItemValue("quick list", "num"); + if (strTmp.isEmpty() || strTmp == "-1") { + strTmp = "0"; + } + int num = strTmp.toInt(); + if (ui_.historyComboBox->currentIndex() == -1 || + newParam.hostAddress_ != param_.hostAddress_ || + newParam.protocolType_ != param_.protocolType_ || + newParam.port_ != param_.port_) { + //changed. add new info + param_ = newParam; + saveParam(num); + ui_.historyComboBox->addItem(param_.hostAddress_); + ui_.historyComboBox->setCurrentIndex(num); + config_->setItemValue("quick list", "num", QString("%1").arg(num + 1)); + } else { + param_ = newParam; + } + + config_->setItemValue("global", "quickdefaultindex", + QString("%1").arg(ui_.historyComboBox->currentIndex())); + done(1); +} + +void quickDialog::onClose() { + done(0); +} + +void quickDialog::onSelectProtocol(int index) +{ + ui_.portCheck->setChecked(false); + ui_.portEdit->setText(QString("%1").arg(ports[index])); +} + +void quickDialog::setUIFromParam() +{ + ui_.historyComboBox->setItemText(ui_.historyComboBox->currentIndex(), param_.hostAddress_); + ui_.protocolComboBox->setCurrentIndex(param_.protocolType_); + ui_.portEdit->setText(QString("%1").arg(param_.port_)); + if (param_.port_ != ports[param_.protocolType_]) { + ui_.portCheck->setChecked(true); + } + else { + ui_.portCheck->setChecked(false); + } +} + +void quickDialog::setParamFromUI() +{ + param_.name_ = ui_.historyComboBox->currentText(); + param_.hostAddress_ = ui_.historyComboBox->currentText(); + param_.protocolType_ = ui_.protocolComboBox->currentIndex(); + bool ok; + param_.port_ = ui_.portEdit->text().toInt(&ok); + if (!ok) { + param_.port_ = ports[param_.protocolType_]; + } +} + +void quickDialog::loadParam(int index) +{ + param_ = FQTermParam(); + QString strSection = QString("quick %1").arg(index); + param_.name_ = config_->getItemValue(strSection, "addr"); + param_.hostAddress_ = param_.name_; + param_.protocolType_ = config_->getItemValue(strSection, "protocol").toInt(); + param_.port_ = config_->getItemValue(strSection, "port").toInt(); +} + +void quickDialog::saveParam(int index) +{ + QString strSection = QString("quick %1").arg(index); + config_->setItemValue(strSection, "addr", param_.hostAddress_); + config_->setItemValue(strSection, "protocol", QString("%1").arg(param_.protocolType_)); + config_->setItemValue(strSection, "port", QString("%1").arg(param_.port_)); +} +} // namespace FQTerm + +#include "quickdialog.moc" diff --git a/src/ui/quickdialog.h b/src/ui/quickdialog.h new file mode 100644 index 0000000..bbcae89 --- /dev/null +++ b/src/ui/quickdialog.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_QUICK_DIALOG_H +#define FQTERM_QUICK_DIALOG_H + +#include "fqterm_param.h" +#include "ui_quickdialog.h" +//Added by qt3to4: +//#include + +class QCloseEvent; +class QResizeEvent; + +namespace FQTerm { + +class FQTermConfig; + +class quickDialog: public QDialog { + Q_OBJECT; + public: + quickDialog(FQTermConfig *, QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~quickDialog(); + + FQTermParam param_; + + static const int ports[3]; + + protected slots: + void listChanged(int); // + void onAdd(); + void onDelete(); + void onAdvance(); + void onConnect(); // + void onClose(); + void onSelectProtocol(int index); + + private: + + void closeEvent(QCloseEvent*); // + void connectSlots(); + void loadHistory(); // + void setUIFromParam(); + void setParamFromUI(); + void loadParam(int index); + void saveParam(int index); + + FQTermConfig *config_; + + private: + Ui::quickDialog ui_; +}; + +} // namespace FQTerm + +#endif // FQTERM_QUICK_DIALOG_H diff --git a/src/ui/quickdialog.ui b/src/ui/quickdialog.ui new file mode 100644 index 0000000..867596d --- /dev/null +++ b/src/ui/quickdialog.ui @@ -0,0 +1,211 @@ + + quickDialog + + + + 0 + 0 + 394 + 117 + + + + + 0 + 0 + + + + Quick Login + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + Host Name + + + + + + + + 0 + 0 + + + + true + + + QComboBox::NoInsert + + + true + + + + + + + Delete + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + + + Advanced + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Connect + + + + + + + Close + + + + + + + + + + + + 0 + 0 + + + + Protocol + + + + + + + + Telnet + + + + + SSH1 + + + + + SSH2 + + + + + + + + Port + + + + + + + false + + + + 0 + 0 + + + + 23 + + + + + + + + + + historyComboBox + deletePushButton + addPushButton + advPushButton + connectPushButton + closePushButton + + + + + portCheck + toggled(bool) + portEdit + setEnabled(bool) + + + 151 + 54 + + + 203 + 54 + + + + + diff --git a/src/ui/schemadialog.cpp b/src/ui/schemadialog.cpp new file mode 100644 index 0000000..d5a197b --- /dev/null +++ b/src/ui/schemadialog.cpp @@ -0,0 +1,323 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "fqterm_config.h" +#include "fqterm_path.h" +#include "fqterm_trace.h" + +#include "schemadialog.h" + +namespace FQTerm { + +schemaDialog::schemaDialog(QWidget *parent, Qt::WFlags fl) + : QDialog(parent, fl), + buttonGroup_(this) { + ui_.setupUi(this); + buttonGroup_.addButton(ui_.noneRadioButton, 0); + buttonGroup_.addButton(ui_.imageRadioButton, 1); + + lastItemID_ = -1; + isModified_ = false; + + ui_.alphaSlider->setMinimum(0); + ui_.alphaSlider->setMaximum(100); + ui_.alphaSlider->setSingleStep(1); + ui_.alphaSlider->setPageStep(10); + + // ui.bgButtonGroup->setRadioButtonExclusive(true); + colorButtons[0] = ui_.clr0Button; + colorButtons[1] = ui_.clr1Button; + colorButtons[2] = ui_.clr2Button; + colorButtons[3] = ui_.clr3Button; + colorButtons[4] = ui_.clr4Button; + colorButtons[5] = ui_.clr5Button; + colorButtons[6] = ui_.clr6Button; + colorButtons[7] = ui_.clr7Button; + colorButtons[8] = ui_.clr8Button; + colorButtons[9] = ui_.clr9Button; + colorButtons[10] = ui_.clr10Button; + colorButtons[11] = ui_.clr11Button; + colorButtons[12] = ui_.clr12Button; + colorButtons[13] = ui_.clr13Button; + colorButtons[14] = ui_.clr14Button; + colorButtons[15] = ui_.clr15Button; + + connectSlots(); + loadList(); +} + + +schemaDialog::~schemaDialog(){} + + +void schemaDialog::connectSlots() { + FQ_VERIFY(connect(ui_.saveButton, SIGNAL(clicked()), this, SLOT(saveSchema()))); + FQ_VERIFY(connect(ui_.removeButton, SIGNAL(clicked()), this, SLOT(removeSchema()))); + FQ_VERIFY(connect(ui_.okButton, SIGNAL(clicked()), this, SLOT(onOK()))); + FQ_VERIFY(connect(ui_.cancelButton, SIGNAL(clicked()), this, SLOT(onCancel()))); + + for (int i = 0; i < 16; ++i) { + FQ_VERIFY(connect(colorButtons[i], SIGNAL(clicked()), this, SLOT(buttonClicked()))); + } + + FQ_VERIFY(connect(ui_.nameListWidget, SIGNAL(currentRowChanged(int)), + this, SLOT(nameChanged(int)))); + + + FQ_VERIFY(connect(ui_.chooseButton, SIGNAL(clicked()), + this, SLOT(chooseImage()))); + + FQ_VERIFY(connect(ui_.titleLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(modified(const QString &)))); + FQ_VERIFY(connect(ui_.imageLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(modified(const QString &)))); + FQ_VERIFY(connect(ui_.alphaSlider, SIGNAL(valueChanged(int)), + this, SLOT(modified(int)))); + FQ_VERIFY(connect(ui_.optionComboBox, SIGNAL(activated(int)), + this, SLOT(modified(int)))); + FQ_VERIFY(connect(ui_.coverComboBox, SIGNAL(activated(int)), + this, SLOT(modified(int)))); + FQ_VERIFY(connect(ui_.noneRadioButton, SIGNAL(toggled(bool)), + this, SLOT(modified(bool)))); + FQ_VERIFY(connect(ui_.imageRadioButton, SIGNAL(toggled(bool)), + this, SLOT(modified(bool)))); + FQ_VERIFY(connect(ui_.alphaCheckBox, SIGNAL(toggled(bool)), + this, SLOT(modified(bool)))); +} + +void schemaDialog::loadList() { + QFileInfoList lstFile = getSchemaList(); + + //if(lstFile != NULL) + { + foreach(QFileInfo fi, lstFile) { + FQTermConfig *pConf = new FQTermConfig(fi.absoluteFilePath()); + QListWidgetItem* item = new QListWidgetItem(pConf->getItemValue("schema", "title"), ui_.nameListWidget); + item->setData(Qt::UserRole, fi.absoluteFilePath()); + ui_.nameListWidget->addItem(item); + delete pConf; + } + } + if (ui_.nameListWidget->count() != 0) { + ui_.nameListWidget->setCurrentRow(0); + } +} + +void schemaDialog::loadSchema(const QString &strSchemaFile) { + FQTermConfig *pConf = new FQTermConfig(strSchemaFile); + + title_ = pConf->getItemValue("schema", "title"); + //0 -- none 1 -- image + int type = pConf->getItemValue("background", "type").toInt(); + if (type == 0) { + ui_.noneRadioButton->setChecked(true); + } else if (type == 1) { + ui_.imageRadioButton->setChecked(true); + } + ui_.imageLineEdit->setText(pConf->getItemValue("image", "name")); + QString strTmp = pConf->getItemValue("image", "render"); + ui_.optionComboBox->setCurrentIndex(strTmp.toInt()); + strTmp = pConf->getItemValue("image", "cover"); + ui_.coverComboBox->setCurrentIndex(strTmp.toInt()); + ui_.alphaCheckBox->setChecked(pConf->getItemValue("image", "usealpha").toInt()); + ui_.alphaSlider->setValue(pConf->getItemValue("image", "alpha").toInt()); + + for (int i = 0; i < 16; ++i) { + colors[i].setNamedColor(pConf->getItemValue("color", QString("color%1").arg(i))); + } + + delete pConf; + + updateView(); + +} + +QFileInfoList schemaDialog::getSchemaList() { + QDir dir; + dir.setNameFilters(QStringList("*.schema")); + dir.setPath(getPath(USER_CONFIG) + "schema"); + return dir.entryInfoList(); +} + +int schemaDialog::saveNumSchema(int n) { + + int saved = n; + title_ = ui_.titleLineEdit->text(); + + QString schemaFileName = getPath(USER_CONFIG) + "schema/" + title_ + ".schema"; + QListWidgetItem* item = ui_.nameListWidget->currentItem(); + // create a new schema if title changed + QString test = ui_.nameListWidget->currentItem()->data(Qt::UserRole).toString(); + if (QFileInfo(schemaFileName) != QFileInfo(ui_.nameListWidget->item(n)->data(Qt::UserRole).toString())) { + item = new QListWidgetItem(title_, ui_.nameListWidget); + item->setData(Qt::UserRole, schemaFileName); + ui_.nameListWidget->addItem(item); + saved = ui_.nameListWidget->row(item); + } + + FQTermConfig *pConf = new FQTermConfig(ui_.nameListWidget->item(n)->data(Qt::UserRole).toString()); + + pConf->setItemValue("schema", "title", title_); + + QString strTmp; + //0 -- none 1 -- image + int type = 0; + + if (ui_.noneRadioButton->isChecked()) { + type = 0; + } else if (ui_.imageRadioButton->isChecked()) { + type = 1; + } + strTmp.setNum(type); + pConf->setItemValue("background", "type", strTmp); + + pConf->setItemValue("image", "name", ui_.imageLineEdit->text()); + + + strTmp.setNum(ui_.optionComboBox->currentIndex()); + pConf->setItemValue("image", "render", strTmp); + + strTmp.setNum(ui_.coverComboBox->currentIndex()); + pConf->setItemValue("image", "cover", strTmp); + + pConf->setItemValue("image", "usealpha", ui_.alphaCheckBox->isChecked() ? "1" : "0"); + + strTmp.setNum(ui_.alphaSlider->value()); + pConf->setItemValue("image", "alpha", strTmp); + + + for (int i = 0; i < 16; ++i) { + pConf->setItemValue("color", QString("color%1").arg(i), colors[i].name()); + } + + pConf->save(schemaFileName); + + delete pConf; + + clearModified(); + emit schemaEdited(); + return saved; +} + +void schemaDialog::updateView() { + // title + ui_.titleLineEdit->setText(title_); + for (int i = 0; i < 16; ++i) { + QPalette palette; + palette.setColor(QPalette::Button, colors[i]); + colorButtons[i]->setPalette(palette); + } + + // load from file, nothing changed + clearModified(); +} + +void schemaDialog::buttonClicked() { + QPushButton *button = (QPushButton*)sender(); + QColor color = + QColorDialog::getColor(button->palette().color(button->backgroundRole())); + if (color.isValid() == true) { + QPalette palette; + palette.setColor(QPalette::Button, color); + button->setPalette(palette); + modified(); + } + for (int i = 0; i < 16; ++i) { + if (colorButtons[i] == button) { + colors[i] = color; + break; + } + } +} + +void schemaDialog::nameChanged(int item) { + if (isModified_) { + QMessageBox mb("FQTerm", "Setting changed, do you want to save?", + QMessageBox::Warning, QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape, 0, this); + if (mb.exec() == QMessageBox::Yes) { + if (lastItemID_ != -1) { + saveNumSchema(lastItemID_); + } + } + } + + int n = item; //nameListBox->index(item); + lastItemID_ = n; + + + loadSchema(ui_.nameListWidget->item(n)->data(Qt::UserRole).toString()); + updateView(); + ui_.nameListWidget->setCurrentRow(n, QItemSelectionModel::Select); +} + + +void schemaDialog::chooseImage() { + QString img = QFileDialog::getOpenFileName( + this, "Choose an image", QDir::currentPath()); + if (!img.isNull()) { + ui_.imageLineEdit->setText(img); + isModified_ = true; + } +} + + + +void schemaDialog::saveSchema() { + // get current schema file name + int n = ui_.nameListWidget->currentRow(); + int saved = saveNumSchema(n); + lastItemID_ = saved; + ui_.nameListWidget->setCurrentRow(saved, QItemSelectionModel::Select); +} + +void schemaDialog::removeSchema() { + QFileInfo fi(ui_.nameListWidget->currentItem()->data(Qt::UserRole).toString()); + if (fi.isWritable()) { + QFile::remove(ui_.nameListWidget->currentItem()->data(Qt::UserRole).toString()); + int n = ui_.nameListWidget->currentRow(); + delete ui_.nameListWidget->takeItem(n); + emit schemaEdited(); + } else { + QMessageBox::warning(this, "Error", + "This is a system schema. Permission Denied"); + } +} + +void schemaDialog::onOK() { + saveSchema(); + done(1); +} + +void schemaDialog::onCancel() { + done(0); +} + + + + +} // namespace FQTerm + +#include "schemadialog.moc" diff --git a/src/ui/schemadialog.h b/src/ui/schemadialog.h new file mode 100644 index 0000000..c2ef977 --- /dev/null +++ b/src/ui/schemadialog.h @@ -0,0 +1,80 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SCHEMADIALOG_H +#define FQTERM_SCHEMADIALOG_H + +#include "ui_schemadialog.h" +#include +namespace FQTerm { + +class schemaDialog: public QDialog { + Q_OBJECT; + public: + schemaDialog(QWidget *parent = 0, Qt::WFlags fl = 0); + ~schemaDialog(); + + static QFileInfoList getSchemaList(); + protected: + QColor colors[16]; + QPushButton * colorButtons[16]; + QString title_; + QStringList fileList_; + + bool isModified_; + int lastItemID_; + private: + Ui::schemaDialog ui_; + QButtonGroup buttonGroup_; + + protected: + void connectSlots(); + + void loadList(); + void loadSchema(const QString &schemaFileName); + int saveNumSchema(int n = -1); + + void updateView(); + + protected slots: + void buttonClicked(); + void nameChanged(int); + void chooseImage(); + + void saveSchema(); + void removeSchema(); + + void onOK(); + void onCancel(); + + void modified(const QString&) {modified();} + void modified(int) {modified();} + void modified(bool) {modified();} + void modified() {isModified_ = true;} + + void clearModified() {isModified_ = false;} + +signals: + void schemaEdited(); +}; + +} // namespace FQTerm + +#endif // FQTERM_SCHEMADIALOG_H diff --git a/src/ui/schemadialog.ui b/src/ui/schemadialog.ui new file mode 100644 index 0000000..0d987bb --- /dev/null +++ b/src/ui/schemadialog.ui @@ -0,0 +1,539 @@ + + + schemaDialog + + + + 0 + 0 + 612 + 334 + + + + Schema Editor + + + + + + + + Title + + + + + + + + + + 0-7 + + + + + + + PointingHandCursor + + + true + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 8-15 + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + + + + + + Save + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Remove + + + + + + + + + + + + + OK + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + + + Background + + + + + + None + + + + + + + + + + + + Choose + + + + + + + Image + + + + + + + + Tile + + + + + Center + + + + + Scale + + + + + + + + + Whole + + + + + Padding + + + + + + + + + + + 0 + 0 + + + + Min + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Max + + + + + + + + + Alpha + + + + + + + Render + + + + + + + Coverage + + + + + + + + + false + + + + 16777215 + 0 + + + + + + + + false + + + + 16777215 + 0 + + + + + + + + Note: + Alpha will only apply on background + If Coverage is set to Padding + Alpha will take no effect + + + + + + + + + + + + + diff --git a/src/ui/shortcutdialog.cpp b/src/ui/shortcutdialog.cpp new file mode 100644 index 0000000..0b73ab3 --- /dev/null +++ b/src/ui/shortcutdialog.cpp @@ -0,0 +1,176 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "shortcutdialog.h" +#include "fqterm_shortcuthelper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace FQTerm +{ +FQTermShortcutDialog::FQTermShortcutDialog(FQTermShortcutHelper* helper, QWidget *parent_, Qt::WFlags fl) + : QDialog(parent_, fl), + helper_(helper), + table_(NULL) { + setWindowTitle(tr("Shortcut Setting")); + //grabKeyboard(); + if (helper_) + { + QSignalMapper* signalMapper = new QSignalMapper(this); + int row = FQTermShortcutHelper::FQTERM_APPLICATION_SHORTCUT_END - FQTermShortcutHelper::FQTERM_APPLICATION_SHORTCUT_START - 1; + int column = 3; + table_ = new QTableWidget(row, column, this); + table_->clear(); + QStringList header; + header << tr("Description") << tr("Shortcut") << ""; + table_->setHorizontalHeaderLabels(header); + for (int i = 0; i < row; ++i) { + for (int j = 0; j < column; ++j) { + if (j == 0) { + QTableWidgetItem* item = new QTableWidgetItem; + table_->setItem(i, j, item); + item->setFlags(item->flags() & ~Qt::ItemIsEditable); + item->setText(helper_->getShortcutDescription(i + 1)); + } else if (j == 1) { + FQTermShortcutTableWidget* stw = new FQTermShortcutTableWidget(table_); + stw->setReadOnly(true); + stw->setText(helper_->getShortcutText(i + 1)); + table_->setCellWidget(i, j, stw); + }else { + QPushButton* btn = new QPushButton(tr("default"), table_); + table_->setCellWidget(i, j, btn); + FQ_VERIFY(connect(btn, SIGNAL(clicked()), signalMapper, SLOT(map()))); + signalMapper->setMapping(btn, i); + } + } + } + table_->resizeColumnsToContents(); + int tableWidth = table_->horizontalHeader()->length(); + if (table_->horizontalScrollBar() && table_->horizontalScrollBar()->isVisible()) { + tableWidth += table_->horizontalScrollBar()->width(); + } + QPushButton* okBtn = new QPushButton(tr("OK"), this); + FQ_VERIFY(connect(okBtn, SIGNAL(clicked()), this, SLOT(okBtnClicked()))); + QPushButton* applyBtn = new QPushButton(tr("Apply"), this); + FQ_VERIFY(connect(applyBtn, SIGNAL(clicked()), this, SLOT(applyBtnClicked()))); + QPushButton* cancelBtn = new QPushButton(tr("Cancel"), this); + FQ_VERIFY(connect(cancelBtn, SIGNAL(clicked()), this, SLOT(cancelBtnClicked()))); + QPushButton* resetBtn = new QPushButton(tr("Reset All"), this); + FQ_VERIFY(connect(resetBtn, SIGNAL(clicked()), this, SLOT(resetBtnClicked()))); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + QGridLayout* layout = new QGridLayout(this); + QLabel* label = new QLabel(tr("Press key/combines on Shortcut column.\nNote Del is reserved for clear shortcut setting.")); + layout->addWidget(label, 0, 0, 1, -1); + layout->addWidget(table_, 1, 0, 1, -1); + layout->addWidget(okBtn, 2, 0); + layout->addWidget(applyBtn, 2, 1); + layout->addWidget(cancelBtn, 2, 2); + layout->addWidget(resetBtn, 2, 3); + setLayout(layout); + int left = 0; + int right = 0; + layout->getContentsMargins(&left, NULL, &right, NULL); + table_->horizontalHeader()->setStretchLastSection(true); + tableWidth *= 1.1; + resize(tableWidth + left + right, height()); + FQ_VERIFY(connect(signalMapper, SIGNAL(mapped(int)),this, SLOT(defaultClicked(int)))); + } +} + +FQTermShortcutDialog::~FQTermShortcutDialog() { + //releaseKeyboard(); +} + +void FQTermShortcutDialog::defaultClicked(int row) { + ((QLineEdit*)table_->cellWidget(row, 1))->setText(helper_->getShortcutDefaultText(row + 1)); +} + +void FQTermShortcutDialog::okBtnClicked() { + applyChanges(); + done(true); +} + +void FQTermShortcutDialog::applyBtnClicked() { + applyChanges(); +} + +void FQTermShortcutDialog::cancelBtnClicked() { + done(false); +} + +void FQTermShortcutDialog::resetBtnClicked() { + int row = FQTermShortcutHelper::FQTERM_APPLICATION_SHORTCUT_END - FQTermShortcutHelper::FQTERM_APPLICATION_SHORTCUT_START - 1; + for (int i = 0; i < row; ++i) { + ((QLineEdit*)table_->cellWidget(i, 1))->setText(helper_->getShortcutDefaultText(i + 1)); + } +} + +void FQTermShortcutDialog::applyChanges() { + int row = FQTermShortcutHelper::FQTERM_APPLICATION_SHORTCUT_END - FQTermShortcutHelper::FQTERM_APPLICATION_SHORTCUT_START - 1; + for (int i = 0; i < row; ++i) { + helper_->setShortcutText(i + 1, ((QLineEdit*)table_->cellWidget(i, 1))->text()); + } +} + +void FQTermShortcutTableWidget::keyReleaseEvent(QKeyEvent * event) { + if (event) { + event->accept(); + } +} + +void FQTermShortcutTableWidget::keyPressEvent(QKeyEvent * event) { + if (event) { + event->accept(); + if (event == QKeySequence::Delete) { + setText(""); + } else { + //Thank you hooey. + int key = event->key(); + Qt::KeyboardModifiers mod = event->modifiers(); + + if (key == Qt::Key_Shift || + key == Qt::Key_Control || + key == Qt::Key_Meta || + key == Qt::Key_Alt || + key == Qt::Key_AltGr) + return; + QString text = ""; + if (mod != Qt::NoModifier) { + QKeySequence seqMod(mod); + text = seqMod.toString(QKeySequence::NativeText); + } + QKeySequence seqKey(key); + text += seqKey.toString(QKeySequence::NativeText); + setText(text); + } + } +} + +}//namespace FQTerm + + +#include "shortcutdialog.moc" diff --git a/src/ui/shortcutdialog.h b/src/ui/shortcutdialog.h new file mode 100644 index 0000000..d8fd109 --- /dev/null +++ b/src/ui/shortcutdialog.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SHORTCUT_DIALOG_H +#define FQTERM_SHORTCUT_DIALOG_H +#include +#include +class QTableWidget; +namespace FQTerm +{ +class FQTermShortcutHelper; + +class FQTermShortcutTableWidget : public QLineEdit +{ +public: + FQTermShortcutTableWidget(QWidget* parent) : QLineEdit(parent) { + } +protected: + void keyReleaseEvent(QKeyEvent * event); + void keyPressEvent(QKeyEvent * event); +}; + +class FQTermShortcutDialog : public QDialog +{ + Q_OBJECT; +public: + FQTermShortcutDialog(FQTermShortcutHelper* helper, QWidget *parent_ = 0, Qt::WFlags fl = Qt::Dialog); + ~FQTermShortcutDialog(); +private: + FQTermShortcutHelper* helper_; + QTableWidget* table_; +protected slots: + void defaultClicked(int row); + void okBtnClicked(); + void applyBtnClicked(); + void cancelBtnClicked(); + void resetBtnClicked(); +private: + void applyChanges(); +}; +}//namespace FQTerm + + +#endif //FQTERM_SHORTCUT_DIALOG_H diff --git a/src/ui/sitemanager.cpp b/src/ui/sitemanager.cpp new file mode 100644 index 0000000..29f2ccd --- /dev/null +++ b/src/ui/sitemanager.cpp @@ -0,0 +1,412 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fqterm_config.h" +#include "fqterm_param.h" +#include "fqterm_param.h" +#include "fqterm_path.h" +#include "fqterm_trace.h" + +#include "sitemanager.h" + +namespace FQTerm{ + +int siteDialog::ports[] = {23, 22, 22, 0}; + +siteDialog::siteDialog(QWidget *parent_ /*= 0*/, Qt::WFlags fl /*= 0*/) + : QDialog(parent_, fl) { + ui_.setupUi(this); + + config_ = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg"); + QStringList name_list; + loadNameList(config_, name_list); + ui_.siteList->addItems(name_list); + + if (ui_.siteList->count() != 0) { + setCurrentSite(0); + loadCurrentParam(); + setUIFromParam(); + } + else { + ui_.editGroup->setDisabled(true); + } + connector(); +} + +siteDialog::~siteDialog() { + config_->save(getPath(USER_CONFIG) + "address.cfg"); + delete config_; +} + +void siteDialog::onSelectProtocol(int index) { + ui_.portCheck->setChecked(false); + ui_.portEdit->setText(QString("%1").arg(ports[index])); +} + +void siteDialog::setParamFromUI() { + param_.name_ = ui_.nameEdit->text(); + param_.hostAddress_ = ui_.addrEdit->text(); + param_.protocolType_ = ui_.protocolCombo->currentIndex(); + bool ok; + int port = ui_.portEdit->text().toInt(&ok); + param_.port_ = (ok && port >= 0 && port <= 65535)?port:ports[ui_.protocolCombo->currentIndex()]; + param_.hostType_ = ui_.hostTypeCombo->currentIndex(); + if (!ui_.proxyCheck->isChecked()) { + param_.proxyType_ = 0; + } + param_.isAutoLogin_ = ui_.autoLoginCheck->isChecked(); +} + +//auto fix errors. +void siteDialog::setUIFromParam() { + ui_.nameEdit->setText(param_.name_); + ui_.addrEdit->setText(param_.hostAddress_); + ui_.protocolCombo->setCurrentIndex(param_.protocolType_); + ui_.portCheck->setCheckState(param_.port_ == ports[ui_.protocolCombo->currentIndex()]?Qt::Unchecked:Qt::Checked); + ui_.portEdit->setText(QString("%1").arg(param_.port_)); + ui_.hostTypeCombo->setCurrentIndex(param_.hostType_); + ui_.proxyCheck->setCheckState(param_.proxyType_?Qt::Checked:Qt::Unchecked); + ui_.autoLoginCheck->setCheckState(param_.isAutoLogin_?Qt::Checked:Qt::Unchecked); + + previewFont(); +} + +void siteDialog::loadCurrentParam() { + if (ui_.siteList->count() == 0) { + return; + } + loadAddress(config_, currentSiteIndex(), param_); +} + +void siteDialog::saveCurrentParam() { + if (ui_.siteList->count() == 0) { + return; + } + saveAddress(config_, currentSiteIndex(), param_); +} + +void siteDialog::previewFont() { + //issue 98 + + QPalette palette; + palette.setColor(QPalette::Window, param_.backgroundColor_); + palette.setColor(QPalette::WindowText, param_.foregroundColor_); + ui_.fontPreviewer->setPalette(palette); + + QString sample("
AaBbCc"); + sample += QString("" + + param_.otherFontName_ + "
"); + ui_.fontPreviewer->setText(sample); +} + +void siteDialog::swapSite(int first, int second) { + FQTermParam firstParam; + FQTermParam secondParam; + loadAddress(config_, first, firstParam); + loadAddress(config_, second, secondParam); + saveAddress(config_, first, secondParam); + saveAddress(config_, second, firstParam); + + QListWidgetItem* firstItem = ui_.siteList->item(first); + QListWidgetItem* secondItem = ui_.siteList->item(second); + QString tmpStr = firstItem->text(); + firstItem->setText(secondItem->text()); + secondItem->setText(tmpStr); +} + +int siteDialog::moveSite(int pos, int offset) +{ + int newPos = pos + offset; + int step = offset>0?1:-1; + if (newPos >= ui_.siteList->count() || newPos < 0) { + return pos; + } + for(int i = pos; i != newPos; i += step) { + swapSite(i , i + step); + } + return newPos; +} + +QMessageBox::StandardButton siteDialog::checkModification(int row) { //with current display + FQTermParam originParam; + loadAddress(config_, row, originParam); + setParamFromUI(); + QMessageBox::StandardButton ret = QMessageBox::No; + if (!(originParam == param_)) { + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setWindowTitle(tr("Warning")); + msgBox.setText(tr("The site configuration has been changed.\nTo save, press Yes.\nTo discard, press No.\nTo continue editing, press Cancel")); + + + switch(ret = static_cast(msgBox.exec())) { + case QMessageBox::No: + param_ = originParam; + break; + default: + break; + } + ui_.siteList->item(row)->setText(param_.name_); + } + return ret; +} + +void siteDialog::onSelectSite(QListWidgetItem* current, QListWidgetItem* previous) +{ + int currentRow = ui_.siteList->row(current); + int previousRow = ui_.siteList->row(previous); + if (currentRow < 0) { + ui_.editGroup->setDisabled(true); + } + else { + ui_.editGroup->setEnabled(true); + } + if (previousRow >= 0){ + if (checkModification(previousRow) == QMessageBox::Cancel) { + forcedSetCurrentSite(previousRow); + return; + } + saveAddress(config_, previousRow, param_); + } + if (currentRow >= 0){ + loadAddress(config_, currentRow, param_); + setUIFromParam(); + } + +} + +//without emit a signal +void siteDialog::forcedSetCurrentSite(int row) +{ + FQ_VERIFY(disconnect(ui_.siteList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, SLOT(onSelectSite(QListWidgetItem*, QListWidgetItem*)))); + ui_.siteList->setCurrentRow(row); + FQ_VERIFY(connect(ui_.siteList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, SLOT(onSelectSite(QListWidgetItem*, QListWidgetItem*)))); +} + +//emit a signal +void siteDialog::setCurrentSite(int row) +{ + ui_.siteList->setCurrentRow(row); +} + +void siteDialog::removeSite(int row) +{ + if (row < 0) { + return; + } + int last = ui_.siteList->count() - 1; + setCurrentSite(last - 1); + moveSite(row, last - row); + config_->deleteSection(QString("%1").arg(last)); + config_->setItemValue("bbs list", "num", QString("%1").arg(last)); + delete ui_.siteList->takeItem(last); + + loadCurrentParam(); + setUIFromParam(); +} + +void siteDialog::onNew() { + int row = ui_.siteList->count(); + if (row < 0) { + row = 0; + } + config_->setItemValue("bbs list", "num", QString("%1").arg(row + 1)); + + FQTermParam newParam; + loadAddress(config_, -1, newParam); + saveAddress(config_, row, newParam); + ui_.siteList->addItem(newParam.name_); + setCurrentSite(row); +} + +void siteDialog::onDelete() { + if (ui_.siteList->count() == 0) { + return; + } + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setWindowTitle(tr("Warning")); + msgBox.setText(tr("Are you sure to DELETE this site?")); + switch(msgBox.exec()) + { + case QMessageBox::Yes: + removeSite(currentSiteIndex()); + break; + case QMessageBox::No: + break; + } +} + +void siteDialog::siteNameChanged( QString name ) { + QListWidgetItem* item = ui_.siteList->currentItem(); + if (item) { + item->setText(name); + } +} + +void siteDialog::setSiteSelected() { + int row = currentSiteIndex(); + if(row >= 0) { + ui_.siteList->item(row)->setSelected(true); + } +} + +void siteDialog::close(int doneValue) { + if (ui_.siteList->count() > 0) { + switch(checkModification(currentSiteIndex())) { + case QMessageBox::Yes: + onApply(); + break; + case QMessageBox::No: + loadCurrentParam(); + break; + case QMessageBox::Cancel: + return; + default: + break; + } + } + done(doneValue); +} + +void siteDialog::onReset() { + loadCurrentParam(); + setUIFromParam(); +} + +void siteDialog::onApply() { + setParamFromUI(); + saveCurrentParam(); + setUIFromParam(); +} + +void siteDialog::onUp() { + int newPos = moveSite(currentSiteIndex(), -1); + forcedSetCurrentSite(newPos); +} + +void siteDialog::onDown() { + int newPos = moveSite(currentSiteIndex(), 1); + forcedSetCurrentSite(newPos); +} + +void siteDialog::onClose() { + close(0); +} + +void siteDialog::onConnect() { + close(1); +} + +void siteDialog::resizeEvent( QResizeEvent * re ) { + previewFont(); +} + +FQTermParam siteDialog::currentParameter() { + return param_; +} + +int siteDialog::currentSiteIndex() { + return ui_.siteList->currentRow(); +} + +void siteDialog::onAdvance() { + setting(addrDialog::General); +} + +void siteDialog::setting(addrDialog::Tabs tab) { + setParamFromUI(); + addrDialog addr(this, param_, addrDialog::APPLY); + addr.setCurrentTabIndex(tab); + int res = addr.exec(); + if (res == 1) { + param_ = addr.param(); + setUIFromParam(); + } +} + +void siteDialog::onProxy() { + setting(addrDialog::Proxy); +} + +void siteDialog::onAutoLogin() { + setting(addrDialog::General); +} + +void siteDialog::onDblClicked(QListWidgetItem * item) { + onConnect(); +} + +void siteDialog::connector() { + FQ_VERIFY(connect(ui_.siteList, SIGNAL(itemSelectionChanged()), + this, SLOT(setSiteSelected()))); + FQ_VERIFY(connect(ui_.siteList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, SLOT(onSelectSite(QListWidgetItem*, QListWidgetItem*)))); + FQ_VERIFY(connect(ui_.nameEdit, SIGNAL(textChanged(QString)), + this, SLOT(siteNameChanged(QString)))); + FQ_VERIFY(connect(ui_.protocolCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(onSelectProtocol(int)))); + FQ_VERIFY(connect(ui_.resetButton, SIGNAL(clicked()), + this, SLOT(onReset()))); + FQ_VERIFY(connect(ui_.upButton, SIGNAL(clicked()), + this, SLOT(onUp()))); + FQ_VERIFY(connect(ui_.downButton, SIGNAL(clicked()), + this, SLOT(onDown()))); + FQ_VERIFY(connect(ui_.newButton, SIGNAL(clicked()), + this, SLOT(onNew()))); + FQ_VERIFY(connect(ui_.deleteButton, SIGNAL(clicked()), + this, SLOT(onDelete()))); + FQ_VERIFY(connect(ui_.applyButton, SIGNAL(clicked()), + this, SLOT(onApply()))); + FQ_VERIFY(connect(ui_.closeButton, SIGNAL(clicked()), + this, SLOT(onClose()))); + FQ_VERIFY(connect(ui_.connectButton, SIGNAL(clicked()), + this, SLOT(onConnect()))); + FQ_VERIFY(connect(ui_.advanceButton, SIGNAL(clicked()), + this, SLOT(onAdvance()))); + FQ_VERIFY(connect(ui_.proxyButton, SIGNAL(clicked()), + this, SLOT(onProxy()))); + FQ_VERIFY(connect(ui_.autoLoginButton, SIGNAL(clicked()), + this, SLOT(onAutoLogin()))); + FQ_VERIFY(connect(ui_.siteList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), + this, SLOT(onDblClicked(QListWidgetItem *)))); +} + +} //namespace FQTerm + +#include "sitemanager.moc" diff --git a/src/ui/sitemanager.h b/src/ui/sitemanager.h new file mode 100644 index 0000000..6aae387 --- /dev/null +++ b/src/ui/sitemanager.h @@ -0,0 +1,104 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SITEMANGER_H +#define FQTERM_SITEMANGER_H + +#include "addrdialog.h" + +#include "ui_sitemanager.h" +#include "ui_quickdialog.h" + +class QListWidgetItem; + +namespace FQTerm { +class FQTermParam; +class FQTermConfig; + +class siteDialog: public QDialog { + Q_OBJECT; + public: + siteDialog(QWidget *parent_ = 0, Qt::WFlags fl = 0);; + ~siteDialog(); + + FQTermParam currentParameter(); + + int currentSiteIndex(); + + private: + void connector(); + + void resizeEvent(QResizeEvent * re); + + //Note: changes are made on config_ + void saveCurrentParam(); + void loadCurrentParam(); + + void setParamFromUI(); + void setUIFromParam(); + + void previewFont(); + + void swapSite(int first, int second); + int moveSite(int pos, int offset); + void forcedSetCurrentSite(int row); + void setCurrentSite(int row); + + QMessageBox::StandardButton checkModification(int row); + + void removeSite(int row); + + void close(int doneValue); + void setting(addrDialog::Tabs tab); + + + protected slots: + void onSelectSite(QListWidgetItem* current, QListWidgetItem* previous); + void siteNameChanged(QString name); + void setSiteSelected(); + + void onSelectProtocol(int index); + + void onReset(); + void onApply(); + void onUp(); + void onDown(); + void onNew(); + void onDelete(); + void onClose(); + void onConnect(); + + void onAdvance(); + void onProxy(); + void onAutoLogin(); + void onDblClicked(QListWidgetItem * item); + + private: + FQTermConfig *config_; + FQTermParam param_; + + Ui::siteManager ui_; + + static int ports[]; //telnet, ssh1, ssh2 +}; + +} //FQTerm namespace + +#endif // FQTERM_SITEMANGER_H diff --git a/src/ui/sitemanager.ui b/src/ui/sitemanager.ui new file mode 100644 index 0000000..9b085ed --- /dev/null +++ b/src/ui/sitemanager.ui @@ -0,0 +1,593 @@ + + siteManager + + + + 0 + 0 + 481 + 495 + + + + Address Book + + + + + + + + + + + &Up + + + + + + + &Down + + + + + + + + + + + + + + + Site Name + + + + + + + + + + Address + + + + + + + + + + Protocol + + + + + + + + Telnet + + + + + SSH1 + + + + + SSH2 + + + + + + + + Port + + + + + + + false + + + + + + + + + + Host Type + + + + + + + + BBS + + + + + *NIX + + + + + + + + + 0 + 0 + + + + Use Proxy + + + + + + + false + + + Setting... + + + + + + + Auto Login + + + + + + + false + + + + 0 + 0 + + + + Setting... + + + + + + + Font Preview + + + + + + + true + + + Font Previewer + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + + 55 + 25 + + + + + + + + &Reset + + + + + + + Qt::Horizontal + + + + 54 + 25 + + + + + + + + A&dvance + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + &New + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Delete + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + C&onnect + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Save + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Close + + + + + + + + + + 9 + 553 + 31 + 0 + + + + + 16777215 + 0 + + + + + + + + + + 120 + 553 + 30 + 0 + + + + + 16777215 + 0 + + + + + + + + + + 156 + 553 + 78 + 0 + + + + + 16777215 + 0 + + + + + + + + + + 240 + 553 + 69 + 0 + + + + + 16777215 + 0 + + + + + + + + + + 410 + 553 + 34 + 0 + + + + + 16777215 + 0 + + + + + + + + + + 369 + 553 + 35 + 0 + + + + + 16777215 + 0 + + + + + + + + + + 46 + 553 + 30 + 0 + + + + + 16777215 + 0 + + + + + + + + + + 82 + 553 + 32 + 0 + + + + + 16777215 + 0 + + + + + + + + + + 315 + 553 + 48 + 0 + + + + + 16777215 + 0 + + + + + + + + + siteList + nameEdit + addrEdit + protocolCombo + portCheck + portEdit + hostTypeCombo + proxyCheck + autoLoginCheck + connectButton + upButton + downButton + resetButton + advanceButton + newButton + deleteButton + applyButton + closeButton + proxyButton + autoLoginButton + + + + + portCheck + toggled(bool) + portEdit + setEnabled(bool) + + + 372 + 81 + + + 477 + 83 + + + + + proxyCheck + toggled(bool) + proxyButton + setEnabled(bool) + + + 235 + 141 + + + 285 + 126 + + + + + autoLoginCheck + toggled(bool) + autoLoginButton + setEnabled(bool) + + + 232 + 155 + + + 361 + 172 + + + + + diff --git a/src/ui/soundconf.cpp b/src/ui/soundconf.cpp new file mode 100644 index 0000000..2681b83 --- /dev/null +++ b/src/ui/soundconf.cpp @@ -0,0 +1,178 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include + +#include "fqterm.h" +#include "fqterm_config.h" +#include "fqterm_path.h" +#include "fqterm_sound.h" + +#include "soundconf.h" + +namespace FQTerm { +/* + * Constructs a fSoundConf which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ + +soundConf::soundConf(FQTermConfig * config, QWidget *parent, Qt::WFlags fl) + : QDialog(parent, fl), + buttonGroup_(this), + config_(config){ + ui_.setupUi(this); + buttonGroup_.addButton(ui_.radioButton1, 0); + buttonGroup_.addButton(ui_.radioButton2, 1); + sound_ = NULL; + loadSetting(); + FQ_VERIFY(connect(ui_.bfSelect, SIGNAL(clicked()), + this, SLOT(onSelectFile()))); + FQ_VERIFY(connect(ui_.bpSelect, SIGNAL(clicked()), + this, SLOT(onSelectProg()))); + FQ_VERIFY(connect(ui_.bpTest, SIGNAL(clicked()), + this, SLOT(onTestPlay()))); + FQ_VERIFY(connect(ui_.bOK, SIGNAL(clicked()), + this, SLOT(accept()))); + FQ_VERIFY(connect(ui_.bCancel, SIGNAL(clicked()), + this, SLOT(reject()))); +} + +/* + * Destroys the object and frees any allocated resources + */ +soundConf::~soundConf() { + // no need to delete child widgets, Qt does it all for us +} + +/* + * public slot + */ +void soundConf::onSelectFile() { + FQTermFileDialog fileDialog(config_); + QString soundfile = fileDialog.getOpenName("Choose a WAVE file", "WAVE Audio Files (*.wav *.WAV)"); + if (!soundfile.isEmpty()) { + ui_.leFile->setText(soundfile); + } +} + +/* + * public slot + */ +void soundConf::onSelectProg() { + FQTermFileDialog fileDialog(config_); + QString progfile = fileDialog.getOpenName("Choose a program", ""); + if (!progfile.isEmpty()) { + ui_.leProg->setText(progfile); + } +} + +/* + * public slot + */ +void soundConf::onPlayMethod(int id) { +FQ_TRACE("sconf", 0) << id << ": " << buttonGroup_.checkedId(); + ui_.bpSelect->setEnabled(id == 1 || buttonGroup_.checkedId() == 1); +} + +void soundConf::onTestPlay() { + if (ui_.leFile->text().isEmpty()) { + QMessageBox::critical(this, tr("No sound file"), + tr("You have to select a file to test the sound"), tr("&Ok")); + + return; + } + + sound_ = NULL; + + switch (buttonGroup_.checkedId()) { + case 0: + sound_ = new FQTermSystemSound(ui_.leFile->text()); + break; + case 1: + if (ui_.leProg->text().isEmpty()) { + QMessageBox::critical(this, tr("No player"), + tr("You have to specify an external player"), tr("&Ok")); + + break; + } + + sound_ = new FQTermExternalSound(ui_.leProg->text(), ui_.leFile->text()); + break; + } + + if (sound_) { + sound_->start(); + } +} + +void soundConf::loadSetting() { + + QString strTmp; + + strTmp = config_->getItemValue("preference", "wavefile"); + if (!strTmp.isEmpty()) { + ui_.leFile->setText(strTmp); + } + + strTmp = config_->getItemValue("preference", "playmethod"); + + int valTmp = !strTmp.isEmpty()? strTmp.toInt(): -1; + + if (valTmp >= 0 && valTmp <= 1) { + buttonGroup_.button(valTmp)->setChecked(true); + if (valTmp == 1) { + strTmp = config_->getItemValue("preference", "externalplayer"); + if (!strTmp.isEmpty()) { + ui_.leProg->setText(strTmp); + } + } + } +} + +void soundConf::saveSetting() { + + QString strTmp; + + config_->setItemValue("preference", "beep", "2"); + + config_->setItemValue("preference", "wavefile", ui_.leFile->text()); + + strTmp.setNum(buttonGroup_.checkedId()); + config_->setItemValue("preference", "playmethod", strTmp); + + if (strTmp == "1") { + config_->setItemValue("preference", "externalplayer", ui_.leProg->text()); + } + + config_->save(getPath(USER_CONFIG) + "fqterm.cfg"); +} + +void soundConf::accept() { + saveSetting(); + QDialog::accept(); +} + +} // namespace FQTerm + +#include "soundconf.moc" diff --git a/src/ui/soundconf.h b/src/ui/soundconf.h new file mode 100644 index 0000000..5b4fe4c --- /dev/null +++ b/src/ui/soundconf.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SOUND_CONF_H +#define FQTERM_SOUND_CONF_H + +#include "ui_soundconf.h" +#include "fqterm_filedialog.h" + +namespace FQTerm { + +class FQTermSound; +class FQTermConfig; + +class soundConf: public QDialog { + Q_OBJECT; + public: + soundConf(FQTermConfig *, QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~soundConf(); + void loadSetting(); + void saveSetting(); + + public slots: + void onSelectFile(); + void onSelectProg(); + void onPlayMethod(int id); + void onTestPlay(); + protected slots: + void accept(); + + private: + FQTermSound *sound_; + Ui::soundConf ui_; + QButtonGroup buttonGroup_; + FQTermConfig * config_; +}; + +} // namespace FQTerm + +#endif // FQTERM_SOUND_CONF_H diff --git a/src/ui/soundconf.ui b/src/ui/soundconf.ui new file mode 100644 index 0000000..9cfe761 --- /dev/null +++ b/src/ui/soundconf.ui @@ -0,0 +1,162 @@ + + soundConf + + + true + + + + 0 + 0 + 308 + 269 + + + + Configure + + + + + + Sound File: + + + + + + + + + Select... + + + + + + + + + + Play With: + + + + + + true + + + Internal + + + + + + + true + + + External + + + + + + + Test + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + false + + + External Program: + + + + + + + + + Select... + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + + + radioButton2 + toggled(bool) + groupBox_3 + setEnabled(bool) + + + 124 + 136 + + + 123 + 176 + + + + + diff --git a/src/ui/sshlogin.ui b/src/ui/sshlogin.ui new file mode 100644 index 0000000..8794a57 --- /dev/null +++ b/src/ui/sshlogin.ui @@ -0,0 +1,75 @@ + + + SSHLogin + + + + 0 + 0 + 295 + 170 + + + + Login + + + + + + + 0 + 0 + + + + Please enter your username and password + + + + + + + UserName: + + + + + + + + + + Password: + + + + + + + + + + Qt::NoFocus + + + OK + + + + + + + Qt::NoFocus + + + Cancel + + + + + + + + + diff --git a/src/ui/sshlogindialog.cpp b/src/ui/sshlogindialog.cpp new file mode 100644 index 0000000..cd858cb --- /dev/null +++ b/src/ui/sshlogindialog.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include + +#include "fqterm_trace.h" +#include "sshlogindialog.h" + +namespace FQTerm { + +/* + * Constructs a fSSHLogin which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +SSHLoginDialog::SSHLoginDialog(QString *username, QString *password, + QWidget *parent_, Qt::WFlags fl) + : QDialog(parent_, fl) { + ui_.setupUi(this); + setWindowTitle(parent_->windowTitle()); + strUserName = username; + strPassword = password; + ui_.lePassword->setEchoMode(QLineEdit::Password); + ui_.leUserName->setText(*username); + ui_.lePassword->setText(*password); + if (!username->isEmpty()) { + ui_.leUserName->setDisabled(true); + ui_.lePassword->setFocus(); + } else { + ui_.leUserName->setDisabled(false); + ui_.leUserName->setFocus(); + } + + FQ_VERIFY(connect(ui_.bOK, SIGNAL(clicked()), this, SLOT(accept()))); + FQ_VERIFY(connect(ui_.bCancel, SIGNAL(clicked()), this, SLOT(reject()))); + FQ_VERIFY(connect(ui_.leUserName, SIGNAL(returnPressed()), this, SLOT(moveFocus()))); + FQ_VERIFY(connect(ui_.lePassword, SIGNAL(returnPressed()), this, SLOT(accept()))); +} + +/* + * Destroys the object and frees any allocated resources + */ +SSHLoginDialog::~SSHLoginDialog() { + // no need to delete child widgets, Qt does it all for us +} + +void SSHLoginDialog::accept() { + *strUserName = ui_.leUserName->text(); + *strPassword = ui_.lePassword->text(); + QDialog::accept(); +} + +void SSHLoginDialog::moveFocus() +{ + ui_.lePassword->setFocus(); +} + +} // namespace FQTerm + +#include "sshlogindialog.moc" diff --git a/src/ui/sshlogindialog.h b/src/ui/sshlogindialog.h new file mode 100644 index 0000000..e3295cc --- /dev/null +++ b/src/ui/sshlogindialog.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_LOGIN_H +#define FQTERM_SSH_LOGIN_H + +#include "ui_sshlogin.h" + +namespace FQTerm { + +class SSHLoginDialog: public QDialog { + Q_OBJECT; +public: + SSHLoginDialog(QString *username, QString *password, + QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~SSHLoginDialog(); +private: + QString *strUserName; + QString *strPassword; + Ui::SSHLogin ui_; +private slots: + void accept(); + void moveFocus(); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_LOGIN_H diff --git a/src/ui/statusBar.cpp b/src/ui/statusBar.cpp new file mode 100644 index 0000000..be48fc4 --- /dev/null +++ b/src/ui/statusBar.cpp @@ -0,0 +1,530 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fqterm_trace.h" +#include "fqterm_path.h" + +#include "popupMessage.h" +#include "progressBar.h" +#include "overlayWidget.h" +#include "statusBar.h" + +namespace FQTerm { + +//TODO allow for uncertain progress periods + +StatusBar *StatusBar::singletonStatusBar_ = 0; + +StatusBar::StatusBar(QWidget *parent, const char *name) + : QWidget(parent) { + setObjectName(name); + singletonStatusBar_ = this; + QBoxLayout *mainlayout = new QHBoxLayout(this); //, 2, /*spacing*/5 ); + mainlayout->setMargin(0); + mainlayout->setSpacing(5); + + //we need extra spacing due to the way we paint the surrounding boxes + QBoxLayout *layout = new QHBoxLayout; + layout->setSpacing(5); + mainlayout->addLayout(layout); + + m_mainTextLabel = new QLabel(this); + m_mainTextLabel->setObjectName("mainTextLabel"); + m_mainTextLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored); + + QWidget *mainProgressBarBox = new QWidget(this); + mainProgressBarBox->setObjectName("progressBox"); + + QHBoxLayout *mainProgressBarLayout = new QHBoxLayout(mainProgressBarBox); + mainProgressBarLayout->setContentsMargins(0, 0, 0, 0); + + QToolButton *b1 = new QToolButton(mainProgressBarBox); + b1->setObjectName("cancelButton"); + b1->setContentsMargins(0, 0, 0, 0); + b1->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored); + mainProgressBarLayout->addWidget(b1); + + mainProgressBar_ = new QProgressBar(mainProgressBarBox); + mainProgressBar_->setObjectName("mainProgressBar"); + mainProgressBarLayout->addWidget(mainProgressBar_); + + QToolButton *b2 = new QToolButton(mainProgressBarBox); + b2->setObjectName("showAllProgressDetails"); + b2->setContentsMargins(0,0,0,0); + b2->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored); + mainProgressBarLayout->addWidget(b2); + + mainProgressBarLayout->setSpacing(2); + mainProgressBarBox->hide(); + + layout->addWidget(mainProgressBarBox); + layout->addWidget(m_mainTextLabel); + + layout->setStretchFactor(m_mainTextLabel, 2); + layout->setStretchFactor(mainProgressBarBox, 1); + + otherWidgetLayout_ = new QHBoxLayout; + otherWidgetLayout_->setSpacing(0); + mainlayout->addLayout(otherWidgetLayout_); + + mainlayout->setStretchFactor(layout, 6); + mainlayout->setStretchFactor(otherWidgetLayout_, 4); + + b1->setIcon(QPixmap(getPath(RESOURCE) + "pic/messagebox_critical.png")); + b2->setIcon(QPixmap(getPath(RESOURCE) + "pic/messagebox_info.png")); + b2->setCheckable(true); + b1->setToolTip(tr("Abort all background-operations")); + b2->setToolTip(tr("Show progress detail")); + + FQ_VERIFY(connect(b1, SIGNAL(clicked()), SLOT(abortAllProgressOperations()))); + FQ_VERIFY(connect(b2, SIGNAL(toggled(bool)), SLOT(toggleProgressWindow(bool)))); + + popupProgressMessage_ = new PopupMessage(this, mainProgressBarBox, 0); + popupProgressMessage_->showCloseButton(false); + popupProgressMessage_->showCounter(false); + + popupProgressMessage_->setFrameStyle(QFrame::Box | QFrame::Raised); + popupProgressMessage_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); +} + +void StatusBar::addWidget(QWidget *widget) { + otherWidgetLayout_->addWidget(widget); +} + + +/// reimplemented functions + +void StatusBar::ensurePolished() { + QWidget::ensurePolished(); + + int h = 0; + QObjectList list = children(); + + //for( QObject * o = list.first(); o; o = list.next() ) { + foreach(QObject *o, list) { + if (o->inherits("QWidget")) { + int _h = static_cast < QWidget * > (o)->minimumSizeHint().height(); + if (_h > h) { + h = _h; + } + + + if (o->inherits("QLabel")) { + static_cast < QLabel * > (o)->setIndent(4); + } + } + } + + h -= 4; // it's too big usually + + //for ( QObject * o = list.first(); o; o = list.next() ) + foreach(QObject *o, list)static_cast < QWidget * > (o)->setFixedHeight(h); + + //delete list; +} + +void StatusBar::paintEvent(QPaintEvent*) { + QObjectList list = children(); //queryList( "QWidget", 0, false, false ); + QPainter p(this); + + //for( QObject * o = list.first(); o; o = list.next() ) { + foreach(QObject *o, list) { + if (o->inherits("QWidget")) { + QWidget *w = (QWidget*)o; + + if (!w->isVisible()) { + continue; + } + + /*style().drawPrimitive( + QStyle::PE_StatusBarSection, + &p, + QRect( w->x() - 1, w->y() - 1, w->width() + 2, w->height() + 2 ), + colorGroup(), + QStyle::State_None, + QStyleOption( w ) );*/ + } + } + + //delete list; +} + +bool StatusBar::event(QEvent *e) { + if (e->type() == QEvent::LayoutRequest) { + update(); + } + + return QWidget::event(e); +} + + +/// Messaging system + +void StatusBar::setMainText(const QString &text) { + mainText_ = text; + + // it may not be appropriate for us to set the mainText yet + resetMainText(); +} + +void StatusBar::shortMessage(const QString &text) { + m_mainTextLabel->setText(text); + m_mainTextLabel->setPalette(QToolTip::palette()); + + //SingleShotPool::startTimer( 5000, this, SLOT(resetMainText()) ); + resetMainText(); +} + +void StatusBar::resetMainText() { + /* + if( sender() ) + debug() << sender()->name() << endl; + + // don't reset if we are showing a shortMessage + if( SingleShotPool::isActive( this, SLOT(resetMainText()) ) ) + return; + */ + m_mainTextLabel->setPalette(QPalette()); + + if (allDone()) { + m_mainTextLabel->setText(mainText_); + } + + else { + //m_mainTextLabel->setPaletteBackgroundColor( m_mainTextLabel->paletteBackgroundColor().dark( 110 ) ); + m_mainTextLabel->setPalette(QToolTip::palette()); + + ProgressBar *bar = 0; + uint count = 0; + + for (ProgressMap::ConstIterator it = progressMap_.begin(); + it != progressMap_.end(); ++it ) { + if (!(*it)->isFinished_) { + bar = *it; + count++; + } + } + + if (count == 1) { + m_mainTextLabel->setText(bar->description() + "..."); + } else { + m_mainTextLabel->setText(tr("Multiple background-tasks running")); + } + } +} +/* + void + StatusBar::shortLongMessage( const QString &_short, const QString &_long ) + { + shortMessage( _short ); + + if ( !_long.isEmpty() ) { + AMAROK_NOTIMPLEMENTED + } + } +*/ +//void +//StatusBar::longMessage( const QString &text, int /*type*/ ) +/*{ + PopupMessage * message; + message = new PopupMessage( this, m_mainTextLabel ); + message->setText( text ); + + if ( !m_messageQueue.isEmpty() ) + message->stackUnder( m_messageQueue.last() ); + + message->reposition(); + message->display(); + + raise(); + + m_messageQueue += message; + } +*/ + +//void +//StatusBar::longMessageThreadSafe( const QString &text, int /*type*/ ) +/*{ + QCustomEvent * e = new QCustomEvent( 1000 ); + e->setData( new QString( text ) ); + QApplication::postEvent( this, e ); + } +*/ +// void +// StatusBar::customEvent( QCustomEvent *e ) +// { +// QString *s = static_cast( e->data() ); +// shortMessage( *s ); +// delete s; +//} + + +/// application wide progress monitor + +inline bool StatusBar::allDone() { + for (ProgressMap::Iterator it = progressMap_.begin(), end = + progressMap_.end(); it != end; ++it) + if ((*it)->isFinished_ == false) { + return false; + } + + return true; +} + +ProgressBar &StatusBar::newProgressOperation(QObject *owner) { + if (progressMap_.contains(owner)) { + return *progressMap_[owner]; + } + + if (allDone()) { + // if we're allDone then we need to remove the old progressBars before + // we start anything new or the total progress will not be accurate + pruneProgressBars(); + } else { + (progressBox()->findChild < QWidget * > ("showAllProgressDetails"))->show(); + } + + QWidget *hbox = new QWidget(popupProgressMessage_); + QHBoxLayout *hlayout = new QHBoxLayout(hbox); + QLabel *label = new QLabel(hbox); + hlayout->addWidget(label); + ProgressBar *pBar = new ProgressBar(hbox, label); + hlayout->addWidget(pBar); + hbox->show(); + popupProgressMessage_->addWidget(hbox); + progressMap_.insert(owner, pBar); + + + FQ_VERIFY(connect(owner, SIGNAL(destroyed(QObject*)), SLOT(endProgressOperation(QObject*)))); + + // so we can show the correct progress information + // after the ProgressBar is setup + //SingleShotPool::startTimer( 0, this, SLOT(updateProgressAppearance()) ); + updateProgressAppearance(); + + progressBox()->show(); + cancelButton()->setEnabled(true); + + return *progressMap_[owner]; +} +/* + ProgressBar& + StatusBar::newProgressOperation( KIO::Job *job ) + { + ProgressBar & bar = newProgressOperation( (QObject*)job ); + bar.setTotalSteps( 100 ); + + if(!allDone()) + static_cast(progressBox()->child("showAllProgressDetails"))->show(); + QVERIFY(connect( job, SIGNAL(result( KIO::Job* )), SLOT(endProgressOperation()))); + //TODO QVERIFY(connect( job, SIGNAL(infoMessage( KIO::Job *job, const QString& )), SLOT() )); + QVERIFY(connect( job, SIGNAL(percent( KIO::Job*, unsigned long )), SLOT(setProgress( KIO::Job*, unsigned long )))); + + return bar; + } +*/ +/* + void + StatusBar::endProgressOperation() + { + QObject *owner = (QObject*)sender(); //HACK deconsting it + KIO::Job *job = dynamic_cast( owner ); + + //FIXME doesn't seem to work for KIO::DeleteJob, it has it's own error handler and returns no error too + // if you try to delete http urls for instance <- KDE SUCKS! + + if( job && job->error() ) + longMessage( job->errorString(), Error ); + + endProgressOperation( owner ); + } +*/ +void StatusBar::endProgressOperation(QObject *owner) { + //the owner of this progress operation has been deleted + //we need to stop listening for progress from it + //NOTE we don't delete it yet, as this upsets some + //things, we just call setDone(). + + if (!progressMap_.contains(owner)) { + return ; + } + + progressMap_[owner]->setDone(); + + if (allDone() && popupProgressMessage_->isHidden()) { + cancelButton()->setEnabled(false); + //SingleShotPool::startTimer( 2000, this, SLOT(hideMainProgressBar()) ); + hideMainProgressBar(); + } + + updateTotalProgress(); +} + +void StatusBar::abortAllProgressOperations() { //slot + for (ProgressMap::Iterator it = progressMap_.begin(), end = + progressMap_.end(); it != end; ++it) { + (*it)->abortButton_->animateClick(); + } + + m_mainTextLabel->setText(tr("Aborting all jobs...")); + + cancelButton()->setEnabled(false); +} + +void StatusBar::toggleProgressWindow(bool show) { //slot + popupProgressMessage_->adjustSize(); + //FIXME shouldn't be needed, adding bars doesn't seem to do this + popupProgressMessage_->setShown(show); + + if (!show) { + hideMainProgressBar(); + } + //SingleShotPool::startTimer( 2000, this, SLOT(hideMainProgressBar()) ); +} + +void StatusBar::showMainProgressBar() { + if (!allDone()) { + progressBox()->show(); + } +} + +void StatusBar::hideMainProgressBar() { + if (allDone() && popupProgressMessage_->isHidden()) { + pruneProgressBars(); + + resetMainText(); + + mainProgressBar_->setValue(0); + progressBox()->close(); + } +} + +void StatusBar::setProgress(int steps) { + setProgress(sender(), steps); +} +/* + void + StatusBar::setProgress( KIO::Job *job, unsigned long percent ) + { + setProgress( ( QObject* ) job, percent ); + } +*/ +void StatusBar::setProgress(const QObject *owner, int steps) { + if (!progressMap_.contains(owner)) { + return ; + } + + progressMap_[owner]->setValue(steps); + + updateTotalProgress(); +} + +void StatusBar::setProgressStatus(const QObject *owner, const QString &text) { + if (!progressMap_.contains(owner)) { + return ; + } + + progressMap_[owner]->setStatus(text); +} + +void StatusBar::incrementProgress() { + incrementProgress(sender()); +} + +void StatusBar::incrementProgress(const QObject *owner) { + if (!progressMap_.contains(owner)) { + return ; + } + + progressMap_[owner]->setValue(progressMap_[owner]->value() + 1); + + updateTotalProgress(); +} + +void StatusBar::updateTotalProgress() { + uint totalSteps = 0; + uint progress = 0; + + for (ProgressMap::ConstIterator it = progressMap_.begin(); + it != progressMap_.end(); ++it ) { + totalSteps += (*it)->maximum(); + progress += (*it)->value(); + } + + if (totalSteps == 0 && progress == 0) { + return ; + } + + mainProgressBar_->setMaximum(totalSteps); + mainProgressBar_->setValue(progress); + + pruneProgressBars(); +} + +void StatusBar::updateProgressAppearance() { + toggleProgressWindowButton()->setShown(progressMap_.count() > 1); + + resetMainText(); + + updateTotalProgress(); +} + +void StatusBar::pruneProgressBars() { + ProgressMap::Iterator it = progressMap_.begin(); + const ProgressMap::Iterator end = progressMap_.end(); + int count = 0; + bool removedBar = false; + while (it != end) + if ((*it)->isFinished_ == true) { + delete (*it)->label_; + delete (*it)->abortButton_; + delete (*it); + + ProgressMap::Iterator jt = it; + ++it; + progressMap_.erase(jt); + removedBar = true; + } else { + ++it; + ++count; + } + if (count == 1 && removedBar) { //if its gone from 2 or more bars to one bar... + resetMainText(); + (progressBox()->findChild < QWidget * > ("showAllProgressDetails"))->hide(); + popupProgressMessage_->setShown(false); + } +} + +} //namespace FQTerm + +#include "statusBar.moc" diff --git a/src/ui/statusBar.h b/src/ui/statusBar.h new file mode 100644 index 0000000..9737f90 --- /dev/null +++ b/src/ui/statusBar.h @@ -0,0 +1,148 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_STATUSBAR_H +#define FQTERM_STATUSBAR_H + +#include "progressBar.h" //convenience +// #include //baseclass +// #include //stack allocated +// #include //stack allocated +//Added by qt3to4: +// #include +#include +#include +#include +#include +#include +#include +#include + +class QString; +class QLayout; +class QLabel; +class QString; + +namespace FQTerm { + +class PopupMessage; +typedef QMap < const QObject *, ProgressBar * > ProgressMap; + +class StatusBar: public QWidget { + Q_OBJECT; + public: + StatusBar(QWidget *parent_, const char *name = "mainStatusBar"); + static StatusBar *instance() { + return singletonStatusBar_ + ; + } + /** + * Start a progress operation, if owner is 0, the return value is + * undefined - the application will probably crash. + * @param owner controls progress for this operation + * @return the progressBar so you can configure its parameters + * @see setProgress( QObject*, int ) + * @see incrementProgress( QObject* ) + * @see setProgressStatus( const QObject*, const QString& ) + */ + ProgressBar &newProgressOperation(QObject *owner); + + void setProgress(const QObject *owner, int steps); + void incrementProgress(const QObject *owner); + void setProgressStatus(const QObject *owner, const QString &text); + public slots: + void setMainText(const QString &text); + void resetMainText(); + void shortMessage(const QString &text); + /** Stop anticipating progress from sender() */ + //void endProgressOperation(); + + /** Stop anticipating progress from @param owner */ + void endProgressOperation(QObject *owner); + + /** + * Convenience function works like setProgress( QObject*, int ) + * Uses the return value from sender() to determine the owner of + * the progress bar in question + */ + void setProgress(int steps); + + /** + * Convenience function works like incrementProgress( QObject* ) + * Uses the return value from sender() to determine the owner of + * the progress bar in question + */ + void incrementProgress(); + + public slots: + void toggleProgressWindow(bool show); + void abortAllProgressOperations(); + + private slots: + /** For internal use against KIO::Jobs */ + //void setProgress( KIO::Job*, unsigned long percent ); + void showMainProgressBar(); + void hideMainProgressBar(); + void updateProgressAppearance(); + + protected: + virtual void ensurePolished(); + // virtual void customEvent( QCustomEvent* ); + virtual void paintEvent(QPaintEvent*); + virtual bool event(QEvent*); + + /** + * You must parent the widget to the statusbar, we won't do that + * for you! The widget will be added to the right of the layout. + * Currently you must add widgets before the statusbar gets shown + * for the first time, because we are not currently very flexible. + */ + void addWidget(QWidget *widget); + + QLabel *m_mainTextLabel; + private: + void updateTotalProgress(); + bool allDone(); ///@return true if all progress operations are complete + void pruneProgressBars(); /// deletes old progress bars + + QWidget *cancelButton() { + return findChild("cancelButton"); + } + QWidget *toggleProgressWindowButton() { + return findChild("showAllProgressDetails"); + } + QWidget *progressBox() { + return findChild ("progressBox"); + } + + PopupMessage *popupProgressMessage_; + QProgressBar *mainProgressBar_; + + ProgressMap progressMap_; + // QList m_messageQueue; + QString mainText_; + + QLayout *otherWidgetLayout_; + static StatusBar *singletonStatusBar_; +}; + +} // namespace FQTerm + +#endif // FQTERM_STATUSBAR_H diff --git a/src/ui/zmodemdialog.cpp b/src/ui/zmodemdialog.cpp new file mode 100644 index 0000000..629a40a --- /dev/null +++ b/src/ui/zmodemdialog.cpp @@ -0,0 +1,73 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +#include "fqterm_trace.h" +#include "zmodemdialog.h" + +namespace FQTerm { + +zmodemDialog::zmodemDialog(QWidget *parent_, Qt::WFlags fl) + : QDialog(parent_, fl) { + ui_.setupUi(this); + FQ_VERIFY(connect(ui_.buttonCancel, SIGNAL(clicked()), this, SLOT(slotCancel()))); +} + +zmodemDialog::~zmodemDialog(){} + +void zmodemDialog::setProgress(int offset) { + ui_.pbProgress->setValue(offset); + QString strTmp; + strTmp = QString("%1 out of %2 bytes").arg(offset).arg(ui_.pbProgress->maximum() + ); + ui_.labelStatus->setText(strTmp); +} + +void zmodemDialog::setFileInfo(const QString &name, int size) { + ui_.labelFileName->setText(name); + ui_.pbProgress->setMaximum(size); +} + +void zmodemDialog::addErrorLog(const QString &err) { + // FIXME:display error message; + //browserError->append(err); +} + +void zmodemDialog::clearErrorLog() { + //browserError->clear(); +} + +void zmodemDialog::slotCancel() { + QMessageBox mb("FQTerm", "We dont support cancel operation yet. " + "But you can try, it will crash when downloading.\n" + "Do you want to continue?", + QMessageBox::Warning, QMessageBox::Yes, + QMessageBox::No | QMessageBox::Escape | QMessageBox::Default, + 0, this); + if (mb.exec() == QMessageBox::Yes) { + emit canceled(); + hide(); + } +} + +} // namespace FQTerm + +#include "zmodemdialog.moc" diff --git a/src/ui/zmodemdialog.h b/src/ui/zmodemdialog.h new file mode 100644 index 0000000..f310b64 --- /dev/null +++ b/src/ui/zmodemdialog.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_ZMODEM_DIALOG_H +#define FQTERM_ZMODEM_DIALOG_H + +#include "ui_zmodemdialog.h" + +namespace FQTerm { + +class zmodemDialog: public QDialog { + Q_OBJECT; + public: + zmodemDialog(QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~zmodemDialog(); + + void setFileInfo(const QString &, int); + void addErrorLog(const QString &); + void clearErrorLog(); + void setProgress(int); + + public slots: + void slotCancel(); + + signals: + void canceled(); + + private: + Ui::zmodemDialog ui_; +}; + +} // namespace FQTerm + +#endif // FQTERM_ZMODEM_DIALOG_H diff --git a/src/ui/zmodemdialog.ui b/src/ui/zmodemdialog.ui new file mode 100644 index 0000000..9f2bb2b --- /dev/null +++ b/src/ui/zmodemdialog.ui @@ -0,0 +1,105 @@ + + zmodemDialog + + + + 0 + 0 + 333 + 259 + + + + Zmodem Status + + + + 9 + + + 6 + + + + + + 0 + 0 + + + + textLabel1 + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 121 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 111 + 20 + + + + + + + + Cancel + + + + + + + + + + + 0 + 0 + + + + textLabel2 + + + + + + + 24 + + + Qt::Horizontal + + + + + + + + + diff --git a/src/unite/CMakeLists.txt b/src/unite/CMakeLists.txt new file mode 100644 index 0000000..b093576 --- /dev/null +++ b/src/unite/CMakeLists.txt @@ -0,0 +1,46 @@ +set(fqunite_SRCS + fqterm_mini_server.h + fqterm_mini_server.cpp +) + +set(fqunite_internal_SRCS + internal/unite.h + internal/user.h + internal/user.cpp + internal/board.h + internal/board.cpp + internal/article.h + internal/article.cpp + internal/session.h + internal/session.cpp + internal/state.h + internal/state.cpp + internal/statebuilder.h + internal/statebuilder.cpp +) + +qt4_automoc( + ${fqunite_SRCS} + ${fqunite_internal_SRCS} +) + +include_directories( + ${QT_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} + ${QT_QTNETWORK_INCLUDE_DIR} + ${QT_QTXML_INCLUDE_DIR} + ${QT_QTGUI_INCLUDE_DIR} + ${OPENSSL_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/internal + ${CMAKE_CURRENT_SOURCE_DIR}/../common + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_library(fqterm_unite + ${fqunite_SRCS} + ${fqunite_internal_SRCS} +) + +add_dependencies(fqterm_unite + fqterm_common +) diff --git a/src/unite/fqterm_mini_server.cpp b/src/unite/fqterm_mini_server.cpp new file mode 100644 index 0000000..2b18faf --- /dev/null +++ b/src/unite/fqterm_mini_server.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#include "fqterm_mini_server.h" +#include "fqterm_trace.h" +#include "fqterm_path.h" +#include "fqterm.h" +#include +#include +#include +#include +#include +namespace FQTerm { + + +void FQTermMiniServerThread::run() +{ + setTerminationEnabled(); + FQTermMiniServer miniServer; + //miniServer.setMaxPendingConnections(1); + miniServer.listen(QHostAddress::LocalHost, 35172); + exec(); + miniServer.close(); + miniServer.finalizeMiniServer(); +} + +FQTermMiniServer::FQTermMiniServer(QObject * parent) + : QTcpServer(parent) { +} + + +FQTermMiniServer::~FQTermMiniServer() { +} + +void FQTermMiniServer::incomingConnection( int socketDescriptor ) { + FQTermUniteSession* session = new FQTermUniteSession(socketDescriptor); + FQ_VERIFY(connect(this, SIGNAL(quit()), session, SLOT(quit()), Qt::QueuedConnection)); + session->start(); +} + +void FQTermMiniServer::finalizeMiniServer() { + emit quit(); +} + + + + + + + + +} //namespace FQTerm + +#include "fqterm_mini_server.moc" diff --git a/src/unite/fqterm_mini_server.h b/src/unite/fqterm_mini_server.h new file mode 100644 index 0000000..3295137 --- /dev/null +++ b/src/unite/fqterm_mini_server.h @@ -0,0 +1,69 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#ifndef FQTERM_MINI_SERVER_H +#define FQTERM_MINI_SERVER_H + +#include +#include +#include +#include +#include +#include +#include "internal/session.h" + +namespace FQTerm { + + +class FQTermMiniServer : public QTcpServer { + Q_OBJECT; +public: + FQTermMiniServer( QObject * parent = 0 ); + ~FQTermMiniServer(); + void finalizeMiniServer(); +protected: + void incomingConnection(int socketDescriptor); +signals: + void quit(); +}; + + +class FQTermMiniServerThread : public QThread{ +protected: + virtual void run(); + +}; +//---------------------------------------------------------------------------------- +// this for FSM +class FQTermUniteDecode; + +//---------------------------------------------------------------------------------- + + +class FQTermUniteSession; +class FQTermUniteState; + + + +//use XML to describe the site. +//each session contains user info, not in the reverse way. +//each session has 1. state (edit, read, menu), 2. strategy (decided by state) 3. context (with which strategy could decide next step. i.e. inner state) +} //namespace FQTerm +#endif diff --git a/src/unite/internal/article.cpp b/src/unite/internal/article.cpp new file mode 100644 index 0000000..c5905f8 --- /dev/null +++ b/src/unite/internal/article.cpp @@ -0,0 +1,19 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ diff --git a/src/unite/internal/article.h b/src/unite/internal/article.h new file mode 100644 index 0000000..43ca0cb --- /dev/null +++ b/src/unite/internal/article.h @@ -0,0 +1,28 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#ifndef FQTERM_UNITE_ARTICLE +#define FQTERM_UNITE_ARTICLE + +namespace FQTerm { + +} //namespace FQTerm + +#endif //FQTERM_UNITE_USER \ No newline at end of file diff --git a/src/unite/internal/board.cpp b/src/unite/internal/board.cpp new file mode 100644 index 0000000..c5905f8 --- /dev/null +++ b/src/unite/internal/board.cpp @@ -0,0 +1,19 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ diff --git a/src/unite/internal/board.h b/src/unite/internal/board.h new file mode 100644 index 0000000..a23db18 --- /dev/null +++ b/src/unite/internal/board.h @@ -0,0 +1,28 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#ifndef FQTERM_UNITE_BOARD +#define FQTERM_UNITE_BOARD + +namespace FQTerm { + +} //namespace FQTerm + +#endif //FQTERM_UNITE_USER \ No newline at end of file diff --git a/src/unite/internal/session.cpp b/src/unite/internal/session.cpp new file mode 100644 index 0000000..6964287 --- /dev/null +++ b/src/unite/internal/session.cpp @@ -0,0 +1,138 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#include "state.h" +#include "fqterm.h" +#include +#include +#include "statebuilder.h" +namespace FQTerm{ + +void FQTermUniteSessionContext::write(const QByteArray& str) { + session_->write(str); +} + +FQTermUniteSessionContext::FQTermUniteSessionContext(FQTermUniteSession* session) : QObject(session), session_(session) { + stateTable_[WELCOME] = new FQTermWelcomeState(this); + stateTable_[EXITING] = new FQTermExitState(this); + stateTable_[READING] = new FQTermReadingState(this); + stateTable_[HELP] = new FQTermHelpState(this); + setCurrentState(WELCOME); +} + +void FQTermUniteSessionContext::processInput(const QByteArray& input) { + inputBuffer_ += input; + while(true) { + int consumed = currentState_->processInput(inputBuffer_); + inputBuffer_ = inputBuffer_.mid(consumed); + if (!consumed || inputBuffer_.size() == 0) { + break; + } + } +} + +void FQTermUniteSessionContext::quit() { + session_->quit(); +} + + + +FQTermUniteState* FQTermUniteSessionContext::setCurrentState(int state, bool init /*= true*/) { + StateTableIterator it = stateTable_.find(state); + if (it != stateTable_.end()) { + currentState_ = it->second; + if (init) + currentState_->initialize(); + } + return currentState_; +} + + + +FQTermUniteSession::FQTermUniteSession(int socketDescriptor ) : context_(NULL) { + moveToThread(this); + socket_ = new QTcpSocket; + FQ_VERIFY(connect(socket_, SIGNAL(readyRead()), + this, SLOT(readyRead()),Qt::DirectConnection)); + FQ_VERIFY(connect(socket_, SIGNAL(disconnected()), + this, SLOT(disconnected()),Qt::DirectConnection)); + FQ_VERIFY(connect(socket_, SIGNAL(stateChanged(QAbstractSocket::SocketState)), + this, SLOT(stateChanged(QAbstractSocket::SocketState)),Qt::DirectConnection)); + FQ_VERIFY(connect(socket_, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(error(QAbstractSocket::SocketError)),Qt::DirectConnection)); + + // FQ_VERIFY(connect(socket_, SIGNAL(connected()), + // this, SLOT(welcome()),Qt::DirectConnection)); + + socket_->setSocketDescriptor(socketDescriptor); + socket_->moveToThread(this); + setTerminationEnabled(); + + StateBuilder sb; + sb.BuildState(); +} + + +FQTermUniteSession::~FQTermUniteSession() { + socket_->close(); + delete socket_; + socket_ = NULL; +} + +void FQTermUniteSession::welcome() +{ + context_ = new FQTermUniteSessionContext(this); +} + +void FQTermUniteSession::readyRead() { + if (context_) { + context_->processInput(socket_->readAll()); + } +} + +void FQTermUniteSession::write( const QByteArray& output ) { + socket_->write(output); +} + +void FQTermUniteSession::run() { + welcome(); + exec(); + disconnected(); +} + + +void FQTermUniteSession::disconnected() { + if (!isRunning()) + return; + quit(); + moveToThread(QApplication::instance()->thread()); + deleteLater(); +} + +void FQTermUniteSession::stateChanged( QAbstractSocket::SocketState socketState ) { +} + +void FQTermUniteSession::error(QAbstractSocket::SocketError socketError) { +} + + +} + +#include "session.moc" \ No newline at end of file diff --git a/src/unite/internal/session.h b/src/unite/internal/session.h new file mode 100644 index 0000000..a5959a1 --- /dev/null +++ b/src/unite/internal/session.h @@ -0,0 +1,77 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ +#ifndef FQTERM_UNITE_SESSION +#define FQTERM_UNITE_SESSION + +#include +#include +#include +#include +#include +namespace FQTerm { + +class FQTermUniteState; +class FQTermUniteSession; +class FQTermUniteSessionContext : public QObject { + Q_OBJECT; +public: + FQTermUniteSessionContext(FQTermUniteSession* session); + void write(const QByteArray& str); + void processInput(const QByteArray& input); + void quit(); + enum STATE{WELCOME = 0, EXITING = 1, READING = 2, HELP = 3}; + FQTermUniteState* setCurrentState(int state, bool init = true); + + int row() {return 24;} + int column() {return 80;} +private: + FQTermUniteSession* session_; + FQTermUniteState* currentState_; + QByteArray inputBuffer_; + typedef std::map StateTable; + typedef std::map::iterator StateTableIterator; + StateTable stateTable_; +}; + + +class FQTermUniteSession : public QThread { + Q_OBJECT; +public: + FQTermUniteSession(int socketDescriptor); + ~FQTermUniteSession(); + void write(const QByteArray& output); + +protected: + virtual void run(); + protected slots: + void readyRead(); + void disconnected(); + void stateChanged(QAbstractSocket::SocketState socketState); + void error(QAbstractSocket::SocketError socketError); + void welcome(); +private: + QTcpSocket* socket_; + FQTermUniteSessionContext* context_; + +}; + +} //namespace FQTerm + +#endif //FQTERM_UNITE_USER \ No newline at end of file diff --git a/src/unite/internal/state.cpp b/src/unite/internal/state.cpp new file mode 100644 index 0000000..39241b0 --- /dev/null +++ b/src/unite/internal/state.cpp @@ -0,0 +1,676 @@ +#include "fqterm.h" +#include "fqterm_path.h" +#include +#include "state.h" +#include + +namespace FQTerm{ + +int FQTermUniteMenu::addEntry( char key ) +{ + entries_.push_back(tolower(key)); + return entries_.size() - 1; +} + +int FQTermUniteMenu::findEntry( char key ) +{ + std::vector::iterator it = std::find(entries_.begin(), entries_.end(), tolower(key)); + if (it == entries_.end()) {return -1;} + return std::distance(entries_.begin(), it); +} + +void FQTermUniteMenu::clearEntry() +{ + entries_.clear(); + clearPointer(current_); + current_ = 0; +} + +int FQTermUniteMenu::currentEntry() +{ + return current_; +} + +int FQTermUniteMenu::setCurrentEntry( char key ) +{ + int next = findEntry(key); + if (next == -1) + return currentEntry(); + clearPointer(current_); + current_ = next; + drawPointer(current_); + return current_; +} + +int FQTermUniteMenu::setCurrentIndex( int index ) +{ + clearPointer(current_); + current_ = index; + drawPointer(current_); + return current_; +} + +int FQTermUniteMenu::nextEntry() +{ + if (!entries_.size()) + return current_; + clearPointer(current_); + current_++; + current_ %= entries_.size(); + drawPointer(current_); + return current_; +} + +int FQTermUniteMenu::prevEntry() +{ + if (!entries_.size()) + return current_; + clearPointer(current_); + current_--; + current_ += entries_.size(); + current_ %= entries_.size(); + drawPointer(current_); + return current_; +} + + +StateOption FQTermUniteDecode::EscStateMachine::normal_state_[] = { + { + CHAR_ESC, 0, esc_state_ + }, { + CHAR_NORMAL, &FQTermUniteDecode::normalInput, normal_state_ + } +}; + +// state after a ESC_CHAR +StateOption FQTermUniteDecode::EscStateMachine::esc_state_[] = { + { + '[', &FQTermUniteDecode::clearParam, bracket_state_ + }, { + CHAR_ESC, &FQTermUniteDecode::doubleEsc, normal_state_ + },{ + CHAR_NORMAL, 0, normal_state_ + } +}; + +// state after ESC [ +StateOption FQTermUniteDecode::EscStateMachine::bracket_state_[] = { + { + '0', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + '1', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + '2', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + '3', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + '4', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + '5', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + '6', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + '7', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + '8', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + '9', &FQTermUniteDecode::paramDigit, bracket_state_ + }, { + 'A', &FQTermUniteDecode::cursorUp, normal_state_ + }, { + 'B', &FQTermUniteDecode::cursorDown, normal_state_ + }, { + 'C', &FQTermUniteDecode::cursorRight, normal_state_ + }, { + 'D', &FQTermUniteDecode::cursorLeft, normal_state_ + }, { + '~', &FQTermUniteDecode::functionKey, normal_state_ + }, { + CHAR_NORMAL, 0, normal_state_ + } +}; + +int FQTermUniteDecode::processInput(const QByteArray& input) { + data_ = input.data(); + currentByte_ = 0; + inputLength_ = input.size(); + /* + for (int i = 0; i < input.size(); ++i) { + bool res = keyReceived(input[i]); + if (!res) { + return i + 1; + } + } + */ + + int i; + StateOption *lastState; + + while (currentByte_ < inputLength_) { + // current state always be initialized to point to the beginning of three structures + // ( normalState, escState, bracketState ) + i = 0; + while (current_state_[i].byte != CHAR_NORMAL && current_state_[i].byte != + data_[currentByte_]) { + i++; + } + + lastState = current_state_ + i; + + bool stopDecode; + if (lastState->action != 0) { + stopDecode = (this->*(lastState->action))(); + } + + // reinit current state + current_state_ = lastState->nextState; + + currentByte_++; + if (stopDecode) + break; + + } + + return currentByte_; +} + +FQTermUniteDecode::FQTermUniteDecode() { + current_state_ = EscStateMachine::normal_state_; + data_ = NULL; + inputLength_ = 0; + currentByte_ = 0; +} + +bool FQTermUniteDecode::clearParam() { + param_ = -1; + return true; +} + +bool FQTermUniteDecode::cursorLeft() { + return keyReceived(LEFT); +} + +bool FQTermUniteDecode::cursorDown() { + return keyReceived(DOWN); +} + +bool FQTermUniteDecode::cursorRight() { + return keyReceived(RIGHT); +} + +bool FQTermUniteDecode::cursorUp() { + return keyReceived(UP); +} + +bool FQTermUniteDecode::normalInput() { + return keyReceived(data_[currentByte_]); +} + +bool FQTermUniteDecode::doubleEsc() { + return keyReceived(DOUBLEESC); +} + +bool FQTermUniteDecode::paramDigit() { + if (param_ < 0) { + param_ = 0; + } + param_ = param_ * 10 + (data_[currentByte_] - '0'); + return true; +} + +bool FQTermUniteDecode::functionKey() { + int key; + switch (param_) { + case 1: key = HOME; break; + case 3: key = DELETE; break; + case 4: key = END; break; + case 5: key = PGUP; break; + case 6: key = PGDOWN; break; + case 11: key = F1; break; + case 12: key = F2; break; + case 13: key = F3; break; + case 14: key = F4; break; + case 15: key = F5; break; + case 17: key = F6; break; + case 18: key = F7; break; + case 19: key = F8; break; + case 20: key = F9; break; + case 21: key = F10; break; + case 23: key = F11; break; + case 24: key = F12; break; + default: + break; + } + return keyReceived(key); +} + +FQTermUniteState::FQTermUniteState(FQTermUniteSessionContext* context) : context_(context) { + +} + +void FQTermUniteState::write( const QByteArray& output ) { + context_->write(output); +} + +QByteArray FQTermUniteState::escape() { + return "\x1b"; +} + +void FQTermUniteState::moveCursorRelative(int dx, int dy) { + //Esc[ValueA Move cursor up n lines CUU + //Esc[ValueB Move cursor down n lines CUD + //Esc[ValueC Move cursor right n lines CUF + //Esc[ValueD Move cursor left n lines CUB + if (dy > 0) { + write(escape() + QString("[%1").arg(dy).toLocal8Bit() + "B"); + } + if (dy < 0) { + write(escape() + QString("[%1").arg(-dy).toLocal8Bit() + "A"); + } + if (dx > 0) { + write(escape() + QString("[%1").arg(dx).toLocal8Bit() + "C"); + } + if (dx < 0) { + write(escape() + QString("[%1").arg(-dx).toLocal8Bit() + "D"); + } + +} + + +void FQTermUniteState::moveCursorAbsolute(int x, int y) { + //Esc[Line;ColumnH Move cursor to screen location v,h CUP + write(escape() + QString("[%1;%2H").arg(y).arg(x).toLocal8Bit()); +} + +void FQTermUniteState::moveCursorHome() { + write(escape() + "[H"); +} + +void FQTermUniteState::scrollWindow(int dy) { + //EscD Move/scroll window up one line IND + //EscM Move/scroll window down one line RI + + if (dy > 0) { + for (int i = 0; i < dy; ++i) + write(escape() + "D"); + } + if (dy < 0) { + dy = -dy; + for (int i = 0; i < dy; ++i) + write(escape() + "M"); + } +} + +void FQTermUniteState::moveCursorNextLine() { + //EscE Move to next line NEL + write(escape() + "E"); + +} + +void FQTermUniteState::saveCursor() { + //Esc7 Save cursor position and attributes DECSC + write(escape() + "7"); +} + +void FQTermUniteState::restoreCursor() { + //Esc8 Restore cursor position and attributes DECSC + write(escape() + "8"); +} + +void FQTermUniteState::setAttr(int attr) { + if (attr == -1) { + write(escape() + "[m"); + } else { + write(escape() + QString("[%1m").arg(attr).toLocal8Bit()); + } +} + +void FQTermUniteState::setForegroundColor(int color, bool highlight /*= true*/) { + int hl = highlight?1:0; + write(escape() + QString("[%1;3%2m").arg(hl).arg(color).toLocal8Bit()); +} + +void FQTermUniteState::setBackgroundColor(int color) { + write(escape() + QString("[4%1m").arg(color).toLocal8Bit()); +} + +void FQTermUniteState::clearLine(int part) { + write(escape() + QString("[%1K").arg(part).toLocal8Bit()); +} + +void FQTermUniteState::clearScreen(int part) { + write(escape() + QString("[%1J").arg(part).toLocal8Bit()); +} + +void FQTermUniteState::setWindowRange(int startLine, int endLine) { + write(escape() + QString("[%1;%2r").arg(startLine).arg(endLine).toLocal8Bit()); +} + + +QByteArray FQTermUniteState::cursorStr() { + QChar c(0x25c6); + QString str(c); + return str.toUtf8(); +} +FQTermWelcomeState::FQTermWelcomeState( FQTermUniteSessionContext* context ) : FQTermUniteState(context) { + addEntry('h'); + addEntry('x'); +} + +void FQTermWelcomeState::initialize() { + moveCursorHome(); + clearScreen(WHOLESCREEN); + + + + QFile welcomeFile(getPath(RESOURCE) + "unite/welcome"); + welcomeFile.open(QIODevice::ReadOnly); + QByteArray str = welcomeFile.readAll(); + write(str); + setCurrentIndex(currentEntry()); + return; +} + +bool FQTermWelcomeState::keyReceived(int key) { + if (tolower(key) == 'j' || key == UP) { + prevEntry(); + } else if (tolower(key) == 'k' || key == DOWN) { + nextEntry(); + } else if (key == '\r' || key == RIGHT) { + enterEntry(); + return false; + } else if (tolower(key) <= 'z' && tolower(key) >= 'a') { + setCurrentEntry(key); + } + return true; +} + +void FQTermWelcomeState::enterEntry() { + if (currentEntry() == 1) { + setNextState(FQTermUniteSessionContext::EXITING); + } else if (currentEntry() == 0) { + setNextState(FQTermUniteSessionContext::HELP); + } +} + +void FQTermWelcomeState::clearPointer(int index) { + moveCursorAbsolute(7, 11 + index); + write(" "); + moveCursorHome(); +} + +void FQTermWelcomeState::drawPointer(int index) { + moveCursorAbsolute(7, 11 + index); + write(cursorStr()); + moveCursorHome(); +} + + + +void FQTermExitState::initialize() { + clearScreen(WHOLESCREEN); + QFile welcomeFile(getPath(RESOURCE) + "unite/exit"); + welcomeFile.open(QIODevice::ReadOnly); + QByteArray str = welcomeFile.readAll(); + write(str); + setCurrentIndex(0); +} + +void FQTermExitState::clearPointer(int index) { + moveCursorAbsolute(28, 10 + index); + setBackgroundColor(BLUE); + write(" "); + //moveCursorHome(); +} + +void FQTermExitState::drawPointer( int index ) { + moveCursorAbsolute(28, 10 + index); + setBackgroundColor(BLUE); + write(cursorStr()); + //moveCursorHome(); +} + +void FQTermExitState::enterEntry() { + if (currentEntry() == 1) { + quit(); + } else { + setNextState(FQTermUniteSessionContext::WELCOME); + } +} + +bool FQTermExitState::keyReceived( int key ) +{ + if (tolower(key) == 'j' || key == UP) { + prevEntry(); + } else if (tolower(key) == 'k' || key == DOWN) { + nextEntry(); + } else if (key == '\r') { + enterEntry(); + return false; + } else if (key >= '0' && key <= '9') { + setCurrentEntry(key); + } else if (tolower(key) == 'c') { + setCurrentIndex(0); + enterEntry(); + return false; + } + //moveCursorHome(); + return true; +} + +FQTermExitState::FQTermExitState( FQTermUniteSessionContext* context ) : FQTermUniteState(context) { + addEntry('1'); + addEntry('2'); +} + +SplittedArticleBuffer::SplittedArticleBuffer(const QByteArray& utf8Content, int column, int row) { + std::vector strList; + QString content = QString::fromUtf8(utf8Content); + lines_.reserve(row); + int start = 0; + for(;;) { + int newStart = findNextLine(content, start, column); + if (newStart == -1) { + lines_.push_back(content.mid(start).toUtf8()); + break; + } else { + lines_.push_back(content.mid(start, newStart - start).toUtf8()); + start = newStart; + } + } +} + +int SplittedArticleBuffer::findNextLine(const QString& str, int start, int column) { + int count = 0; + for (int i = start; i < str.length(); ++i) { + if (str[i] == '\t') { + count += 2; + } else { + count += str[i] <= 0x7F ? 1 : 2; + } + if (count > column) { + return i; + } + if (str[i] == '\n') { + if (i + 1 < str.length()) + return i + 1; + } + } + return -1; +} + +void FQTermReadingState::initialize() { + clearScreen(WHOLESCREEN); + moveCursorHome(); + drawLines(row() - 1, 1); + drawFooter(); + moveCursorAbsolute(column(), row()); +} + + +void FQTermReadingState::setFile(const QString& filename) { + currentStartLine_ = 0; + QFile file(filename); + file.open(QIODevice::ReadOnly); + content_ = file.readAll(); + delete saBuffer_; + saBuffer_ = new SplittedArticleBuffer(content_, column(), row()); +} + +FQTermReadingState::FQTermReadingState( FQTermUniteSessionContext* context ) : FQTermUniteState(context) { + returnState_ = FQTermUniteSessionContext::WELCOME; + currentStartLine_ = 0; + saBuffer_ = 0; +} + +bool FQTermReadingState::keyReceived( int key ) { + if (tolower(key) == 'q' || key == LEFT || !saBuffer_) { + setNextState(returnState_); + return false; + } else if (tolower(key) == 'k' || key == DOWN) { + adjustLineByDiff(1); + drawLines(row() - 1, 1); + drawFooter(); + } else if (tolower(key) == 'j' || key == UP) { + adjustLineByDiff(-1); + drawLines(row() - 1, 1); + drawFooter(); + } else if (key == PGDOWN || key == ' ' || key == RIGHT) { + adjustLineByDiff(row() - 2); + drawLines(row() - 1, 1); + drawFooter(); + } else if (key == PGUP) { + adjustLineByDiff(-row() + 2); + drawLines(row() - 1, 1); + drawFooter(); + } else if (key == HOME) { + adjustLineByDiff(-saBuffer_->count()); + drawLines(row() - 1, 1); + drawFooter(); + } else if (key == END) { + adjustLineByDiff(saBuffer_->count()); + drawLines(row() - 1, 1); + drawFooter(); + } + return true; +} + +void FQTermReadingState::drawFooter() { + if (!saBuffer_) + return; + cursorGuard(*this); + moveCursorAbsolute(1, row()); + setBackgroundColor(BLUE); + QByteArray footer = QString("Current Line: (%1-%2) Total: %3").arg(currentStartLine_ + 1).arg(qMin(saBuffer_->count(), currentStartLine_ + row() - 1)).arg(saBuffer_->count()).toLocal8Bit(); + footer += QByteArray(column() - footer.size(), ' '); + write(footer); + setAttr(CLEARATTR); +} + +void FQTermReadingState::adjustLineByDiff(int delta) { + if (!saBuffer_) + return; + currentStartLine_ += delta; + if (currentStartLine_ + row() - 1 >= saBuffer_->count()) + currentStartLine_ = saBuffer_->count() - (row() - 1); + if (currentStartLine_ < 0) + currentStartLine_ = 0; +} + + +void FQTermReadingState::drawLines(int count, int yPos) { + if (!saBuffer_) + return; + cursorGuard cg(*this); + QByteArray blankLine(column(), ' '); + for (int i = 0; i < count; ++i) { + moveCursorAbsolute(1, yPos + i); + clearLine(WHOLELINE); + if (currentStartLine_ + yPos + i - 1 >= saBuffer_->count()) { + write(blankLine); + } else { + write(saBuffer_->retriveLine(currentStartLine_ + yPos + i - 1)); + } + } +} + +FQTermReadingState::~FQTermReadingState() { + delete saBuffer_; +} + + + + + +FQTermHelpState::FQTermHelpState(FQTermUniteSessionContext* context) : FQTermUniteState(context) { + addEntry('s'); //0.entry for script + addEntry('t'); //1.entry for shortcut + addEntry('u'); //2.entry for unix host + addEntry('x'); //3.entry for quit to welcome +} + +void FQTermHelpState::initialize() { + moveCursorHome(); + clearScreen(WHOLESCREEN); + QFile welcomeFile(getPath(RESOURCE) + "unite/help"); + welcomeFile.open(QIODevice::ReadOnly); + QByteArray str = welcomeFile.readAll(); + write(str); + setCurrentIndex(currentEntry()); + return; +} + +bool FQTermHelpState::keyReceived(int key) { + if (tolower(key) == 'j' || key == UP) { + prevEntry(); + } else if (tolower(key) == 'k' || key == DOWN) { + nextEntry(); + } else if (key == '\r' || key == RIGHT) { + enterEntry(); + return false; + } else if (tolower(key) <= 'z' && tolower(key) >= 'a') { + setCurrentEntry(key); + } + return true; +} + +void FQTermHelpState::enterEntry() { + if (currentEntry() == 3) { + setNextState(FQTermUniteSessionContext::WELCOME); + return; + } + + QString doc; + switch(currentEntry()) + { + case 0: + doc = "script-doc"; + break; + case 1: + doc = "shortcut-doc"; + break; + case 2: + doc = "ssh-unix-doc"; + break; + } + FQTermUniteState* reader = setNextState(FQTermUniteSessionContext::READING, false); + ((FQTermReadingState*)reader)->setFile(getPath(RESOURCE) + "unite/" + doc); + ((FQTermReadingState*)reader)->setReturnState(FQTermUniteSessionContext::HELP); + reader->initialize(); +} + +void FQTermHelpState::clearPointer(int index) { + moveCursorAbsolute(7, 11 + index); + write(" "); + moveCursorHome(); +} + +void FQTermHelpState::drawPointer(int index) { + moveCursorAbsolute(7, 11 + index); + write(cursorStr()); + moveCursorHome(); +} + +} // namespace FQTerm + +#include "state.moc" \ No newline at end of file diff --git a/src/unite/internal/state.h b/src/unite/internal/state.h new file mode 100644 index 0000000..e294372 --- /dev/null +++ b/src/unite/internal/state.h @@ -0,0 +1,219 @@ +#ifndef FQTERM_UNITE_STATE +#define FQTERM_UNITE_STATE + +#include +#include "session.h" + +namespace FQTerm { +class FQTermUniteDecode; +typedef bool (FQTermUniteDecode:: *StateFunc)(); + +struct StateOption { + int byte; // char value to look for; -1==end/default + StateFunc action; + StateOption *nextState; +}; + + + +class FQTermUniteDecode { +public: + FQTermUniteDecode(); + virtual ~FQTermUniteDecode() {} + //should return number of chars consumed + virtual int processInput(const QByteArray& input); +protected: + virtual bool keyReceived(int key) = 0; + //tab = 7, backspace = 8, delete is *[3~, page up is 5~, page down is 6~, home is 1~, end is 4~, double esc is double esc, + //up is A, down is B, left is D, right is C. + //F1 - F12 11~ 12~ 13~ 14~ 15~ 17~ 18~ 19~ 20~ 21~ 23~ 24~ + //static char* specialKeys[]; + enum SPECIALKEY{SPECIALKEYSTART = 0x10000, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + UP, DOWN, LEFT, RIGHT, DOUBLEESC, INSERT, HOME, END, PGUP, PGDOWN, DELETE}; + + // Virtual Keys: move cursor + bool cursorLeft(); + bool cursorDown(); + bool cursorRight(); + bool cursorUp(); + + // other escape sequence actions + bool normalInput(); + + //double esc pressed + bool doubleEsc(); + + // action parameters + bool clearParam(); + bool paramDigit(); + //function key map + bool functionKey(); +private: + // ********** decoder states **************** + StateOption *current_state_; + int param_; //valid when > 0. + const char* data_; + int inputLength_; + int currentByte_; + QByteArray leftToDecode_; + struct EscStateMachine { + static StateOption normal_state_[], esc_state_[], bracket_state_[]; + }; +}; + +class FQTermUniteState : public QObject, + public FQTermUniteDecode { + Q_OBJECT; +public: + FQTermUniteState(FQTermUniteSessionContext* context); + virtual ~FQTermUniteState() {} + virtual void initialize() = 0; + + +protected: + //util functions + //cursor manipulations + void moveCursorRelative(int dx, int dy); + void moveCursorAbsolute(int x, int y); + void moveCursorHome(); + //To scroll up, dy < 0, scroll down, dy > 0. + void scrollWindow(int dy); + void moveCursorNextLine(); + void saveCursor(); + void restoreCursor(); + + //attr control + enum CHARATTR{DEFAULTATTR = -1, CLEARATTR = 0, BOLD = 1, LOWINTENSITY = 2, UNDERLINE = 4, BLINK = 5, REVERSECOLOR = 7, INVISIBLE = 8}; + void setAttr(int attr); + enum CHARCOLOR{BLACK = 0, RED = 1, GREEN = 2, YELLOW = 3, BLUE = 4, PURPLE = 5, INDIGO = 6, WHITE = 7}; + void setForegroundColor(int color, bool highlight = true); + void setBackgroundColor(int color); + + //clear lines/screen + enum CLEARLINE{CURSORRIGHT = 0, CURSORLEFT = 1, WHOLELINE = 2}; + void clearLine(int part); + enum CLEARSCREEN{CURSORDOWN = 0, CURSORUP = 1, WHOLESCREEN = 2}; + void clearScreen(int part); + + //window setting + void setWindowRange(int startLine, int endLine); + + QByteArray escape(); + QByteArray cursorStr(); + void write(const QByteArray& output); + void quit() {context_->quit();} + FQTermUniteState* setNextState(int state, bool init = true) {return context_->setCurrentState(state, init);} + int row() {return context_->row();} + int column() {return context_->column();} + + + friend struct cursorGuard; + struct cursorGuard { + cursorGuard(FQTermUniteState& state) : state_(state) {state_.saveCursor();} + ~cursorGuard() {state_.restoreCursor();} + private: + FQTermUniteState& state_; + }; +private: + FQTermUniteSessionContext* context_; + int lastState_; +}; + +class FQTermUniteMenu { +public: + FQTermUniteMenu() {current_ = 0;} + virtual ~FQTermUniteMenu() {} +protected: + int addEntry(char key); + int findEntry(char key); + void clearEntry(); + int currentEntry(); + int setCurrentEntry(char key); + int setCurrentIndex(int index); + + int nextEntry(); + int prevEntry(); + virtual void clearPointer(int index) = 0; + virtual void drawPointer(int index) = 0; + virtual void enterEntry() = 0; +private: + std::vector entries_; + int current_; +}; + + +class FQTermWelcomeState : public FQTermUniteState, public FQTermUniteMenu { + Q_OBJECT; +public: + FQTermWelcomeState(FQTermUniteSessionContext* context); + virtual void initialize(); +protected: + virtual bool keyReceived(int key); +private: + virtual void clearPointer(int index); + virtual void drawPointer(int index); + virtual void enterEntry(); +}; + +class FQTermExitState : public FQTermUniteState, public FQTermUniteMenu { + Q_OBJECT; +public: + FQTermExitState(FQTermUniteSessionContext* context); + virtual void initialize(); +protected: + virtual bool keyReceived(int key); +private: + virtual void clearPointer(int index); + virtual void drawPointer(int index); + void enterEntry(); +}; + +class SplittedArticleBuffer { +public: + SplittedArticleBuffer(const QByteArray& utf8Content, int column, int row = 24); + ~SplittedArticleBuffer() {} + int count() {return lines_.size();} + QByteArray& retriveLine(size_t index) {return lines_[index];} +private: + static int findNextLine(const QString& str, int start, int column); + std::vector lines_; +}; + +//TODO: content should be shared. +//TODO: buffer should be opt-ed. +class FQTermReadingState : public FQTermUniteState { + Q_OBJECT; +public: + FQTermReadingState(FQTermUniteSessionContext* context); + ~FQTermReadingState(); + virtual void initialize(); + void setFile(const QString& filename); + void setReturnState(int state) {returnState_ = state;} +protected: + virtual bool keyReceived(int key); +private: + void drawLines(int count, int yPos); + void drawFooter(); + void adjustLineByDiff(int delta); + SplittedArticleBuffer* saBuffer_; + QByteArray content_; + int currentStartLine_; + int returnState_; +}; + + +class FQTermHelpState : public FQTermUniteState, public FQTermUniteMenu { + Q_OBJECT; +public: + FQTermHelpState(FQTermUniteSessionContext* context); + virtual void initialize(); +protected: + virtual bool keyReceived(int key); +private: + virtual void clearPointer(int index); + virtual void drawPointer(int index); + virtual void enterEntry(); +}; + +} // namespace FQTerm +#endif \ No newline at end of file diff --git a/src/unite/internal/statebuilder.cpp b/src/unite/internal/statebuilder.cpp new file mode 100644 index 0000000..48ea6f6 --- /dev/null +++ b/src/unite/internal/statebuilder.cpp @@ -0,0 +1,32 @@ + +#include "statebuilder.h" +#include "fqterm.h" +#include "fqterm_path.h" + +#include +#include + +namespace FQTerm { + +void StateBuilder::BuildState() +{ + QDomDocument domDocument; + QFile welcome(getPath(RESOURCE) + "unite/welcom.xml"); + welcome.open(QIODevice::ReadOnly); + QString errorStr; + int errorLine; + int errorColumn; + domDocument.setContent(welcome.readAll(), true, &errorStr, &errorLine, &errorColumn); + QDomElement root = domDocument.firstChildElement("page"); + if (root.isNull()) + { + + } + QDomAttr a = root.attributeNode("type"); + //cout << a.value() << endl; + + +} + + +} \ No newline at end of file diff --git a/src/unite/internal/statebuilder.h b/src/unite/internal/statebuilder.h new file mode 100644 index 0000000..f323ecd --- /dev/null +++ b/src/unite/internal/statebuilder.h @@ -0,0 +1,16 @@ + +#ifndef FQTERM_UNITE_STATEBUILDER +#define FQTERM_UNITE_STATEBUILDER + +namespace FQTerm { + +class FQTermState; + +class StateBuilder +{ +public: + void BuildState(); +}; + +} +#endif \ No newline at end of file diff --git a/src/unite/internal/unite.h b/src/unite/internal/unite.h new file mode 100644 index 0000000..cc614a7 --- /dev/null +++ b/src/unite/internal/unite.h @@ -0,0 +1,35 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#ifndef FQTERM_UNITE_USER +#define FQTERM_UNITE_USER + +namespace FQTerm { +//to make it more clear, a general method to serialize c++ +//classes is needed. +class FQUUser { +public: +private: + +}; + +} //namespace FQTerm + +#endif //FQTERM_UNITE_USER \ No newline at end of file diff --git a/src/unite/internal/user.cpp b/src/unite/internal/user.cpp new file mode 100644 index 0000000..c5905f8 --- /dev/null +++ b/src/unite/internal/user.cpp @@ -0,0 +1,19 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ diff --git a/src/unite/internal/user.h b/src/unite/internal/user.h new file mode 100644 index 0000000..cc614a7 --- /dev/null +++ b/src/unite/internal/user.h @@ -0,0 +1,35 @@ +/*************************************************************************** +* fqterm, a terminal emulator for both BBS and *nix. * +* Copyright (C) 2008 fqterm development group. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +#ifndef FQTERM_UNITE_USER +#define FQTERM_UNITE_USER + +namespace FQTerm { +//to make it more clear, a general method to serialize c++ +//classes is needed. +class FQUUser { +public: +private: + +}; + +} //namespace FQTerm + +#endif //FQTERM_UNITE_USER \ No newline at end of file diff --git a/src/utilities/CMakeLists.txt b/src/utilities/CMakeLists.txt new file mode 100644 index 0000000..af3c169 --- /dev/null +++ b/src/utilities/CMakeLists.txt @@ -0,0 +1,33 @@ +set(fqterm_utilities_SRCS + fqterm_convert.h + fqterm_http.h + fqterm_ip_location.h + fqterm_convert.cpp + fqterm_http.cpp + fqterm_ip_location.cpp +) + +set(fq_SRCS + fqwcwidth.h + fqwcwidth.cpp +) + +qt4_automoc(${fqterm_utilities_SRCS}) + +include_directories( + ${QT_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} + ${QT_QTGUI_INCLUDE_DIR} + ${QT_QTNETWORK_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../common + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_library(fqterm_utilities + ${fqterm_utilities_SRCS} + ${fq_SRCS} +) + +add_dependencies(fqterm_utilities + fqterm_common +) diff --git a/src/utilities/fqterm_convert.cpp b/src/utilities/fqterm_convert.cpp new file mode 100644 index 0000000..3ac821d --- /dev/null +++ b/src/utilities/fqterm_convert.cpp @@ -0,0 +1,3485 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_convert.h" + +namespace FQTerm { + +const char BtoG_bad1 = '\xa1'; +const char BtoG_bad2 = '\xf5'; +const char GtoB_bad1 = '\xa1'; +const char GtoB_bad2 = '\xbc'; + +#define HIGHBYTE(word) (word)>>8 & 0x00ff +#define LOWBYTE(word) (word) & 0x00ff +#define MAKEWORD(c1,c2) ( (c1)<<8 & 0xff00 ) | c2 +FQTermConvert::FQTermConvert(){} + +FQTermConvert::~FQTermConvert(){} + +char *FQTermConvert::G2B(const char *string, int length) { + static char save = '\0'; + if (length == 0) { + return 0; + } + char *s = new char[length + 2]; //because we may have the save char + int len = length; + const char *p = string; + int n = 0; + + if (save != '\0') { + g2b(save, *p, s); + n = 2; + p++; + save = '\0'; + len++; + } + + while (p < string + length && *p != '\0') { + if (*p &0x80) { + // reach the end this is half of a word, save it + if (p == string + length - 1) { + save = *p; + len--; + break; + } + + g2b(*p, *(p + 1), s + n); + n += 2; + p += 2; + } else { + s[n] = *p; + p++; + n++; + } + } + + s[len] = '\0'; + return s; +} + +void FQTermConvert::g2b(unsigned char c1, unsigned char c2, char *s) { + unsigned int i; + if ((c2 >= 0xa1) && (c2 <= 0xfe)) { + if ((c1 >= 0xa1) && (c1 <= 0xa9)) { + i = ((c1 - 0xa1) *94+(c2 - 0xa1)) *2; + s[0] = GtoB[i++]; + s[1] = GtoB[i]; + return ; + } else if ((c1 >= 0xb0) && (c1 <= 0xf7)) { + i = ((c1 - 0xb0 + 9) *94+(c2 - 0xa1)) *2; + s[0] = GtoB[i++]; + s[1] = GtoB[i]; + return ; + } + } + s[0] = GtoB_bad1; + s[1] = GtoB_bad2; +} + +char *FQTermConvert::B2G(const char *string, int length) { + static char save = '\0'; + if (length == 0) { + return 0; + } + char *s = new char[length + 2]; //because we may have the save char + int len = length; + const char *p = string; + int n = 0; + + if (save != '\0') { + b2g(save, *p, s); + n = 2; + p++; + save = '\0'; + len++; + } + + while (p < string + length && *p != '\0') { + if (*p &0x80) { + // reach the end this is half of a word, save it + if (p == string + length - 1) { + save = *p; + len--; + break; + } + + b2g(*p, *(p + 1), s + n); + p += 2; + n += 2; + } else { + s[n] = *p; + p++; + n++; + } + } + + s[len] = '\0'; + return s; +} + +void FQTermConvert::b2g(unsigned char c1, unsigned char c2, char *s) { + unsigned int i; + if ((c1 >= 0xa1) && (c1 <= 0xf9)) { + if ((c2 >= 0x40) && (c2 <= 0x7e)) { + i = ((c1 - 0xa1) *157+(c2 - 0x40)) *2; + s[0] = BtoG[i++]; + s[1] = BtoG[i]; + return ; + } else if ((c2 >= 0xa1) && (c2 <= 0xfe)) { + i = ((c1 - 0xa1) *157+(c2 - 0xa1) + 63) *2; + s[0] = BtoG[i++]; + s[1] = BtoG[i]; + return ; + } + } + s[0] = BtoG_bad1; + s[1] = BtoG_bad2; +} + +unsigned char FQTermConvert::GtoB[] = { + 0xa1, 0x40, 0xa1, 0x42, 0xa1, 0x43, 0xa1, 0x4f, 0xa1, 0xc2, 0xa1, 0xbc, 0xa1, + 0x4c, 0xa1, 0xb2, 0xa1, 0xbc, 0xa2, 0x77, 0xa1, 0xe3, 0xa1, 0xfc, 0xa1, 0x4b, + 0xa1, 0xa5, 0xa1, 0xa6, 0xa1, 0xa7, 0xa1, 0xa8, 0xa1, 0x65, 0xa1, 0x66, 0xa1, + 0x71, 0xa1, 0x72, 0xa1, 0x6d, 0xa1, 0x6e, 0xa1, 0x75, 0xa1, 0x76, 0xa1, 0x79, + 0xa1, 0x7a, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0x69, 0xa1, 0x6a, 0xa1, 0xd3, 0xa1, + 0xd1, 0xa1, 0xd2, 0xa1, 0x4a, 0xa3, 0x4e, 0xa1, 0xbc, 0xa3, 0x55, 0xa3, 0x53, + 0xa1, 0xe5, 0xa1, 0xe4, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xd4, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xe7, 0xa1, 0xbc, 0xa1, 0xf3, 0xa1, 0xec, 0xa1, 0xed, 0xa1, 0xdd, + 0xa1, 0xbc, 0xa1, 0xdc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xda, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xd8, 0xa1, 0xd9, 0xa1, 0xdb, 0xa1, 0xee, 0xa1, 0xef, 0xa1, 0xf1, + 0xa1, 0xf0, 0xa2, 0x58, 0xa1, 0xac, 0xa1, 0xaa, 0xa2, 0x4a, 0xa2, 0x43, 0xa1, + 0xbc, 0xa2, 0x46, 0xa2, 0x47, 0xa1, 0xbc, 0xa1, 0xb1, 0xa1, 0xbc, 0xa1, 0xb8, + 0xa1, 0xb9, 0xa1, 0xb3, 0xa1, 0xb4, 0xa1, 0xb7, 0xa1, 0xba, 0xa1, 0xbb, 0xa1, + 0xbc, 0xa1, 0xbd, 0xa1, 0xb5, 0xa1, 0xb6, 0xa1, 0xb0, 0xa1, 0xf7, 0xa1, 0xf6, + 0xa1, 0xf4, 0xa1, 0xf5, 0xa2, 0xa4, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa2, 0xb9, 0xa2, + 0xba, 0xa2, 0xbb, 0xa2, 0xbc, 0xa2, 0xbd, 0xa2, 0xbe, 0xa2, 0xbf, 0xa2, 0xc0, + 0xa2, 0xc1, 0xa2, 0xc2, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0x49, 0xa1, 0xa9, 0xa1, 0xad, 0xa2, 0x43, 0xa2, 0x48, 0xa1, 0xae, 0xa1, 0xac, + 0xa1, 0x5d, 0xa1, 0x5e, 0xa1, 0xaf, 0xa1, 0xcf, 0xa1, 0x41, 0xa1, 0xd0, 0xa1, + 0x44, 0xa1, 0xfe, 0xa2, 0xaf, 0xa2, 0xb0, 0xa2, 0xb1, 0xa2, 0xb2, 0xa2, 0xb3, + 0xa2, 0xb4, 0xa2, 0xb5, 0xa2, 0xb6, 0xa2, 0xb7, 0xa2, 0xb8, 0xa1, 0x47, 0xa1, + 0x46, 0xa1, 0xd5, 0xa1, 0xd7, 0xa1, 0xd6, 0xa1, 0x48, 0xa2, 0x49, 0xa2, 0xcf, + 0xa2, 0xd0, 0xa2, 0xd1, 0xa2, 0xd2, 0xa2, 0xd3, 0xa2, 0xd4, 0xa2, 0xd5, 0xa2, + 0xd6, 0xa2, 0xd7, 0xa2, 0xd8, 0xa2, 0xd9, 0xa2, 0xda, 0xa2, 0xdb, 0xa2, 0xdc, + 0xa2, 0xdd, 0xa2, 0xde, 0xa2, 0xdf, 0xa2, 0xe0, 0xa2, 0xe1, 0xa2, 0xe2, 0xa2, + 0xe3, 0xa2, 0xe4, 0xa2, 0xe5, 0xa2, 0xe6, 0xa2, 0xe7, 0xa2, 0xe8, 0xa1, 0xa3, + 0xa2, 0x40, 0xa1, 0xa4, 0xa1, 0x73, 0xa1, 0x5a, 0xa1, 0xab, 0xa2, 0xe9, 0xa2, + 0xea, 0xa2, 0xeb, 0xa2, 0xec, 0xa2, 0xed, 0xa2, 0xee, 0xa2, 0xef, 0xa2, 0xf0, + 0xa2, 0xf1, 0xa2, 0xf2, 0xa2, 0xf3, 0xa2, 0xf4, 0xa2, 0xf5, 0xa2, 0xf6, 0xa2, + 0xf7, 0xa2, 0xf8, 0xa2, 0xf9, 0xa2, 0xfa, 0xa2, 0xfb, 0xa2, 0xfc, 0xa2, 0xfd, + 0xa2, 0xfe, 0xa3, 0x40, 0xa3, 0x41, 0xa3, 0x42, 0xa3, 0x43, 0xa1, 0x61, 0xa1, + 0x55, 0xa1, 0x62, 0xa1, 0xc2, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa3, 0x44, 0xa3, 0x45, 0xa3, 0x46, 0xa3, 0x47, 0xa3, + 0x48, 0xa3, 0x49, 0xa3, 0x4a, 0xa3, 0x4b, 0xa3, 0x4c, 0xa3, 0x4d, 0xa3, 0x4e, + 0xa3, 0x4f, 0xa3, 0x50, 0xa3, 0x51, 0xa3, 0x52, 0xa3, 0x53, 0xa3, 0x54, 0xa3, + 0x55, 0xa3, 0x56, 0xa3, 0x57, 0xa3, 0x58, 0xa3, 0x59, 0xa3, 0x5a, 0xa3, 0x5b, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa3, 0x5c, 0xa3, 0x5d, 0xa3, 0x5e, 0xa3, 0x5f, 0xa3, 0x60, + 0xa3, 0x61, 0xa3, 0x62, 0xa3, 0x63, 0xa3, 0x64, 0xa3, 0x65, 0xa3, 0x66, 0xa3, + 0x67, 0xa3, 0x68, 0xa3, 0x69, 0xa3, 0x6a, 0xa3, 0x6b, 0xa3, 0x6c, 0xa3, 0x6d, + 0xa3, 0x6e, 0xa3, 0x6f, 0xa3, 0x70, 0xa3, 0x71, 0xa3, 0x72, 0xa3, 0x73, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa3, 0x74, 0xa3, + 0x75, 0xa3, 0x76, 0xa3, 0x77, 0xa3, 0x78, 0xa3, 0x79, 0xa3, 0x7a, 0xa3, 0x7b, + 0xa3, 0x7c, 0xa3, 0x7d, 0xa3, 0x7e, 0xa3, 0xa1, 0xa3, 0xa2, 0xa3, 0xa3, 0xa3, + 0xa4, 0xa3, 0xa5, 0xa3, 0xa6, 0xa3, 0xa7, 0xa3, 0xa8, 0xa3, 0xa9, 0xa3, 0xaa, + 0xa3, 0xab, 0xa3, 0xac, 0xa3, 0xad, 0xa3, 0xae, 0xa3, 0xaf, 0xa3, 0xb0, 0xa3, + 0xb1, 0xa3, 0xb2, 0xa3, 0xb3, 0xa3, 0xb4, 0xa3, 0xb5, 0xa3, 0xb6, 0xa3, 0xb7, + 0xa3, 0xb8, 0xa3, 0xb9, 0xa3, 0xba, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa2, 0x77, 0xa1, 0xbc, 0xa2, 0x78, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa2, 0x7a, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa2, 0x7b, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa2, 0x7c, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa2, 0x7d, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa2, 0x75, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa2, 0x74, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa2, + 0x73, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa2, 0x72, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa2, 0x71, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, + 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xa1, 0xbc, 0xb0, 0xda, 0xaa, 0xfc, 0xae, 0x4a, 0xae, 0xc1, 0xab, 0x75, 0xad, + 0xfc, 0xab, 0x73, 0xbd, 0x4a, 0xc0, 0xf9, 0xc4, 0xa7, 0xb8, 0x47, 0xa6, 0xe3, + 0xc3, 0xaa, 0xb7, 0x52, 0xb9, 0x69, 0xbe, 0x62, 0xae, 0xf2, 0xa6, 0x77, 0xad, + 0xcd, 0xab, 0xf6, 0xb7, 0x74, 0xa9, 0xa4, 0xd3, 0x69, 0xae, 0xd7, 0xbb, 0xea, + 0xa9, 0xf9, 0xaf, 0x73, 0xa5, 0x57, 0xb1, 0xce, 0xbc, 0xf5, 0xbf, 0xac, 0xc3, + 0xcd, 0xb6, 0xc6, 0xb6, 0xf8, 0xbe, 0xd2, 0xbf, 0x44, 0xaa, 0xdd, 0xae, 0xc3, + 0xa5, 0xb6, 0xa5, 0x7a, 0xa7, 0x61, 0xaf, 0xb9, 0xa4, 0x4b, 0xac, 0xcd, 0xa4, + 0xda, 0xa9, 0xde, 0xb6, 0x5b, 0xb9, 0x76, 0xa7, 0xe2, 0xaf, 0xd2, 0xc5, 0xf2, + 0xc5, 0x51, 0xbd, 0x7d, 0xaa, 0xa8, 0xa5, 0xd5, 0xac, 0x66, 0xa6, 0xca, 0xc2, + 0x5c, 0xa8, 0xd5, 0xb1, 0xd1, 0xab, 0xf4, 0xde, 0xfb, 0xb4, 0xb3, 0xaf, 0x5a, + 0xb7, 0x68, 0xa7, 0xe6, 0xaf, 0xeb, 0xb9, 0x7b, 0xaa, 0x4f, 0xaa, 0xa9, 0xa7, + 0xea, 0xa9, 0xd5, 0xa6, 0xf1, 0xc3, 0xa4, 0xa5, 0x62, 0xbf, 0xec, 0xb2, 0xcc, + 0xa8, 0xb9, 0xc0, 0xb0, 0xb1, 0xf5, 0xba, 0x5d, 0xbb, 0x48, 0xb8, 0x6a, 0xb4, + 0xce, 0xbd, 0x53, 0xb0, 0x46, 0xc2, 0xe9, 0xb3, 0xc4, 0xc1, 0xbd, 0xad, 0x63, + 0xad, 0x4d, 0xa5, 0x5d, 0xbd, 0xc7, 0xad, 0xe9, 0xc1, 0xa1, 0xb9, 0x72, 0xab, + 0x4f, 0xb3, 0xf9, 0xb9, 0xa1, 0xc4, 0x5f, 0xa9, 0xea, 0xb3, 0xf8, 0xbc, 0xc9, + 0xb0, 0x5c, 0xc0, 0x6a, 0xc3, 0x7a, 0xaa, 0x4d, 0xb8, 0x4f, 0xb4, 0x64, 0xa8, + 0xf5, 0xa5, 0x5f, 0xbd, 0xfa, 0xad, 0x49, 0xa8, 0xa9, 0xbe, 0x58, 0xad, 0xbf, + 0xaf, 0x56, 0xb3, 0xc6, 0xbe, 0xce, 0xb5, 0x48, 0xb3, 0x51, 0xa9, 0x62, 0xad, + 0x66, 0xa5, 0xbb, 0xb2, 0xc2, 0xb1, 0x59, 0xc1, 0x5e, 0xac, 0xc7, 0xac, 0xa6, + 0xc2, 0xdb, 0xb0, 0x6e, 0xb9, 0x47, 0xbb, 0xf3, 0xa4, 0xf1, 0xbb, 0xc0, 0xb5, + 0xa7, 0xa9, 0xbc, 0xba, 0xd1, 0xe3, 0xc9, 0xbd, 0xaa, 0xb2, 0xa6, 0xc0, 0xc5, + 0xcf, 0x68, 0xb9, 0xf4, 0xa7, 0xc8, 0xde, 0xcd, 0xb3, 0xac, 0xb1, 0xcd, 0xb9, + 0xfa, 0xa5, 0xb2, 0xb9, 0x40, 0xbe, 0xc0, 0xc1, 0x75, 0xc1, 0xd7, 0xb0, 0xa1, + 0xc3, 0x40, 0xc3, 0xe4, 0xbd, 0x73, 0xb6, 0x53, 0xab, 0xf3, 0xab, 0x4b, 0xc5, + 0xdc, 0xa4, 0xcb, 0xbf, 0xeb, 0xc5, 0x47, 0xc4, 0x7c, 0xb9, 0x4d, 0xbc, 0xd0, + 0xb3, 0x43, 0xbd, 0xa8, 0xaa, 0xed, 0xc5, 0xbe, 0xe5, 0x78, 0xa7, 0x4f, 0xc3, + 0xa7, 0xb1, 0x6c, 0xd9, 0x79, 0xc3, 0x78, 0xc0, 0xd8, 0xbb, 0xab, 0xec, 0xe8, + 0xa7, 0x4c, 0xa6, 0x42, 0xac, 0x60, 0xa4, 0xfe, 0xaa, 0xc3, 0xbb, 0xe6, 0xac, + 0xb1, 0xaf, 0x66, 0xa8, 0xc3, 0xac, 0xc1, 0xb5, 0xd4, 0xbc, 0xbd, 0xbc, 0xb7, + 0xd2, 0xdc, 0xaa, 0x69, 0xb3, 0xd5, 0xab, 0x6b, 0xb7, 0x69, 0xb9, 0x60, 0xba, + 0xe4, 0xa7, 0x42, 0xa9, 0xad, 0xb2, 0xed, 0xb2, 0xe4, 0xbb, 0x4b, 0xb4, 0xf1, + 0xaa, 0x79, 0xbb, 0xe9, 0xae, 0xb7, 0xa4, 0x52, 0xad, 0xf7, 0xb8, 0xc9, 0xb0, + 0xf0, 0xa4, 0xa3, 0xa5, 0xac, 0xa8, 0x42, 0xc3, 0xaf, 0xb3, 0xa1, 0xa9, 0xc6, + 0xc0, 0xbf, 0xb2, 0x71, 0xb5, 0xf4, 0xa7, 0xf7, 0xa4, 0x7e, 0xb0, 0x5d, 0xb8, + 0x42, 0xbd, 0xf2, 0xb1, 0xc4, 0xb1, 0x6d, 0xb5, 0xe6, 0xbd, 0xb2, 0xc0, 0x5c, + 0xb0, 0xd1, 0xc5, 0xfa, 0xb4, 0xdd, 0xba, 0x46, 0xba, 0x47, 0xc0, 0xe9, 0xbb, + 0x61, 0xbf, 0xb5, 0xad, 0xdc, 0xb7, 0xc9, 0xc2, 0xc3, 0xbe, 0xde, 0xc1, 0x57, + 0xbc, 0xd1, 0xb1, 0xe4, 0xaf, 0xf3, 0xb4, 0x5a, 0xb5, 0xa6, 0xb0, 0xbc, 0xa5, + 0x55, 0xb4, 0xfa, 0xbc, 0x68, 0xf3, 0x4f, 0xb4, 0xa1, 0xa4, 0x65, 0xd3, 0xb3, + 0xaf, 0xf9, 0xac, 0x64, 0xe2, 0xed, 0xb7, 0x67, 0xb9, 0xee, 0xa7, 0xc3, 0xae, + 0x74, 0xb8, 0xd2, 0xa9, 0xee, 0xae, 0xe3, 0xb0, 0x5b, 0xc4, 0x65, 0xba, 0x55, + 0xc2, 0xcd, 0xc6, 0x61, 0xc5, 0xfe, 0xc4, 0xf1, 0xc3, 0xea, 0xb2, 0xa3, 0xc4, + 0xc4, 0xc5, 0xb8, 0xa9, 0xf7, 0xb2, 0x73, 0xb3, 0xf5, 0xb9, 0xc1, 0xb1, 0x60, + 0xaa, 0xf8, 0xc0, 0x76, 0xb8, 0x7a, 0xbc, 0x74, 0xb4, 0xaf, 0xba, 0x5a, 0xb0, + 0xdb, 0xad, 0xd2, 0xb6, 0x57, 0xa7, 0xdb, 0xb6, 0x72, 0xb4, 0xc2, 0xbc, 0x4a, + 0xbc, 0xe9, 0xb1, 0x5f, 0xa7, 0x6e, 0xaa, 0xa3, 0xa8, 0xae, 0xa7, 0xe8, 0xba, + 0x4d, 0xb4, 0x77, 0xb9, 0xfd, 0xba, 0xab, 0xd7, 0xeb, 0xa6, 0xda, 0xa8, 0xb0, + 0xb9, 0xd0, 0xb1, 0xe1, 0xa7, 0xd5, 0xa8, 0x49, 0xb3, 0xaf, 0xb6, 0x58, 0xc5, + 0xa8, 0xbc, 0xb5, 0xba, 0xd9, 0xab, 0xb0, 0xbe, 0xed, 0xa6, 0xa8, 0xa7, 0x65, + 0xad, 0xbc, 0xb5, 0x7b, 0xc3, 0x67, 0xbc, 0xe1, 0xb8, 0xdb, 0xa9, 0xd3, 0xb3, + 0x78, 0xc1, 0xfe, 0xaf, 0xaf, 0xa6, 0x59, 0xb7, 0xf6, 0xab, 0xf9, 0xb0, 0xcd, + 0xa6, 0xc0, 0xbf, 0xf0, 0xa6, 0xa2, 0xb9, 0xa3, 0xae, 0xa2, 0xbe, 0xa6, 0xa8, + 0xd7, 0xa4, 0xd8, 0xa8, 0xaa, 0xaf, 0xcd, 0xa5, 0xb8, 0xbf, 0x4b, 0xa5, 0x52, + 0xa8, 0x52, 0xc2, 0xce, 0xb1, 0x52, 0xc3, 0x64, 0xa9, 0xe2, 0xb9, 0x53, 0xc3, + 0xa5, 0xc5, 0x43, 0xb8, 0x59, 0xb7, 0x54, 0xc4, 0x77, 0xa4, 0xb3, 0xba, 0xf7, + 0xe2, 0xe4, 0xc1, 0xe0, 0xaf, 0xe4, 0xaa, 0xec, 0xa5, 0x58, 0xc3, 0x6f, 0xbc, + 0x70, 0xc3, 0xdc, 0xbe, 0x53, 0xc2, 0xfa, 0xde, 0x51, 0xb0, 0xa3, 0xb7, 0xa1, + 0xc2, 0xa6, 0xc0, 0x78, 0xc5, 0xf7, 0xdd, 0x7a, 0xc4, 0xb2, 0xb3, 0x42, 0xb4, + 0xa2, 0xa4, 0x74, 0xac, 0xef, 0xdd, 0xdc, 0xb6, 0xc7, 0xb2, 0xee, 0xb3, 0xdd, + 0xa6, 0xea, 0xbd, 0x48, 0xb5, 0xa1, 0xbc, 0x6c, 0xa7, 0xc9, 0xc2, 0xf4, 0xb3, + 0xd0, 0xa7, 0x6a, 0xaa, 0xa4, 0xb4, 0xa8, 0xc1, 0xe8, 0xab, 0xab, 0xac, 0x4b, + 0xdd, 0xcf, 0xbe, 0x4a, 0xae, 0x42, 0xb2, 0x45, 0xaf, 0xc2, 0xc4, 0xf8, 0xc2, + 0x57, 0xba, 0xef, 0xb2, 0xab, 0xaf, 0xfd, 0xba, 0xcf, 0xbb, 0xdb, 0xc3, 0xe3, + 0xb7, 0x4f, 0xb2, 0xa1, 0xb5, 0xfc, 0xa6, 0xb9, 0xa8, 0xeb, 0xbd, 0xe7, 0xa6, + 0xb8, 0xc1, 0x6f, 0xbd, 0xb5, 0xa7, 0x77, 0xa5, 0x5e, 0xb1, 0x71, 0xc2, 0x4f, + 0xb4, 0xea, 0xb2, 0xca, 0xbe, 0x4c, 0xc1, 0x4c, 0xab, 0x50, 0xf9, 0x4f, 0xbf, + 0x79, 0xc2, 0xab, 0xba, 0x52, 0xb1, 0x5a, 0xb6, 0xca, 0xaf, 0xdc, 0xb7, 0xf1, + 0xba, 0xe9, 0xb2, 0x66, 0xbb, 0x41, 0xa7, 0xf8, 0xa6, 0x73, 0xa4, 0x6f, 0xbd, + 0x52, 0xbc, 0xbc, 0xb7, 0x62, 0xb1, 0xb9, 0xae, 0xc0, 0xbf, 0xf9, 0xb7, 0x66, + 0xb9, 0x46, 0xb5, 0xaa, 0xbd, 0x44, 0xa5, 0xb4, 0xa4, 0x6a, 0xa7, 0x62, 0xa4, + 0xef, 0xd8, 0x56, 0xc0, 0xb9, 0xb1, 0x61, 0xac, 0x70, 0xa5, 0x4e, 0xb6, 0x55, + 0xb3, 0x55, 0xab, 0xdd, 0xb6, 0x65, 0xab, 0xe5, 0xaf, 0xd4, 0xbe, 0xe1, 0xa4, + 0xa6, 0xb3, 0xe6, 0xe8, 0x58, 0xe5, 0xb8, 0xc1, 0x78, 0xa5, 0xb9, 0xb4, 0xe1, + 0xa6, 0xfd, 0xbc, 0xaa, 0xb2, 0x48, 0xbd, 0xcf, 0xbc, 0x75, 0xb3, 0x4a, 0xb7, + 0xed, 0xbe, 0xd7, 0xc4, 0xd2, 0xc0, 0xfa, 0xc0, 0xc9, 0xa4, 0x4d, 0xb7, 0x6f, + 0xc1, 0xd0, 0xad, 0xcb, 0xae, 0x71, 0xc3, 0xab, 0xbe, 0xc9, 0xa8, 0xec, 0xbd, + 0x5f, 0xb1, 0xa5, 0xb9, 0x44, 0xb5, 0x73, 0xbc, 0x77, 0xb1, 0x6f, 0xaa, 0xba, + 0xc3, 0xde, 0xbf, 0x4f, 0xb5, 0x6e, 0xb5, 0xa5, 0xc0, 0xfc, 0xb9, 0xb9, 0xbe, + 0x48, 0xb3, 0xf6, 0xa7, 0x43, 0xba, 0x77, 0xad, 0x7d, 0xbc, 0xc4, 0xb2, 0xc3, + 0xa8, 0x66, 0xba, 0xb0, 0xbb, 0x43, 0xb9, 0xde, 0xa9, 0xe8, 0xa9, 0xb3, 0xa6, + 0x61, 0xb8, 0xa6, 0xb2, 0xc4, 0xab, 0xd2, 0xa7, 0xcc, 0xbb, 0xbc, 0xbd, 0x6c, + 0xc4, 0x41, 0xd5, 0x69, 0xb7, 0xbf, 0xb8, 0x4b, 0xc2, 0x49, 0xa8, 0xe5, 0xc0, + 0x51, 0xb9, 0xd4, 0xb9, 0x71, 0xa6, 0xfa, 0xa8, 0x6c, 0xa9, 0xb1, 0xb1, 0x7d, + 0xb3, 0xfe, 0xbe, 0xfd, 0xb7, 0xb5, 0xb8, 0x4d, 0xa5, 0x70, 0xc0, 0x4a, 0xad, + 0xe4, 0xa4, 0x4e, 0xb1, 0xbc, 0xa6, 0x51, 0xb3, 0xa8, 0xbd, 0xd5, 0xb6, 0x5e, + 0xaf, 0x52, 0xba, 0xd0, 0xbd, 0xba, 0xad, 0xa1, 0xbf, 0xd2, 0xc5, 0x7c, 0xa4, + 0x42, 0xa8, 0x6e, 0xa5, 0x6d, 0xb0, 0x76, 0xb3, 0xbb, 0xb9, 0xa9, 0xbf, 0xf5, + 0xa9, 0x77, 0xad, 0x71, 0xa5, 0xe1, 0xaa, 0x46, 0xa5, 0x56, 0xb8, 0xb3, 0xc0, + 0xb4, 0xb0, 0xca, 0xb4, 0xc9, 0xcb, 0xbe, 0xab, 0xf0, 0xad, 0xe1, 0xac, 0x7d, + 0xb0, 0xc2, 0xa7, 0xdd, 0xb0, 0xab, 0xb0, 0x7e, 0xa8, 0xa7, 0xb3, 0x72, 0xb5, + 0x6b, 0xb3, 0xa3, 0xb7, 0xfe, 0xac, 0x72, 0xc3, 0x7d, 0xbf, 0x57, 0xc5, 0xaa, + 0xb0, 0xf4, 0xb8, 0x40, 0xbd, 0xe4, 0xa7, 0xf9, 0xc1, 0xe1, 0xa8, 0x7b, 0xab, + 0xd7, 0xb4, 0xe7, 0xa7, 0xaa, 0xba, 0xdd, 0xb5, 0x75, 0xc1, 0xeb, 0xac, 0x71, + 0xc2, 0x5f, 0xbd, 0x76, 0xb0, 0xef, 0xa7, 0x49, 0xb6, 0xa4, 0xb9, 0xef, 0xbc, + 0x5b, 0xbe, 0xb7, 0xc3, 0xdb, 0xb4, 0xb0, 0xb9, 0x79, 0xa7, 0x79, 0xb6, 0x77, + 0xac, 0xde, 0xb9, 0x50, 0xd5, 0x73, 0xce, 0x47, 0xa6, 0x68, 0xb9, 0xdc, 0xce, + 0x57, 0xb8, 0xfa, 0xa6, 0xb7, 0xb8, 0xf6, 0xb2, 0xeb, 0xa8, 0xef, 0xb4, 0x6b, + 0xbc, 0x5a, 0xb8, 0xbf, 0xae, 0x6f, 0xc3, 0x5a, 0xab, 0x58, 0xc3, 0x42, 0xb3, + 0x5f, 0xae, 0x5a, 0xb4, 0x63, 0xa4, 0xcc, 0xa7, 0xe3, 0xb9, 0x4b, 0xb6, 0x6b, + 0xbe, 0x6a, 0xae, 0xa6, 0xa6, 0xd3, 0xa8, 0xe0, 0xa6, 0xd5, 0xba, 0xb8, 0xbb, + 0xe7, 0xac, 0x7c, 0xa4, 0x47, 0xb6, 0x4c, 0xb5, 0x6f, 0xbb, 0x40, 0xb5, 0xad, + 0xa5, 0xef, 0xa5, 0x46, 0xbb, 0xd6, 0xaa, 0x6b, 0xb5, 0x57, 0xc3, 0xbf, 0xa6, + 0x7c, 0xb5, 0x66, 0xc2, 0xbd, 0xbc, 0xd4, 0xc4, 0x73, 0xb3, 0xab, 0xc1, 0x63, + 0xa4, 0x5a, 0xb7, 0xd0, 0xa4, 0xcf, 0xaa, 0xf0, 0xad, 0x53, 0xb3, 0x63, 0xa5, + 0xc7, 0xb6, 0xba, 0xaa, 0x78, 0xa7, 0x7b, 0xaa, 0xda, 0xa4, 0xe8, 0xaa, 0xd5, + 0xa9, 0xd0, 0xa8, 0xbe, 0xa7, 0xab, 0xa5, 0xe9, 0xb3, 0x58, 0xaf, 0xbc, 0xa9, + 0xf1, 0xb5, 0xe1, 0xab, 0x44, 0xb0, 0xd8, 0xad, 0xb8, 0xaa, 0xce, 0xad, 0xea, + 0xbd, 0xda, 0xa7, 0x70, 0xaa, 0xcd, 0xbc, 0x6f, 0xaa, 0x6d, 0xb6, 0x4f, 0xaa, + 0xe2, 0xd7, 0xf4, 0xa7, 0x68, 0xaa, 0x5e, 0xa4, 0xc0, 0xaf, 0xc9, 0xbc, 0x58, + 0xb5, 0x49, 0xa8, 0x57, 0xaf, 0xbb, 0xbe, 0xc4, 0xa5, 0xf7, 0xa9, 0xc1, 0xbc, + 0xab, 0xc1, 0x54, 0xc2, 0xd7, 0xab, 0xca, 0xb7, 0xac, 0xb8, 0xc1, 0xae, 0x70, + 0xbe, 0x57, 0xad, 0xb7, 0xba, 0xc6, 0xb2, 0x6c, 0xb3, 0x7b, 0xb6, 0xbe, 0xc1, + 0x5f, 0xbf, 0xd8, 0xa9, 0x5e, 0xbb, 0xf1, 0xa6, 0xf2, 0xa7, 0x5f, 0xa4, 0xd2, + 0xbc, 0xc5, 0xbd, 0xa7, 0xb9, 0xe5, 0xa7, 0xdf, 0xa9, 0xd8, 0xbf, 0xe7, 0xb4, + 0x54, 0xac, 0x74, 0xb2, 0xc5, 0xa5, 0xf1, 0xab, 0x52, 0xaa, 0x41, 0xaf, 0x42, + 0xb2, 0x65, 0xba, 0xd6, 0xb5, 0xf6, 0xa5, 0xb1, 0xa8, 0x6a, 0xbc, 0xbe, 0xbb, + 0xb2, 0xad, 0xc1, 0xb0, 0x79, 0xa9, 0xf2, 0xb2, 0xe3, 0xb5, 0xc6, 0xa9, 0xb2, + 0xbb, 0x47, 0xad, 0x75, 0xb0, 0xc6, 0xc2, 0xd0, 0xbd, 0xe1, 0xb4, 0x5f, 0xb3, + 0xc5, 0xa5, 0x49, 0xaa, 0xfa, 0xa4, 0xf7, 0xb8, 0xa1, 0xad, 0x74, 0xb4, 0x49, + 0xad, 0x72, 0xaa, 0xfe, 0xb0, 0xfc, 0xbf, 0xa3, 0xa9, 0x4a, 0xbe, 0xbf, 0xb9, + 0xc7, 0xb8, 0xd3, 0xa7, 0xef, 0xb7, 0xa7, 0xb6, 0x74, 0xbb, 0x5c, 0xb5, 0x40, + 0xb7, 0x46, 0xa5, 0xcc, 0xb1, 0xec, 0xac, 0x61, 0xac, 0xf1, 0xa8, 0x78, 0xbb, + 0xb0, 0xb7, 0x50, 0xb5, 0x7a, 0xb4, 0xb1, 0xc6, 0x42, 0xa9, 0xa3, 0xad, 0xe8, + 0xbf, 0xfb, 0xac, 0xfb, 0xa8, 0x7a, 0xba, 0xf5, 0xb1, 0x5e, 0xb4, 0xe4, 0xba, + 0x62, 0xbf, 0x74, 0xaf, 0x6f, 0xb0, 0xaa, 0xbb, 0x49, 0xaf, 0xcc, 0xbf, 0x7c, + 0xb7, 0x64, 0xc2, 0xee, 0xbd, 0x5a, 0xa7, 0x69, 0xad, 0xf4, 0xba, 0x71, 0xc0, + 0xc1, 0xa4, 0xe0, 0xc2, 0x46, 0xaf, 0xde, 0xaa, 0xb8, 0xb3, 0xce, 0xad, 0xb2, + 0xb8, 0xaf, 0xae, 0xe6, 0xb5, 0xf0, 0xbb, 0xd5, 0xb9, 0x6a, 0xbb, 0xcc, 0xad, + 0xd3, 0xa6, 0x55, 0xb5, 0xb9, 0xae, 0xda, 0xb8, 0xf2, 0xaf, 0xd1, 0xa7, 0xf3, + 0xa9, 0xb0, 0xc3, 0xbc, 0xae, 0x47, 0xaf, 0xd5, 0xb1, 0xf0, 0xa4, 0x75, 0xa7, + 0xf0, 0xa5, 0x5c, 0xae, 0xa5, 0xc5, 0xc7, 0xa8, 0xd1, 0xb0, 0x60, 0xa4, 0xbd, + 0xae, 0x63, 0xa4, 0x7d, 0xbe, 0x64, 0xa8, 0x45, 0xab, 0xfd, 0xb0, 0x5e, 0xa6, + 0x40, 0xb9, 0x5f, 0xa4, 0xc4, 0xb7, 0xbe, 0xad, 0x65, 0xaa, 0xaf, 0xab, 0xaf, + 0xba, 0x63, 0xc1, 0xca, 0xb0, 0xf7, 0xb6, 0x64, 0xdb, 0xa3, 0xa9, 0x42, 0xe3, + 0x54, 0xa6, 0xf4, 0xaa, 0x66, 0xa9, 0x74, 0xa9, 0x68, 0xb9, 0xaa, 0xa5, 0x6a, + 0xc5, 0xdb, 0xb0, 0xa9, 0xa8, 0xa6, 0xaa, 0xd1, 0xac, 0x47, 0xc5, 0x55, 0xa9, + 0x54, 0xb6, 0xb1, 0xa8, 0xed, 0xa5, 0xca, 0xd4, 0x6c, 0xb9, 0xe8, 0xb1, 0xbe, + 0xbb, 0x6f, 0xa8, 0xc4, 0xa9, 0xe4, 0xa9, 0xc7, 0xb4, 0xc3, 0xc3, 0xf6, 0xa9, + 0x78, 0xab, 0x61, 0xc6, 0x5b, 0xba, 0xde, 0xc0, 0x5d, 0xc5, 0xf8, 0xba, 0x44, + 0xc4, 0xe9, 0xb3, 0x65, 0xa5, 0xfa, 0xbc, 0x73, 0xb3, 0x7d, 0xba, 0xc0, 0xb3, + 0x57, 0xa6, 0x63, 0xd6, 0xba, 0xc2, 0x6b, 0xc0, 0x74, 0xbb, 0xd3, 0xad, 0x79, + 0xb0, 0xad, 0xb8, 0xde, 0xac, 0xd1, 0xae, 0xdb, 0xc2, 0x64, 0xb8, 0xf7, 0xb6, + 0x51, 0xbc, 0x44, 0xbe, 0x40, 0xba, 0x75, 0xb4, 0xd2, 0xc1, 0xe7, 0xb3, 0xa2, + 0xb0, 0xea, 0xaa, 0x47, 0xbb, 0x71, 0xb9, 0x4c, 0xab, 0xa2, 0xc0, 0x65, 0xab, + 0xc4, 0xae, 0xfc, 0xae, 0xf3, 0xa5, 0xe8, 0xae, 0x60, 0xc0, 0x62, 0xb6, 0x6f, + 0xe9, 0x77, 0xcd, 0xd5, 0xc1, 0xfa, 0xa7, 0x74, 0xb2, 0x5b, 0xb4, 0x48, 0xa8, + 0xe7, 0xb3, 0xdb, 0xa8, 0x75, 0xbf, 0xab, 0xbe, 0xd9, 0xae, 0xc2, 0xa7, 0xf2, + 0xbe, 0xd1, 0xae, 0xab, 0xb2, 0x6b, 0xa6, 0xbd, 0xba, 0x7e, 0xc9, 0x71, 0xaa, + 0x43, 0xaf, 0xe8, 0xc0, 0xa2, 0xc0, 0x7a, 0xbb, 0xa8, 0xb2, 0x40, 0xb0, 0x71, + 0xa6, 0x6e, 0xaf, 0xd3, 0xb8, 0xb9, 0xaf, 0x45, 0xa8, 0xfe, 0xb3, 0xdc, 0xb2, + 0xfc, 0xdb, 0x5d, 0xae, 0xd6, 0xa5, 0xdd, 0xa9, 0x4d, 0xa6, 0xf3, 0xa6, 0x58, + 0xb2, 0xb0, 0xb8, 0xe8, 0xbb, 0xd2, 0xaa, 0x65, 0xb2, 0x55, 0xbb, 0xae, 0xbd, + 0xc5, 0xc5, 0x62, 0xb6, 0x50, 0xbc, 0x4b, 0xb6, 0xc2, 0xb2, 0xaa, 0xab, 0xdc, + 0xac, 0xbd, 0xab, 0xeb, 0xad, 0xf3, 0xa6, 0xeb, 0xbe, 0xee, 0xbf, 0xc5, 0xab, + 0xed, 0xc5, 0x46, 0xab, 0xa1, 0xaf, 0x4d, 0xad, 0x69, 0xc2, 0x45, 0xac, 0x78, + 0xa7, 0xbb, 0xa5, 0xb0, 0xac, 0xf5, 0xb3, 0xef, 0xab, 0x4a, 0xb5, 0x55, 0xa7, + 0x71, 0xab, 0x70, 0xad, 0xd4, 0xab, 0xe1, 0xa9, 0x49, 0xa5, 0x47, 0xa9, 0xbf, + 0xb7, 0xe4, 0xb3, 0xfd, 0xb8, 0xac, 0xad, 0x4a, 0xbd, 0xb9, 0xaa, 0xb0, 0xbd, + 0x6b, 0xb4, 0xf2, 0xa9, 0xb7, 0xaa, 0xea, 0xb0, 0xe4, 0xc5, 0x40, 0xa4, 0xac, + 0xba, 0xad, 0xa4, 0xe1, 0xaa, 0xe1, 0xbc, 0x4d, 0xb5, 0xd8, 0xb7, 0xe2, 0xb7, + 0xc6, 0xb5, 0x65, 0xb9, 0xba, 0xa4, 0xc6, 0xb8, 0xdc, 0xba, 0x69, 0xab, 0xde, + 0xc3, 0x68, 0xb2, 0x61, 0xc3, 0x61, 0xc5, 0x77, 0xc0, 0xf4, 0xae, 0xd9, 0xc1, + 0xd9, 0xbd, 0x77, 0xb4, 0xab, 0xb1, 0x77, 0xb3, 0xea, 0xba, 0xc8, 0xb8, 0xe6, + 0xb7, 0xd8, 0xb5, 0x41, 0xab, 0xc6, 0xa4, 0xdb, 0xaf, 0xee, 0xb7, 0x57, 0xb6, + 0xc0, 0xc1, 0x44, 0xbd, 0xc0, 0xc2, 0xae, 0xac, 0xd3, 0xb0, 0xc4, 0xb4, 0x71, + 0xb7, 0xd7, 0xae, 0xcc, 0xb7, 0x45, 0xab, 0xe9, 0xc1, 0xc0, 0xa6, 0xc7, 0xb4, + 0xa7, 0xbd, 0xf7, 0xc0, 0xb2, 0xab, 0xec, 0xb5, 0xee, 0xa6, 0x5e, 0xb7, 0xb4, + 0xae, 0xac, 0xbc, 0x7a, 0xa5, 0x63, 0xb4, 0x66, 0xb1, 0xe2, 0xb8, 0xec, 0xc2, + 0xa9, 0xb7, 0x7c, 0xc0, 0xed, 0xb6, 0xd7, 0xbf, 0xd0, 0xbb, 0xa3, 0xc3, 0xb8, + 0xb8, 0xa7, 0xa9, 0xfc, 0xb1, 0x42, 0xbb, 0xee, 0xb4, 0xfd, 0xb2, 0x56, 0xc1, + 0xc5, 0xac, 0xa1, 0xa5, 0xeb, 0xa4, 0xf5, 0xc0, 0xf2, 0xa9, 0xce, 0xb4, 0x62, + 0xc0, 0x4e, 0xb3, 0x66, 0xba, 0xd7, 0xc0, 0xbb, 0xa7, 0xa3, 0xb0, 0xf2, 0xbe, + 0xf7, 0xb7, 0xee, 0xbd, 0x5d, 0xbf, 0x6e, 0xba, 0xdf, 0xa6, 0xd9, 0xc4, 0xc8, + 0xb8, 0xf1, 0xbf, 0x45, 0xc3, 0xd5, 0xc2, 0xfb, 0xae, 0x56, 0xc1, 0x5a, 0xbd, + 0x72, 0xa6, 0x4e, 0xb7, 0xa5, 0xb4, 0xc6, 0xbf, 0xe8, 0xc4, 0x79, 0xb6, 0xb0, + 0xa4, 0xce, 0xab, 0xe6, 0xaf, 0x65, 0xa8, 0x56, 0xa7, 0x59, 0xb6, 0xfa, 0xaf, + 0xc5, 0xc0, 0xbd, 0xb4, 0x58, 0xaf, 0xe1, 0xa4, 0x76, 0xc1, 0xaa, 0xa7, 0xde, + 0xbe, 0xac, 0xa9, 0x75, 0xc9, 0xab, 0xb2, 0xbd, 0xbe, 0xaf, 0xb1, 0xaa, 0xc0, + 0xd9, 0xb1, 0x48, 0xb1, 0x49, 0xad, 0x70, 0xb0, 0x4f, 0xac, 0x4a, 0xa7, 0xd2, + 0xbb, 0xda, 0xa7, 0xb2, 0xc4, 0x7e, 0xac, 0xf6, 0xb9, 0xc5, 0xcf, 0x45, 0xa7, + 0xa8, 0xa8, 0xce, 0xae, 0x61, 0xa5, 0x5b, 0xb2, 0xf3, 0xc0, 0x55, 0xb8, 0xeb, + 0xa5, 0xd2, 0xb9, 0x5b, 0xb0, 0xb2, 0xbd, 0x5b, 0xbb, 0xf9, 0xac, 0x5b, 0xbe, + 0x72, 0xb6, 0xf9, 0xc4, 0xe8, 0xba, 0xca, 0xb0, 0xed, 0xa6, 0x79, 0xba, 0xe0, + 0xb6, 0xa1, 0xb7, 0xce, 0xad, 0xdd, 0xaa, 0xd3, 0xc1, 0x7d, 0xab, 0xc1, 0xbd, + 0x70, 0xc3, 0xb5, 0xc0, 0xcb, 0xac, 0x5a, 0xc6, 0x50, 0xc6, 0x50, 0xb4, 0x7a, + 0xbe, 0xdf, 0xc2, 0xb2, 0xbb, 0xfc, 0xb0, 0xc5, 0xb4, 0xee, 0xc2, 0xcb, 0xc2, + 0x65, 0xc5, 0xb3, 0xbd, 0xee, 0xbd, 0xe2, 0xa8, 0xa3, 0xc1, 0xe4, 0xbd, 0x62, + 0xa5, 0xf3, 0xb0, 0xb7, 0xc4, 0xa5, 0xbc, 0x43, 0xc0, 0x5e, 0xba, 0xa5, 0xc2, + 0x71, 0xbc, 0xee, 0xab, 0xd8, 0xbb, 0xf8, 0xab, 0xb8, 0xb1, 0x4e, 0xbc, 0xdf, + 0xa6, 0xbf, 0xc3, 0xa6, 0xbd, 0xb1, 0xbc, 0xd5, 0xbc, 0xfa, 0xc1, 0xbf, 0xa6, + 0x4b, 0xc2, 0xe6, 0xad, 0xb0, 0xbf, 0xbc, 0xb4, 0xd4, 0xc1, 0x47, 0xb5, 0x4a, + 0xbd, 0xa6, 0xa5, 0xe6, 0xad, 0xa5, 0xbc, 0xe5, 0xc5, 0xba, 0xbc, 0x62, 0xc4, + 0x5a, 0xc5, 0xcd, 0xbb, 0xc7, 0xc1, 0x42, 0xb9, 0xae, 0xb8, 0x7d, 0xac, 0xbe, + 0xa8, 0xa4, 0xbb, 0xe5, 0xc3, 0xba, 0xb5, 0xb1, 0xb6, 0xcf, 0xb1, 0xd0, 0xbb, + 0xc3, 0xc3, 0xe2, 0xb8, 0xfb, 0xa5, 0x73, 0xb5, 0xa2, 0xb4, 0xa6, 0xb1, 0xb5, + 0xac, 0xd2, 0xd6, 0xc5, 0xb5, 0xf3, 0xb6, 0xa5, 0xba, 0x49, 0xa7, 0x54, 0xb8, + 0x60, 0xae, 0xdc, 0xb3, 0xc7, 0xb1, 0xb6, 0xb7, 0xfb, 0xba, 0xdc, 0xbc, 0xe4, + 0xb5, 0xb2, 0xb8, 0xd1, 0xa9, 0x6a, 0xa7, 0xd9, 0xc2, 0xc7, 0xaa, 0xe3, 0xac, + 0xc9, 0xad, 0xc9, 0xa4, 0xb6, 0xac, 0xce, 0xbb, 0x7c, 0xa9, 0xa1, 0xa4, 0x79, + 0xb5, 0xac, 0xa4, 0xe7, 0xaa, 0xf7, 0xa4, 0xb5, 0xac, 0x7a, 0xc3, 0xcc, 0xba, + 0xf2, 0xc0, 0x41, 0xb6, 0xc8, 0xc2, 0xd4, 0xb6, 0x69, 0xe0, 0xda, 0xae, 0xca, + 0xb8, 0x54, 0xaa, 0xf1, 0xc2, 0x75, 0xae, 0xfb, 0xba, 0xc9, 0xab, 0x6c, 0xaf, + 0xf0, 0xb9, 0xb8, 0xb2, 0xf4, 0xb7, 0xfa, 0xb4, 0xb9, 0xc4, 0x48, 0xa8, 0xca, + 0xc5, 0xe5, 0xba, 0xeb, 0xb8, 0x65, 0xb8, 0x67, 0xa4, 0xab, 0xc4, 0xb5, 0xb4, + 0xba, 0xc0, 0x56, 0xc0, 0x52, 0xb9, 0xd2, 0xb7, 0x71, 0xc3, 0xe8, 0xae, 0x7c, + 0xb5, 0x6a, 0xb9, 0x74, 0xb3, 0xba, 0xc4, 0x76, 0xd0, 0xe4, 0xac, 0xb3, 0xb5, + 0x7e, 0xb4, 0xaa, 0xa8, 0x73, 0xaa, 0xc8, 0xa8, 0x68, 0xad, 0xb4, 0xa4, 0x5b, + 0xa8, 0x62, 0xa4, 0x45, 0xb0, 0x73, 0xb4, 0x5c, 0xb1, 0xcf, 0xc2, 0xc2, 0xa6, + 0xdd, 0xb8, 0xa4, 0xa9, 0x53, 0xb4, 0x4e, 0xaa, 0xb9, 0xc1, 0xf9, 0xa9, 0xeb, + 0xaa, 0xae, 0xaf, 0x6a, 0xa9, 0x7e, 0xbe, 0x73, 0xb5, 0xe2, 0xa7, 0xbd, 0xa9, + 0x43, 0xaf, 0x78, 0xc1, 0x7c, 0xaa, 0x71, 0xbb, 0x45, 0xa9, 0xda, 0xbe, 0xda, + 0xa5, 0xa8, 0xa8, 0xe3, 0xb6, 0x5a, 0xbd, 0xf5, 0xbf, 0xf7, 0xad, 0xd1, 0xa5, + 0x79, 0xc4, 0xdf, 0xac, 0xb2, 0xbc, 0x40, 0xae, 0xbd, 0xc3, 0x59, 0xae, 0x53, + 0xad, 0xc2, 0xb2, 0xb2, 0xa8, 0xf7, 0xb8, 0x68, 0xe5, 0xb1, 0xc5, 0xcc, 0xa7, + 0xe0, 0xb1, 0xb8, 0xad, 0xcf, 0xc0, 0xef, 0xc4, 0xb1, 0xa8, 0x4d, 0xb3, 0x5a, + 0xb5, 0xb4, 0xa7, 0xa1, 0xb5, 0xdf, 0xb6, 0x76, 0xad, 0x78, 0xa7, 0x67, 0xae, + 0x6d, 0xab, 0x54, 0xb5, 0xa4, 0xc0, 0xe0, 0xb0, 0x70, 0xc2, 0x40, 0xb3, 0xd8, + 0xa9, 0x40, 0xa5, 0x64, 0xab, 0xa3, 0xb6, 0x7d, 0xb4, 0x7b, 0xb7, 0xa2, 0xb3, + 0xcd, 0xb4, 0x6e, 0xa5, 0x5a, 0xb3, 0xf4, 0xb0, 0xc9, 0xa7, 0xa2, 0xac, 0xe5, + 0xac, 0xdd, 0xb1, 0x64, 0xba, 0x42, 0xc1, 0x52, 0xa6, 0xaa, 0xa7, 0xdc, 0xa4, + 0xae, 0xaa, 0xa1, 0xa6, 0xd2, 0xab, 0xfe, 0xaf, 0x4e, 0xbe, 0x61, 0xa9, 0x56, + 0xad, 0x56, 0xac, 0x5f, 0xb4, 0xca, 0xbd, 0x57, 0xc1, 0xfb, 0xac, 0xec, 0xb4, + 0xdf, 0xab, 0x79, 0xa5, 0x69, 0xb4, 0xf7, 0xa7, 0x4a, 0xa8, 0xe8, 0xab, 0xc8, + 0xbd, 0xd2, 0xaa, 0xd6, 0xb0, 0xd9, 0xbe, 0xc1, 0xc0, 0xb5, 0xa7, 0x7c, 0xa7, + 0x5c, 0xaa, 0xc5, 0xae, 0xa3, 0xa4, 0xd5, 0xb1, 0xb1, 0xe1, 0xe0, 0xa4, 0x66, + 0xa6, 0xa9, 0xb1, 0x46, 0xac, 0x5c, 0xad, 0xfa, 0xb8, 0x5d, 0xad, 0x57, 0xbb, + 0xc5, 0xae, 0x77, 0xbf, 0xc7, 0xa6, 0x6a, 0xab, 0xb1, 0xce, 0xd8, 0xb8, 0xf3, + 0xaf, 0xe3, 0xb6, 0xf4, 0xb8, 0x5f, 0xbb, 0xfb, 0xa7, 0xd6, 0xbc, 0x65, 0xb4, + 0xda, 0xa6, 0x4a, 0xb5, 0xa8, 0xa8, 0x67, 0xae, 0xd8, 0xc4, 0x71, 0xb2, 0xb5, + 0xc3, 0x6d, 0xaa, 0x70, 0xc1, 0xab, 0xb2, 0xaf, 0xf5, 0xc9, 0xbf, 0x73, 0xb8, + 0xaa, 0xab, 0xb6, 0xbb, 0xed, 0xb3, 0xc8, 0xf5, 0x58, 0xb7, 0x5c, 0xbc, 0xec, + 0xa9, 0x5b, 0xa9, 0xf8, 0xae, 0xb9, 0xa7, 0x78, 0xac, 0x41, 0xc2, 0x58, 0xb9, + 0xf8, 0xc1, 0xef, 0xa9, 0x55, 0xa9, 0xd4, 0xb3, 0xe2, 0xc4, 0xfa, 0xc3, 0xbe, + 0xbb, 0xb6, 0xb0, 0xd5, 0xb5, 0xdc, 0xa8, 0xd3, 0xbf, 0xe0, 0xc2, 0xc5, 0xb0, + 0xfd, 0xc4, 0xe6, 0xc4, 0x64, 0xc4, 0x78, 0xc1, 0xf1, 0xc4, 0xf5, 0xc4, 0x69, + 0xf8, 0xc2, 0xc5, 0xf3, 0xc4, 0xfd, 0xc3, 0x69, 0xc6, 0x6c, 0xc4, 0xea, 0xc0, + 0xdd, 0xb2, 0x77, 0xb7, 0x7d, 0xaf, 0x54, 0xb4, 0x59, 0xad, 0xa6, 0xae, 0xd4, + 0xae, 0xf6, 0xbc, 0xb4, 0xb3, 0xd2, 0xa8, 0x63, 0xa6, 0xd1, 0xa8, 0xd0, 0xab, + 0xbe, 0xb9, 0x54, 0xaf, 0x4f, 0xe5, 0xfc, 0xb0, 0xc7, 0xbc, 0xd6, 0xb9, 0x70, + 0xc5, 0x4a, 0xc1, 0xa2, 0xbd, 0x55, 0xb2, 0xd6, 0xc0, 0x77, 0xc2, 0x53, 0xbe, + 0xdd, 0xa6, 0xd8, 0xc3, 0xfe, 0xb2, 0x5c, 0xd9, 0xb1, 0xb7, 0xab, 0xa7, 0x4e, + 0xcd, 0xf9, 0xb1, 0xf9, 0xb2, 0x70, 0xbe, 0xa4, 0xc6, 0x58, 0xbb, 0xa9, 0xc2, + 0xf7, 0xba, 0x76, 0xb2, 0x7a, 0xa7, 0xf5, 0xb8, 0xcc, 0xc3, 0x55, 0xc2, 0xa7, + 0xb2, 0xfa, 0xaf, 0xef, 0xa6, 0x4f, 0xae, 0xdf, 0xc4, 0x52, 0xbc, 0x46, 0xc0, + 0x79, 0xc4, 0x74, 0xbe, 0xfa, 0xa7, 0x51, 0xe0, 0xf4, 0xa8, 0xd2, 0xab, 0x57, + 0xb5, 0x67, 0xa5, 0xdf, 0xb2, 0xc9, 0xc3, 0x77, 0xc1, 0xf5, 0xa4, 0x4f, 0xbc, + 0xfe, 0xad, 0xf9, 0xad, 0xc7, 0xc1, 0x70, 0xbd, 0xac, 0xb3, 0x73, 0xc5, 0x49, + 0xb7, 0x47, 0xbc, 0xa6, 0xba, 0xa7, 0xc3, 0xae, 0xc0, 0xc4, 0xc1, 0x79, 0xc3, + 0xec, 0xc5, 0xca, 0xb7, 0xd2, 0xbd, 0x6d, 0xc2, 0xb3, 0xb2, 0x44, 0xbc, 0xd9, + 0xb8, 0x64, 0xa8, 0x7d, 0xa8, 0xe2, 0xbd, 0xf8, 0xb6, 0x71, 0xb4, 0xbd, 0xab, + 0x47, 0xbd, 0xcc, 0xbc, 0xba, 0xb2, 0xe1, 0xb9, 0xb1, 0xc0, 0xf8, 0xbf, 0x52, + 0xb9, 0xe9, 0xbf, 0xf1, 0xbc, 0xe3, 0xa4, 0x46, 0xe1, 0xe6, 0xf4, 0xef, 0xb9, + 0xf9, 0xae, 0xc6, 0xa6, 0x43, 0xb5, 0xf5, 0xaf, 0x50, 0xa6, 0x48, 0xc2, 0x79, + 0xb5, 0x59, 0xaa, 0x4c, 0xc1, 0x43, 0xc0, 0x4d, 0xc1, 0x7b, 0xbe, 0x46, 0xc5, + 0xec, 0xb2, 0x4f, 0xbb, 0xfe, 0xb8, 0xee, 0xa7, 0x5b, 0xa9, 0xf0, 0xac, 0xc2, + 0xb5, 0xd9, 0xb9, 0x73, 0xc4, 0xd6, 0xb9, 0x61, 0xa7, 0x44, 0xb2, 0xdc, 0xad, + 0xe2, 0xc6, 0x46, 0xb3, 0xae, 0xc0, 0xad, 0xbb, 0xe2, 0xa5, 0x74, 0xa5, 0x4f, + 0xb7, 0xc8, 0xaf, 0x5b, 0xba, 0x68, 0xb2, 0xb8, 0xc3, 0x48, 0xaf, 0x64, 0xbc, + 0x42, 0xbd, 0x46, 0xac, 0x79, 0xac, 0x68, 0xa4, 0xbb, 0xc0, 0x73, 0xc5, 0xa4, + 0xc4, 0x56, 0xc5, 0xa2, 0xc1, 0x4b, 0xb6, 0xa9, 0xc3, 0x62, 0xc3, 0x6c, 0xc3, + 0xf7, 0xbc, 0xd3, 0xb0, 0xfa, 0xba, 0x4f, 0xc1, 0x4d, 0xba, 0x7c, 0xad, 0xae, + 0xc4, 0xaa, 0xbf, 0x63, 0xc6, 0x60, 0xc3, 0x66, 0xc4, 0x6c, 0xbe, 0xdb, 0xb3, + 0xbf, 0xb8, 0xb8, 0xbe, 0x7c, 0xc4, 0x53, 0xb8, 0x4c, 0xc5, 0x53, 0xb8, 0xf4, + 0xb8, 0xef, 0xb3, 0xc0, 0xe9, 0xf0, 0xb8, 0x53, 0xbf, 0xfd, 0xb3, 0xb0, 0xbc, + 0xae, 0xc6, 0x6a, 0xa7, 0x66, 0xbe, 0x54, 0xab, 0x51, 0xae, 0xc8, 0xbc, 0x69, + 0xb9, 0xf0, 0xc1, 0x5c, 0xbc, 0x7b, 0xb4, 0xe2, 0xab, 0xdf, 0xb2, 0x76, 0xc2, + 0x6f, 0xba, 0xf1, 0xc5, 0x72, 0xc5, 0xcb, 0xc5, 0x70, 0xc6, 0x65, 0xa7, 0x5a, + 0xb6, 0xc3, 0xb1, 0xb0, 0xb2, 0xa4, 0xb1, 0xc1, 0xbd, 0xfc, 0xad, 0xdb, 0xa8, + 0xda, 0xb2, 0x5f, 0xba, 0xfa, 0xbd, 0xd7, 0xc5, 0xda, 0xc1, 0xb3, 0xc3, 0xb9, + 0xc5, 0xde, 0xc6, 0x72, 0xc6, 0x59, 0xc5, 0x5b, 0xbb, 0x72, 0xb8, 0xa8, 0xac, + 0xa5, 0xc0, 0x64, 0xb5, 0xb8, 0xb6, 0xfd, 0xb3, 0xc2, 0xba, 0xbf, 0xbd, 0x58, + 0xbf, 0xc2, 0xb0, 0xa8, 0xbd, 0x7c, 0xb9, 0xc0, 0xb6, 0xdc, 0xae, 0x49, 0xb6, + 0x52, 0xb3, 0xc1, 0xbd, 0xe6, 0xc1, 0xda, 0xaf, 0xdf, 0xbf, 0x66, 0xc4, 0x43, + 0xc6, 0x5a, 0xba, 0xa1, 0xbd, 0xaf, 0xb0, 0xd2, 0xba, 0x43, 0xba, 0xa9, 0xf0, + 0xe3, 0xa8, 0x7e, 0xaf, 0xed, 0xaa, 0xbc, 0xaa, 0x5d, 0xa6, 0xa3, 0xb2, 0xf5, + 0xbf, 0xdf, 0xad, 0x54, 0xc1, 0xe3, 0xa4, 0xf2, 0xa5, 0xd9, 0xb9, 0x67, 0xa5, + 0x66, 0xad, 0x5a, 0xab, 0x5f, 0xb4, 0x55, 0xbb, 0xaa, 0xb6, 0x54, 0xbb, 0xf2, + 0xaa, 0xb4, 0xaa, 0x54, 0xb1, 0xf6, 0xa1, 0xbc, 0xbe, 0x60, 0xb7, 0xd1, 0xa8, + 0x53, 0xac, 0xdc, 0xb4, 0x43, 0xc1, 0xe2, 0xa8, 0x43, 0xac, 0xfc, 0xac, 0x4e, + 0xb4, 0x4b, 0xa9, 0x66, 0xb4, 0x41, 0xaa, 0xf9, 0xb4, 0x65, 0xad, 0xcc, 0xb5, + 0xde, 0xbb, 0x58, 0xc2, 0x63, 0xb7, 0xf9, 0xbf, 0xf8, 0xb2, 0x72, 0xb9, 0xda, + 0xa9, 0x73, 0xd6, 0xa9, 0xee, 0xc5, 0xc3, 0xfb, 0xc1, 0x53, 0xb0, 0x67, 0xc1, + 0xbc, 0xc0, 0xb1, 0xa6, 0xcc, 0xaf, 0xb5, 0xb3, 0x56, 0xaa, 0x63, 0xbb, 0x65, + 0xb1, 0x4b, 0xbe, 0xad, 0xb4, 0xd6, 0xaf, 0x76, 0xba, 0xf8, 0xb0, 0xc3, 0xa7, + 0x4b, 0xab, 0x6a, 0xae, 0x59, 0xbd, 0x71, 0xad, 0xb1, 0xad, 0x5d, 0xb4, 0x79, + 0xba, 0xcb, 0xc2, 0xc6, 0xac, 0xed, 0xb4, 0xf9, 0xbc, 0x71, 0xa7, 0xae, 0xbd, + 0xb0, 0xb7, 0xc0, 0xa5, 0xc1, 0xa9, 0xd7, 0xa5, 0xd7, 0xb1, 0xd3, 0xbc, 0xa7, + 0xbb, 0xd4, 0xa9, 0xfa, 0xbf, 0xc1, 0xbb, 0xef, 0xbb, 0xca, 0xa6, 0x57, 0xa9, + 0x52, 0xc2, 0xd5, 0xba, 0x4e, 0xbc, 0xb1, 0xc4, 0xa8, 0xbc, 0xd2, 0xbd, 0xa4, + 0xbf, 0x69, 0xbc, 0xaf, 0xc5, 0x5d, 0xa9, 0xd9, 0xa5, 0xbd, 0xb2, 0xf6, 0xbe, + 0xa5, 0xc0, 0x71, 0xaa, 0x6a, 0xba, 0x7a, 0xb9, 0xe6, 0xad, 0xaf, 0xbf, 0xd1, + 0xa6, 0xc8, 0xac, 0x59, 0xa9, 0xe6, 0xa8, 0x64, 0xaf, 0x61, 0xa9, 0x69, 0xa5, + 0xc0, 0xb9, 0xd3, 0xbc, 0xc7, 0xb9, 0xf5, 0xb6, 0xd2, 0xbc, 0x7d, 0xa4, 0xec, + 0xa5, 0xd8, 0xb7, 0xfc, 0xaa, 0xaa, 0xbf, 0x70, 0xae, 0xb3, 0xad, 0xfe, 0xa7, + 0x6f, 0xb6, 0x75, 0xa8, 0xba, 0xae, 0x52, 0xaf, 0xc7, 0xa6, 0xbb, 0xa4, 0x44, + 0xa5, 0xa4, 0xad, 0x40, 0xa9, 0x60, 0xab, 0x6e, 0xa8, 0x6b, 0xc3, 0xf8, 0xc5, + 0x6e, 0xbc, 0xb8, 0xb8, 0xa3, 0xb4, 0x6f, 0xbe, 0x78, 0xd5, 0xef, 0xa9, 0x4f, + 0xbe, 0x6b, 0xa4, 0xba, 0xb9, 0xe0, 0xaf, 0xe0, 0xa9, 0x67, 0xc0, 0x4f, 0xad, + 0xd9, 0xaa, 0x64, 0xa5, 0xa7, 0xc0, 0xc0, 0xa7, 0x41, 0xb0, 0xce, 0xbf, 0xb0, + 0xb0, 0x66, 0xb7, 0xc4, 0xe7, 0x59, 0xa9, 0xe0, 0xa6, 0x7e, 0xbd, 0x56, 0xc2, + 0x5b, 0xb1, 0xc9, 0xa9, 0xc0, 0xae, 0x51, 0xc6, 0x43, 0xb3, 0xbe, 0xa7, 0xbf, + 0xae, 0xba, 0xc2, 0xbf, 0xc4, 0x5e, 0xef, 0xbf, 0xc6, 0x68, 0xc2, 0xec, 0xaf, + 0x49, 0xb1, 0x7a, 0xc2, 0x66, 0xc0, 0xf1, 0xbe, 0xae, 0xb9, 0xe7, 0xc0, 0xbe, + 0xc0, 0xd7, 0xa4, 0xfb, 0xa7, 0xe1, 0xb6, 0x73, 0xaf, 0xc3, 0xc1, 0x77, 0xbf, + 0x40, 0xb9, 0x41, 0xa7, 0xcb, 0xa5, 0xa3, 0xa7, 0x56, 0xab, 0xe3, 0xa4, 0x6b, + 0xb7, 0x78, 0xad, 0x68, 0xba, 0xc4, 0xae, 0xbf, 0xc0, 0xb6, 0xc4, 0x7a, 0xbf, + 0xd5, 0xae, 0x40, 0xbc, 0xda, 0xc5, 0xc3, 0xbc, 0xde, 0xc3, 0xc2, 0xb9, 0xc3, + 0xb0, 0xb8, 0xe2, 0x78, 0xb0, 0xd4, 0xad, 0x77, 0xaa, 0xa6, 0xa9, 0xac, 0xa9, + 0xc8, 0xb5, 0x5d, 0xa9, 0xe7, 0xb1, 0xc6, 0xb5, 0x50, 0xb1, 0x72, 0xb4, 0xfb, + 0xac, 0xa3, 0xc3, 0x6b, 0xbc, 0xef, 0xbd, 0x4c, 0xbd, 0x59, 0xac, 0xdf, 0xaf, + 0x60, 0xa7, 0x50, 0xab, 0x71, 0xa5, 0xe3, 0xc3, 0x65, 0xae, 0xc7, 0xea, 0xe5, + 0xad, 0x44, 0xa9, 0xdf, 0xa9, 0x48, 0xa7, 0x53, 0xac, 0xb6, 0xb3, 0x54, 0xb6, + 0x5d, 0xaa, 0x77, 0xa9, 0x41, 0xad, 0x46, 0xb0, 0xf6, 0xbb, 0x70, 0xbd, 0xdf, + 0xb3, 0xad, 0xb0, 0x74, 0xa8, 0xd8, 0xa8, 0x4b, 0xbc, 0x51, 0xac, 0xd6, 0xaf, + 0x79, 0xa9, 0xe1, 0xb2, 0x69, 0xbc, 0xea, 0xb4, 0x5e, 0xbd, 0xb4, 0xb4, 0xd7, + 0xb8, 0x4e, 0xc1, 0x4f, 0xbf, 0xb1, 0xaa, 0x42, 0xc4, 0x50, 0xb1, 0xb7, 0xb8, + 0x49, 0xcb, 0xf2, 0xcf, 0xec, 0xc5, 0x52, 0xa7, 0xe5, 0xa9, 0xdc, 0xbc, 0x41, + 0xb5, 0x5c, 0xac, 0x73, 0xb0, 0xe0, 0xb5, 0xca, 0xaf, 0x68, 0xa5, 0xd6, 0xa4, + 0xc7, 0xb5, 0x6c, 0xbb, 0xf7, 0xa7, 0xbe, 0xc4, 0xb4, 0xbd, 0x67, 0xb0, 0xbe, + 0xa4, 0xf9, 0xc4, 0x46, 0xc4, 0xc6, 0xba, 0x7d, 0xbf, 0x5d, 0xb2, 0xbc, 0xba, + 0x4a, 0xbf, 0x68, 0xab, 0xf7, 0xc0, 0x57, 0xb3, 0x68, 0xab, 0x7e, 0xb8, 0x75, + 0xa5, 0xe2, 0xa9, 0x57, 0xc4, 0xab, 0xb5, 0xd3, 0xa5, 0xad, 0xbe, 0xcc, 0xb2, + 0x7e, 0xb5, 0xfb, 0xab, 0xcc, 0xa9, 0x59, 0xbc, 0xe2, 0xbb, 0xe1, 0xb1, 0x43, + 0xaf, 0x7d, 0xbe, 0x7a, 0xad, 0xa2, 0xb2, 0xcb, 0xad, 0xe5, 0xbc, 0xb3, 0xe7, + 0x45, 0xb9, 0xb2, 0xb3, 0x40, 0xb8, 0xb2, 0xb5, 0xd0, 0xbb, 0x5a, 0xae, 0x48, + 0xbe, 0xeb, 0xae, 0x45, 0xb4, 0xb6, 0xae, 0xfa, 0xc3, 0xd0, 0xc3, 0x6e, 0xc2, + 0x72, 0xb4, 0xc1, 0xb4, 0xdb, 0xb4, 0xcf, 0xb1, 0xad, 0xa9, 0x64, 0xa4, 0x43, + 0xd0, 0xe2, 0xba, 0xa3, 0xac, 0x6d, 0xcb, 0x50, 0xa8, 0xe4, 0xb4, 0xd1, 0xa9, + 0x5f, 0xaa, 0x5b, 0xb2, 0xa5, 0xb1, 0x54, 0xc2, 0xc0, 0xbb, 0xf4, 0xba, 0x58, + 0xac, 0xe8, 0xaa, 0xc2, 0xc3, 0x4d, 0xb0, 0x5f, 0xb0, 0x5a, 0xa4, 0x5e, 0xa5, + 0xf8, 0xb1, 0xd2, 0xab, 0xb4, 0xac, 0xe4, 0xbe, 0xb9, 0xae, 0xf0, 0xa8, 0xb4, + 0xb1, 0xf3, 0xa8, 0x54, 0xaa, 0x5f, 0xb0, 0x57, 0xd5, 0x74, 0xab, 0xea, 0xac, + 0xa2, 0xb2, 0x6f, 0xc9, 0xe7, 0xa1, 0xbc, 0xb9, 0x5d, 0xa4, 0x64, 0xbe, 0x45, + 0xc3, 0xb1, 0xa5, 0x61, 0xc1, 0xbe, 0xb0, 0xae, 0xc0, 0x72, 0xbf, 0xfa, 0xb9, + 0x58, 0xab, 0x65, 0xbc, 0xe7, 0xbb, 0xba, 0xb2, 0x4c, 0xc4, 0xfe, 0xb9, 0xd5, + 0xb4, 0x4f, 0xa4, 0xed, 0xba, 0x70, 0xba, 0x6a, 0xb6, 0xe6, 0xb5, 0xc4, 0xaa, + 0xca, 0xc0, 0xf0, 0xc1, 0xa5, 0xb1, 0x6a, 0xb7, 0x6d, 0xbe, 0xf5, 0xc1, 0xea, + 0xba, 0x56, 0xae, 0xa8, 0xbe, 0xf4, 0xc1, 0x40, 0xb3, 0xec, 0xb9, 0xb4, 0xa5, + 0xa9, 0xc0, 0x54, 0xbc, 0xc0, 0xc2, 0xbc, 0xae, 0x6b, 0xab, 0x4e, 0xc2, 0xac, + 0xa4, 0xc1, 0xad, 0x58, 0xa5, 0x42, 0xa9, 0xc4, 0xc5, 0xd1, 0xb4, 0xdc, 0xab, + 0x49, 0xbf, 0xcb, 0xaf, 0xb3, 0xb5, 0x5e, 0xb6, 0xd4, 0xaa, 0xe0, 0xbe, 0xe0, + 0xb8, 0x56, 0xb9, 0xec, 0xa8, 0x47, 0xab, 0x43, 0xbb, 0xb4, 0xb2, 0x42, 0xb6, + 0xc9, 0xad, 0xeb, 0xb2, 0x4d, 0xc0, 0xba, 0xb4, 0xb8, 0xd9, 0xe6, 0xb1, 0xa1, + 0xb3, 0xbc, 0xbd, 0xd0, 0xbc, 0x79, 0xc3, 0xa3, 0xbd, 0x61, 0xac, 0xee, 0xa5, + 0x43, 0xaa, 0xf4, 0xb2, 0x79, 0xa8, 0x44, 0xa5, 0x7d, 0xad, 0xa9, 0xaa, 0x73, + 0xc1, 0xcd, 0xb0, 0xcf, 0xb3, 0x49, 0xa6, 0xb1, 0xc2, 0xdf, 0xa9, 0x7d, 0xc5, + 0x58, 0xb4, 0xeb, 0xa8, 0xfa, 0xb0, 0xf9, 0xc6, 0x54, 0xbd, 0xec, 0xa5, 0x68, + 0xb0, 0xe9, 0xf9, 0xaf, 0xc5, 0x76, 0xee, 0xc7, 0xac, 0x75, 0xa5, 0xfe, 0xb2, + 0xac, 0xae, 0xb1, 0xa4, 0xfc, 0xa8, 0xe9, 0xc4, 0x55, 0xaf, 0xca, 0xcd, 0x50, + 0xbf, 0x61, 0xab, 0x6f, 0xc4, 0x4e, 0xba, 0x65, 0xbd, 0x54, 0xb3, 0xb6, 0xb8, + 0xc8, 0xb8, 0x73, 0xb5, 0x4d, 0xbf, 0x55, 0xa5, 0x54, 0xac, 0x56, 0xc5, 0x7b, + 0xc4, 0x5b, 0xc4, 0x63, 0xc4, 0x57, 0xc5, 0xfd, 0xc4, 0xc7, 0xc2, 0x5a, 0xc2, + 0xb6, 0xb7, 0x53, 0xbc, 0xf6, 0xa4, 0xd0, 0xa4, 0xaf, 0xa4, 0x48, 0xa7, 0xd4, + 0xb6, 0xb4, 0xa5, 0xf4, 0xbb, 0x7b, 0xa4, 0x62, 0xa7, 0xb3, 0xac, 0xf7, 0xa5, + 0xb5, 0xa4, 0xb4, 0xa4, 0xe9, 0xa6, 0xa5, 0xaf, 0xf1, 0xbb, 0x54, 0xba, 0x61, + 0xbf, 0xc4, 0xba, 0xb2, 0xb7, 0xbb, 0xae, 0x65, 0xb5, 0xb3, 0xa4, 0xbe, 0xb4, + 0x7c, 0xac, 0x58, 0xa6, 0xd7, 0xaf, 0xf8, 0xc4, 0xaf, 0xbe, 0xa7, 0xc0, 0xa9, + 0xa6, 0x70, 0xb0, 0x64, 0xa8, 0xc5, 0xa6, 0xbc, 0xa4, 0x4a, 0xbf, 0xc8, 0xb3, + 0x6e, 0xa8, 0xbf, 0xbf, 0xb6, 0xb7, 0xe7, 0xbe, 0x55, 0xb6, 0x7c, 0xbc, 0xed, + 0xad, 0x59, 0xae, 0x7a, 0xbc, 0xbb, 0xcf, 0x73, 0xc2, 0xc4, 0xb8, 0x7c, 0xc4, + 0xce, 0xb6, 0xeb, 0xc1, 0xc9, 0xa4, 0x54, 0xa4, 0x54, 0xb3, 0xca, 0xb4, 0xb2, + 0xae, 0xe1, 0xb6, 0xda, 0xb3, 0xe0, 0xb7, 0x6b, 0xc4, 0xcc, 0xb1, 0xbd, 0xb7, + 0x41, 0xb7, 0xe6, 0xa6, 0xe2, 0xc0, 0xdf, 0xb4, 0xcb, 0xb9, 0xac, 0xb2, 0xef, + 0xac, 0xe2, 0xb1, 0xfe, 0xab, 0x62, 0xa8, 0x46, 0xaf, 0xbd, 0xb6, 0xcc, 0xd4, + 0xa3, 0xb7, 0xd9, 0xbf, 0x7a, 0xc5, 0xce, 0xac, 0xc0, 0xd0, 0x73, 0xa7, 0xfc, + 0xa4, 0x73, 0xa7, 0x52, 0xba, 0xb4, 0xad, 0x6d, 0xb0, 0x7b, 0xb0, 0xa2, 0xbe, + 0xd5, 0xc4, 0xba, 0xbf, 0xaf, 0xb5, 0xbd, 0xa6, 0xc2, 0xae, 0xb0, 0xc2, 0xb5, + 0xe1, 0x61, 0xb6, 0xcb, 0xb0, 0xd3, 0xbd, 0xe0, 0xae, 0xce, 0xa4, 0x57, 0xa9, + 0x7c, 0xbb, 0x6e, 0xb1, 0xe9, 0xae, 0xb4, 0xb5, 0x79, 0xbf, 0x4e, 0xa8, 0xa2, + 0xa4, 0x63, 0xbb, 0xe0, 0xa4, 0xd6, 0xad, 0xef, 0xaa, 0xf2, 0xb2, 0xd0, 0xb0, + 0xf8, 0xbb, 0xad, 0xb3, 0x44, 0xa6, 0xde, 0xaa, 0xd9, 0xb3, 0x6a, 0xc4, 0xe1, + 0xae, 0x67, 0xc4, 0xe0, 0xaf, 0x41, 0xaa, 0xc0, 0xb3, 0x5d, 0xaf, 0x7e, 0xa5, + 0xd3, 0xa9, 0x44, 0xa6, 0xf9, 0xa8, 0xad, 0xb2, 0x60, 0xae, 0x57, 0xb2, 0xd4, + 0xaf, 0xab, 0xa8, 0x48, 0xbc, 0x66, 0xc2, 0x54, 0xac, 0xc6, 0xb5, 0xc7, 0xb7, + 0x56, 0xba, 0xaf, 0xc1, 0x6e, 0xa5, 0xcd, 0xb5, 0x63, 0xac, 0xb9, 0xa4, 0xc9, + 0xc3, 0xb7, 0xac, 0xd9, 0xb2, 0xb1, 0xb3, 0xd1, 0xb3, 0xd3, 0xb8, 0x74, 0xae, + 0x76, 0xa5, 0xa2, 0xb7, 0xe0, 0xac, 0x49, 0xc0, 0xe3, 0xb8, 0xd6, 0xab, 0xcd, + 0xbd, 0xbe, 0xa4, 0x51, 0xa5, 0xdb, 0xac, 0x42, 0xae, 0xc9, 0xa4, 0xb0, 0xad, + 0xb9, 0xbb, 0x6b, 0xb9, 0xea, 0xc3, 0xd1, 0xa5, 0x76, 0xa5, 0xda, 0xa8, 0xcf, + 0xab, 0xcb, 0xbe, 0x70, 0xa9, 0x6c, 0xa6, 0xa1, 0xa5, 0xdc, 0xa4, 0x68, 0xa5, + 0x40, 0xac, 0x55, 0xa8, 0xc6, 0xab, 0xf8, 0xbb, 0x7d, 0xb3, 0x75, 0xb6, 0xd5, + 0xac, 0x4f, 0xb6, 0xdd, 0xbe, 0xbd, 0xbe, 0x41, 0xa5, 0x4b, 0xa8, 0xcd, 0xc4, + 0xc0, 0xb9, 0xa2, 0xa4, 0xf3, 0xa5, 0xab, 0xab, 0xee, 0xab, 0xc7, 0xb5, 0xf8, + 0xb8, 0xd5, 0xa6, 0xac, 0xa4, 0xe2, 0xad, 0xba, 0xa6, 0x75, 0xb9, 0xd8, 0xb1, + 0xc2, 0xb0, 0xe2, 0xa8, 0xfc, 0xbd, 0x47, 0xc3, 0x7e, 0xbd, 0xad, 0xbc, 0xcf, + 0xae, 0xde, 0xae, 0xed, 0xa7, 0xe7, 0xbf, 0xe9, 0xa8, 0xfb, 0xb5, 0xce, 0xb2, + 0x51, 0xb2, 0xa8, 0xae, 0xd1, 0xc5, 0xab, 0xb1, 0x45, 0xbc, 0xf4, 0xc1, 0xa6, + 0xb4, 0xbb, 0xc0, 0xc6, 0xb8, 0x70, 0xb8, 0xbe, 0xb6, 0xc1, 0xb9, 0xab, 0xc4, + 0xdd, 0xb3, 0x4e, 0xad, 0x7a, 0xbe, 0xf0, 0xa7, 0xf4, 0xa6, 0xa7, 0xbd, 0xdd, + 0xb9, 0xd6, 0xb1, 0x66, 0xbc, 0xc6, 0xba, 0xa4, 0xae, 0xa4, 0xa8, 0xea, 0xad, + 0x41, 0xba, 0x4c, 0xb0, 0x49, 0xa5, 0xcf, 0xab, 0xd3, 0xae, 0xea, 0xac, 0x43, + 0xc1, 0xf7, 0xc2, 0xf9, 0xb2, 0x6e, 0xbd, 0xd6, 0xa4, 0xf4, 0xba, 0xce, 0xb5, + 0x7c, 0xa7, 0x6d, 0xc0, 0xfe, 0xb6, 0xb6, 0xb5, 0xcf, 0xbb, 0xa1, 0xba, 0xd3, + 0xae, 0xd2, 0xc3, 0x7b, 0xb4, 0xb5, 0xbc, 0xb9, 0xbc, 0x52, 0xab, 0xe4, 0xa8, + 0x70, 0xa5, 0x71, 0xb5, 0xb7, 0xa6, 0xba, 0xb8, 0x76, 0xa6, 0x78, 0xb6, 0xe0, + 0xa5, 0x7c, 0xa6, 0xf8, 0xa6, 0xfc, 0xb9, 0x7d, 0xa4, 0x78, 0xc3, 0x50, 0xc1, + 0x71, 0xbc, 0xa3, 0xb9, 0x7c, 0xb0, 0x65, 0xa7, 0xba, 0xb3, 0x5e, 0xbb, 0x77, + 0xb7, 0x6a, 0xbf, 0xb4, 0xc2, 0x5d, 0xb9, 0xc2, 0xc4, 0xac, 0xb6, 0x70, 0xab, + 0x55, 0xaf, 0xc0, 0xb3, 0x74, 0xb5, 0xaf, 0xe0, 0xf4, 0xb6, 0xec, 0xb7, 0xb9, + 0xb1, 0x4a, 0xb6, 0x44, 0xb5, 0xc2, 0xbb, 0xc4, 0xbb, 0x5b, 0xba, 0xe2, 0xc1, + 0xf6, 0xb6, 0xa6, 0xc0, 0x48, 0xb8, 0x6b, 0xc5, 0xe8, 0xb8, 0x48, 0xb7, 0xb3, + 0xc1, 0x4a, 0xb9, 0x45, 0xc0, 0x47, 0xaf, 0xa9, 0xae, 0x5d, 0xb7, 0x6c, 0xb5, + 0xab, 0xbb, 0x62, 0xb1, 0xf4, 0xad, 0xf6, 0xc1, 0x59, 0xba, 0xbe, 0xaf, 0xc1, + 0xc2, 0xea, 0xa9, 0xd2, 0xb6, 0xf2, 0xa5, 0x4c, 0xa5, 0xa6, 0xa6, 0x6f, 0xb6, + 0xf0, 0xc3, 0xa1, 0xbe, 0xd8, 0xc1, 0xcf, 0xbd, 0xf1, 0xad, 0x4c, 0xad, 0x61, + 0xa9, 0xef, 0xa5, 0x78, 0xae, 0xf5, 0xa1, 0xbc, 0xa4, 0xd3, 0xba, 0x41, 0xa8, + 0x4f, 0xa7, 0x7e, 0xc5, 0x75, 0xb3, 0x67, 0xc5, 0xf5, 0xc5, 0x79, 0xbe, 0xc2, + 0xc0, 0xc8, 0xb7, 0xf0, 0xbc, 0xe6, 0xc3, 0xd3, 0xbd, 0xcd, 0xa9, 0x5a, 0xb4, + 0xe0, 0xb3, 0x52, 0xba, 0xd2, 0xb1, 0xb4, 0xb9, 0xc4, 0xac, 0xb4, 0xb4, 0xf6, + 0xb6, 0xed, 0xb7, 0x65, 0xb0, 0xf3, 0xb4, 0xc5, 0xbd, 0xa3, 0xad, 0xf0, 0xbf, + 0x7d, 0xad, 0xd5, 0xbd, 0xf6, 0xb2, 0x49, 0xbd, 0xeb, 0xbf, 0x53, 0xb1, 0xc7, + 0xc0, 0xdc, 0xb7, 0xca, 0xb8, 0x6c, 0xb5, 0xe5, 0xae, 0xe7, 0xb0, 0x6b, 0xb2, + 0x5e, 0xb3, 0xb3, 0xb0, 0x51, 0xae, 0x4d, 0xaf, 0x53, 0xc4, 0xf0, 0xc4, 0xcb, + 0xaf, 0x6b, 0xc1, 0xc3, 0xb1, 0xe8, 0xad, 0xe7, 0xbd, 0xf0, 0xbe, 0x4f, 0xb4, + 0xa3, 0xc3, 0x44, 0xbf, 0xe1, 0xb3, 0xda, 0xc5, 0xe9, 0xb4, 0xc0, 0xc0, 0xa1, + 0xb1, 0xa7, 0xae, 0xf7, 0xab, 0x63, 0xb1, 0x50, 0xa4, 0xd1, 0xb2, 0x4b, 0xb6, + 0xf1, 0xa5, 0xd0, 0xb2, 0xa2, 0xab, 0xef, 0xbb, 0x51, 0xb5, 0xc9, 0xac, 0x44, + 0xb1, 0xf8, 0xad, 0x7c, 0xb2, 0xb7, 0xb8, 0xf5, 0xb6, 0x4b, 0xc5, 0x4b, 0xa9, + 0xab, 0xc6, 0x55, 0xc5, 0xa5, 0xd6, 0x4c, 0xa5, 0xc5, 0xa7, 0xca, 0xb0, 0xb1, + 0xab, 0x46, 0xae, 0x78, 0xae, 0xbc, 0xb8, 0xa5, 0xb3, 0x71, 0xae, 0xe4, 0xe0, + 0xac, 0xc0, 0xfb, 0xa6, 0x50, 0xbb, 0xc9, 0xa7, 0xcd, 0xb5, 0xa3, 0xb1, 0xed, + 0xd1, 0xb6, 0xb5, 0xa9, 0xb2, 0xce, 0xb5, 0x68, 0xb0, 0xbd, 0xa7, 0xeb, 0xc0, + 0x59, 0xb3, 0x7a, 0xa5, 0x59, 0xa8, 0x72, 0xac, 0xf0, 0xb9, 0xcf, 0xae, 0x7b, + 0xb3, 0x7e, 0xb6, 0xee, 0xb1, 0x4f, 0xa4, 0x67, 0xa6, 0x52, 0xa8, 0xdf, 0xb4, + 0xf8, 0xb9, 0xce, 0xb1, 0xc0, 0xc0, 0x5a, 0xbb, 0x4c, 0xb8, 0xc0, 0xbf, 0xc6, + 0xb0, 0x68, 0xa7, 0x5d, 0xa4, 0xd9, 0xc1, 0x76, 0xa9, 0xec, 0xa6, 0xab, 0xb2, + 0xe6, 0xc0, 0x6b, 0xaa, 0xfb, 0xb9, 0xa4, 0xbe, 0x6d, 0xbe, 0xf2, 0xa7, 0xb4, + 0xa9, 0xdd, 0xb3, 0xe8, 0xab, 0xf5, 0xab, 0x7a, 0xb5, 0xec, 0xba, 0xda, 0xab, + 0xbd, 0xa5, 0xcb, 0xc4, 0xfb, 0xac, 0x6e, 0xa5, 0x7e, 0xbd, 0xdc, 0xc5, 0x73, + 0xc6, 0x57, 0xaa, 0xb1, 0xb9, 0x78, 0xa4, 0x59, 0xd6, 0x4a, 0xa7, 0xb9, 0xb8, + 0x4a, 0xae, 0xbe, 0xb1, 0xdf, 0xb5, 0x70, 0xb1, 0x7b, 0xa9, 0x7b, 0xb0, 0xfb, + 0xb8, 0x55, 0xb5, 0xc3, 0xa8, 0x4c, 0xa4, 0xfd, 0xa4, 0x60, 0xaa, 0x50, 0xba, + 0xf4, 0xa9, 0xb9, 0xa9, 0xf4, 0xb1, 0xe6, 0xa7, 0xd1, 0xa6, 0x6b, 0xab, 0xc2, + 0xc4, 0xde, 0xb7, 0x4c, 0xa6, 0x4d, 0xad, 0xb3, 0xb9, 0x48, 0xae, 0xe9, 0xb3, + 0xf2, 0xb0, 0xdf, 0xb1, 0xa9, 0xac, 0xb0, 0xc0, 0xe5, 0xba, 0xfb, 0xb8, 0xab, + 0xb5, 0xe4, 0xa9, 0x65, 0xb0, 0xb6, 0xb0, 0xb0, 0xa7, 0xc0, 0xbd, 0x6e, 0xa5, + 0xbc, 0xbd, 0xab, 0xa8, 0xfd, 0xac, 0xc8, 0xad, 0x47, 0xb3, 0xde, 0xc3, 0x51, + 0xa6, 0xec, 0xb4, 0xf4, 0xbf, 0xd7, 0xb1, 0x4c, 0xbc, 0xa2, 0xbd, 0xc3, 0xbd, + 0x45, 0xb7, 0xc5, 0xb0, 0x41, 0xa4, 0xe5, 0xbb, 0x44, 0xaf, 0xbe, 0xa7, 0x6b, + 0xc3, 0xad, 0xaf, 0xbf, 0xb0, 0xdd, 0xb6, 0xe4, 0xaf, 0xce, 0xc2, 0x7c, 0xbe, + 0xe2, 0xbd, 0xbd, 0xb4, 0xf5, 0xba, 0xdb, 0xa7, 0xda, 0xba, 0x57, 0xaa, 0xd7, + 0xb4, 0xa4, 0xa8, 0x55, 0xa7, 0xc5, 0xb6, 0xe3, 0xc2, 0xeb, 0xaf, 0x51, 0xa6, + 0xc3, 0xbb, 0x7a, 0xab, 0xce, 0xb5, 0x4c, 0xbf, 0xbe, 0xb1, 0xef, 0xa7, 0x5e, + 0xa7, 0x64, 0xa4, 0xf0, 0xaa, 0x5a, 0xa4, 0xad, 0xae, 0xb8, 0xa4, 0xc8, 0xbb, + 0x52, 0xa5, 0xee, 0xab, 0x56, 0xb6, 0xf5, 0xa5, 0xb3, 0xc3, 0xfa, 0xb1, 0xe0, + 0xaa, 0xab, 0xa4, 0xc5, 0xb0, 0xc8, 0xae, 0xa9, 0xbb, 0x7e, 0xa9, 0xf5, 0xba, + 0xb3, 0xaa, 0x52, 0xa6, 0xe8, 0xd6, 0xb4, 0xaa, 0xbf, 0xb4, 0xb7, 0xbc, 0x48, + 0xa7, 0x6c, 0xbf, 0xfc, 0xc4, 0xeb, 0xb5, 0x7d, 0xae, 0xa7, 0xa7, 0xc6, 0xb1, + 0x78, 0xbd, 0xa5, 0xa4, 0x69, 0xb1, 0xa4, 0xba, 0xb6, 0xb2, 0x6d, 0xb7, 0xcb, + 0xa6, 0xc1, 0xb5, 0x52, 0xc0, 0xca, 0xc5, 0xa7, 0xae, 0x75, 0xb2, 0xdf, 0xb7, + 0x40, 0xb3, 0xdf, 0xbb, 0xd1, 0xac, 0x7e, 0xa8, 0x74, 0xbb, 0xd8, 0xc0, 0xb8, + 0xb2, 0xd3, 0xbd, 0x4d, 0xbd, 0xbc, 0xa7, 0x58, 0xc1, 0xf8, 0xc1, 0xd2, 0xb7, + 0x76, 0xae, 0x6c, 0xab, 0x4c, 0xaf, 0x55, 0xa4, 0x55, 0xb7, 0x48, 0xae, 0x4c, + 0xc0, 0x7e, 0xb1, 0xc8, 0xa1, 0xbc, 0xa5, 0xfd, 0xa5, 0x50, 0xc2, 0x41, 0xc5, + 0xd6, 0xab, 0x77, 0xbd, 0xe5, 0xbb, 0xce, 0xb2, 0xec, 0xb6, 0xa2, 0xb2, 0x43, + 0xa9, 0xb6, 0xb6, 0xfb, 0xc5, 0xe3, 0xc0, 0x49, 0xb2, 0x7b, 0xc4, 0x6d, 0xbf, + 0xa4, 0xb8, 0xa2, 0xc0, 0x60, 0xb8, 0x72, 0xbe, 0xcb, 0xb3, 0xb4, 0xad, 0xad, + 0xbd, 0x75, 0xac, 0xdb, 0xb4, 0x5b, 0xc6, 0x5e, 0xad, 0xbb, 0xbd, 0x63, 0xc1, + 0xb8, 0xb4, 0xf0, 0xb6, 0x6d, 0xb5, 0xbe, 0xb2, 0xbb, 0xb8, 0xd4, 0xb7, 0x51, + 0xc5, 0x54, 0xa8, 0xc9, 0xb6, 0xb5, 0xab, 0xd1, 0xbe, 0xf3, 0xb9, 0xb3, 0xa6, + 0x56, 0xb6, 0x48, 0xbf, 0xbd, 0xb5, 0x76, 0xbe, 0x5d, 0xab, 0x64, 0xad, 0xfd, + 0xc4, 0xdb, 0xbe, 0x50, 0xae, 0xf8, 0xae, 0x64, 0xb2, 0x63, 0xbe, 0xe5, 0xa4, + 0x70, 0xa7, 0xb5, 0xae, 0xd5, 0xa8, 0x76, 0xbc, 0x53, 0xaf, 0xba, 0xae, 0xc4, + 0xb7, 0xa4, 0xa8, 0xc7, 0xb7, 0xb2, 0xc3, 0xc8, 0xbe, 0x63, 0xa8, 0xf3, 0xae, + 0xb5, 0xc4, 0xe2, 0xa8, 0xb8, 0xb1, 0xd7, 0xaf, 0xd9, 0xbf, 0xd3, 0xbc, 0x67, + 0xb1, 0xf1, 0xa8, 0xf8, 0xc3, 0xc9, 0xbe, 0xd3, 0xaa, 0x6e, 0xc2, 0x6d, 0xc1, + 0xc2, 0xae, 0x68, 0xc1, 0x7e, 0xaa, 0xe4, 0xbe, 0x4e, 0xaa, 0x59, 0xa8, 0xaf, + 0xb7, 0x73, 0xca, 0xe3, 0xa4, 0xdf, 0xab, 0x48, 0xf4, 0xb5, 0xac, 0x50, 0xb8, + 0x7b, 0xb5, 0x56, 0xb4, 0x69, 0xbf, 0xb3, 0xa6, 0x44, 0xab, 0xac, 0xa7, 0xce, + 0xa8, 0xb7, 0xa6, 0xe6, 0xbf, 0xf4, 0xa9, 0xaf, 0xa7, 0xf6, 0xa9, 0xca, 0xa9, + 0x6d, 0xa5, 0x53, 0xa5, 0xfb, 0xaf, 0xdd, 0xa6, 0x49, 0xac, 0xa4, 0xb6, 0xaf, + 0xba, 0xb5, 0xa5, 0xf0, 0xad, 0xd7, 0xb2, 0xdb, 0xa6, 0xb4, 0xb6, 0xe5, 0xc4, + 0xc3, 0xa8, 0x71, 0xb3, 0x53, 0xc2, 0xb8, 0xbc, 0x56, 0xa6, 0xa6, 0xbb, 0xdd, + 0xb5, 0xea, 0xbc, 0x4e, 0xb6, 0xb7, 0xae, 0x7d, 0xb3, 0x5c, 0xbb, 0x57, 0xb3, + 0xa4, 0xb1, 0xd4, 0xa6, 0xb0, 0xa7, 0xc7, 0xaf, 0x62, 0xab, 0xf2, 0xb5, 0xb6, + 0xb4, 0x42, 0xba, 0xfc, 0xc4, 0xf2, 0xb0, 0x61, 0xb3, 0xd9, 0xab, 0xc5, 0xc4, + 0x61, 0xb1, 0xdb, 0xa5, 0xc8, 0xbf, 0xef, 0xc5, 0x7e, 0xaf, 0x74, 0xb5, 0xba, + 0xb9, 0x75, 0xc1, 0xa7, 0xbe, 0xc7, 0xa5, 0xde, 0xb3, 0xb7, 0xa6, 0xe5, 0xb3, + 0xd4, 0xe2, 0xc0, 0xb4, 0x60, 0xa6, 0xaf, 0xb8, 0xdf, 0xb4, 0x4d, 0xb9, 0xa5, + 0xa8, 0xb5, 0xae, 0xee, 0xa6, 0xc4, 0xb0, 0x56, 0xb0, 0x54, 0xbb, 0xb9, 0xa8, + 0xb3, 0xc0, 0xa3, 0xa9, 0xe3, 0xbe, 0x7e, 0xc0, 0x6e, 0xa7, 0x72, 0xa4, 0x58, + 0xaa, 0xde, 0xa4, 0xfa, 0xb0, 0x48, 0xb1, 0x56, 0xb8, 0xc5, 0xb2, 0x50, 0xb6, + 0xae, 0xb0, 0xd7, 0xa8, 0xc8, 0xb3, 0x59, 0xb2, 0x6a, 0xc3, 0x60, 0xec, 0x49, + 0xb7, 0xcf, 0xb2, 0x54, 0xc6, 0x51, 0xc4, 0x59, 0xac, 0xe3, 0xe3, 0xe9, 0xc5, + 0xc9, 0xa9, 0xb5, 0xa8, 0xa5, 0xc3, 0x43, 0xc0, 0x46, 0xaa, 0xa2, 0xaa, 0x75, + 0xa9, 0x61, 0xb1, 0xbb, 0xb2, 0xb4, 0xad, 0x6c, 0xba, 0x74, 0xc6, 0x41, 0xb3, + 0xf7, 0xbf, 0x50, 0xb9, 0xbd, 0xb5, 0x78, 0xb6, 0xad, 0xad, 0xf1, 0xab, 0xdb, + 0xbf, 0x56, 0xae, 0x62, 0xbf, 0xce, 0xc5, 0xe7, 0xac, 0x6f, 0xa5, 0xa1, 0xc0, + 0x6d, 0xaf, 0xb1, 0xb7, 0xa8, 0xb4, 0xad, 0xa8, 0xcb, 0xba, 0xc5, 0xa6, 0xcf, + 0xac, 0x76, 0xb6, 0xa7, 0xae, 0xf1, 0xa5, 0xf5, 0xc4, 0x6f, 0xbe, 0x69, 0xbc, + 0xcb, 0xba, 0x79, 0xc1, 0xdc, 0xb8, 0x79, 0xa7, 0xaf, 0xba, 0xbd, 0xb7, 0x6e, + 0xb3, 0xf3, 0xbb, 0xbb, 0xbd, 0x60, 0xc1, 0xc1, 0xab, 0xc0, 0xab, 0x72, 0xaf, + 0xe6, 0xc3, 0xc4, 0xad, 0x6e, 0xc4, 0xa3, 0xb7, 0xa6, 0xbc, 0x4f, 0xad, 0x43, + 0xb7, 0xdd, 0xb3, 0xa5, 0xa7, 0x4d, 0xa4, 0x5d, 0xad, 0xb6, 0xb1, 0xb3, 0xb7, + 0x7e, 0xb8, 0xad, 0xa6, 0xb2, 0xb5, 0xc5, 0xa9, 0x5d, 0xb2, 0x47, 0xa4, 0x40, + 0xb3, 0xfc, 0xc2, 0xe5, 0xb4, 0xa5, 0xe4, 0x76, 0xa8, 0xcc, 0xa5, 0xec, 0xa6, + 0xe7, 0xc0, 0x5b, 0xa6, 0x69, 0xbf, 0xf2, 0xb2, 0xbe, 0xbb, 0xf6, 0xaf, 0xd8, + 0xba, 0xc3, 0xa8, 0x5e, 0xa9, 0x79, 0xab, 0xbc, 0xc2, 0x55, 0xb4, 0xc8, 0xc3, + 0xc6, 0xad, 0xca, 0xa4, 0x77, 0xa4, 0x41, 0xa8, 0x6f, 0xa5, 0x48, 0xc3, 0xc0, + 0xa7, 0xed, 0xa9, 0xf6, 0xa8, 0xb6, 0xa6, 0x7a, 0xbb, 0xf5, 0xa7, 0xd0, 0xc1, + 0x72, 0xb6, 0x68, 0xb8, 0x77, 0xac, 0xcc, 0xa5, 0xe7, 0xb8, 0xc7, 0xb7, 0x4e, + 0xbc, 0xdd, 0xbe, 0xd0, 0xb8, 0x71, 0xaf, 0x71, 0xb7, 0xb8, 0xb8, 0xda, 0xc4, + 0xb3, 0xbd, 0xcb, 0xc4, 0xb6, 0xb2, 0xa7, 0xc1, 0x6c, 0xb2, 0xdd, 0xc3, 0xb6, + 0xaf, 0xf4, 0xbd, 0xae, 0xa6, 0x5d, 0xae, 0xef, 0xad, 0xb5, 0xb3, 0xb1, 0xab, + 0xc3, 0xa7, 0x75, 0xbb, 0xc8, 0xb2, 0x5d, 0xb1, 0x47, 0xb6, 0xbc, 0xa4, 0xa8, + 0xa4, 0xde, 0xc1, 0xf4, 0xa6, 0x4c, 0xad, 0x5e, 0xc4, 0xe5, 0xc0, 0xa6, 0xc6, + 0x4e, 0xc0, 0xb3, 0xc5, 0xd5, 0xbc, 0xfc, 0xbf, 0xc3, 0xc0, 0xe7, 0xba, 0xb7, + 0xc3, 0xc7, 0xaa, 0xef, 0xc4, 0xb9, 0xac, 0xd5, 0xbc, 0x76, 0xbf, 0x6f, 0xb5, + 0x77, 0xac, 0x4d, 0xb3, 0xe9, 0xbe, 0xd6, 0xb6, 0xc4, 0xc1, 0x73, 0xf7, 0xea, + 0xb1, 0x65, 0xb9, 0x6c, 0xbf, 0xe3, 0xb8, 0xba, 0xb5, 0xfa, 0xaa, 0x61, 0xb4, + 0xe9, 0xa5, 0xc3, 0xb1, 0x76, 0xab, 0x69, 0xa5, 0xce, 0xab, 0xd5, 0xc0, 0x75, + 0xb1, 0x79, 0xbc, 0x7e, 0xa4, 0xd7, 0xa5, 0xd1, 0xb6, 0x6c, 0xb9, 0x5c, 0xb5, + 0x53, 0xaa, 0x6f, 0xb9, 0x43, 0xa8, 0xbb, 0xa6, 0xb3, 0xa4, 0xcd, 0xa5, 0x6b, + 0xa6, 0xf6, 0xb9, 0x56, 0xbb, 0xa4, 0xa4, 0x53, 0xa5, 0xae, 0xa8, 0xb1, 0xb2, + 0x4a, 0xa9, 0xf3, 0xaa, 0xbb, 0xb7, 0xae, 0xb8, 0xb7, 0xb7, 0x4d, 0xc1, 0xd6, + 0xa7, 0x45, 0xab, 0x5c, 0xb9, 0x4f, 0xb3, 0xbd, 0xb4, 0x72, 0xb4, 0xfc, 0xba, + 0xae, 0xb6, 0xa8, 0xa4, 0xa9, 0xae, 0x54, 0xab, 0x42, 0xbb, 0x50, 0xc0, 0xac, + 0xac, 0xea, 0xa6, 0x74, 0xbb, 0x79, 0xa6, 0xd0, 0xa5, 0xc9, 0xb0, 0xec, 0xa8, + 0xa1, 0xc6, 0x7b, 0xa6, 0x53, 0xb9, 0x4a, 0xb3, 0xeb, 0xae, 0x6e, 0xb1, 0x73, + 0xc2, 0xa1, 0xb1, 0xfd, 0xba, 0xbb, 0xa8, 0x7c, 0xc5, 0x41, 0xaf, 0x44, 0xb4, + 0x4a, 0xb8, 0xce, 0xb9, 0x77, 0xbf, 0xdd, 0xb6, 0xbf, 0xc0, 0x70, 0xb2, 0x57, + 0xad, 0xde, 0xa4, 0xb8, 0xab, 0xae, 0xb0, 0x4b, 0xad, 0xec, 0xb4, 0xa9, 0xc1, + 0xd5, 0xb6, 0xe9, 0xad, 0xfb, 0xb6, 0xea, 0xb7, 0xe1, 0xb7, 0xbd, 0xbd, 0x74, + 0xbb, 0xb7, 0xad, 0x62, 0xc4, 0x40, 0xab, 0xe8, 0xb0, 0x7c, 0xa4, 0xea, 0xac, + 0xf9, 0xb6, 0x56, 0xc5, 0x44, 0xc6, 0x5f, 0xa9, 0xa8, 0xb8, 0x66, 0xa4, 0xeb, + 0xae, 0xae, 0xbe, 0x5c, 0xaf, 0xd0, 0xb6, 0xb3, 0xe0, 0xa8, 0xa4, 0xc3, 0xb9, + 0x6b, 0xa4, 0xb9, 0xb9, 0x42, 0xc4, 0xad, 0xc1, 0xdf, 0xb7, 0x77, 0xc3, 0xfd, + 0xa5, 0xa5, 0xa5, 0x60, 0xaf, 0x7b, 0xc2, 0xf8, 0xae, 0xe2, 0xab, 0x76, 0xa8, + 0x61, 0xae, 0x5f, 0xb8, 0xfc, 0xa6, 0x41, 0xa6, 0x62, 0xab, 0xa5, 0xf6, 0xe3, + 0xbc, 0xc8, 0xc6, 0x67, 0xc5, 0x42, 0xc5, 0xa6, 0xb8, 0xae, 0xbe, 0x44, 0xc1, + 0x56, 0xc6, 0x77, 0xc4, 0xa6, 0xb4, 0xc7, 0xa6, 0xad, 0xbe, 0xfe, 0xb0, 0x44, + 0xc4, 0xbc, 0xbe, 0xb8, 0xb3, 0x79, 0xa8, 0x6d, 0xa8, 0x5f, 0xc0, 0xea, 0xb3, + 0x64, 0xbe, 0xdc, 0xab, 0x68, 0xbf, 0x41, 0xb8, 0xe9, 0xab, 0xe7, 0xbc, 0x57, + 0xbc, 0xa8, 0xb4, 0xbf, 0xc3, 0xd8, 0xb2, 0xcf, 0xb3, 0xe5, 0xb4, 0xed, 0xa5, + 0xbe, 0xaa, 0xee, 0xee, 0xd4, 0xb9, 0x68, 0xaf, 0x77, 0xac, 0x5d, 0xba, 0x5e, + 0xa9, 0x51, 0xa5, 0x45, 0xac, 0xb5, 0xb6, 0x42, 0xba, 0x4b, 0xc2, 0x4e, 0xa6, + 0x76, 0xaf, 0xb6, 0xb6, 0xc5, 0xb9, 0xeb, 0xc2, 0xa4, 0xc0, 0xd6, 0xb8, 0xe2, + 0xd6, 0xdf, 0xaa, 0x67, 0xb7, 0xf8, 0xb1, 0xd9, 0xc1, 0xd3, 0xb9, 0xf1, 0xae, + 0x69, 0xc5, 0xd9, 0xb4, 0xcc, 0xa6, 0xfb, 0xbe, 0xd4, 0xaf, 0xb8, 0xb4, 0xef, + 0xba, 0xec, 0xbc, 0xcc, 0xb3, 0xb9, 0xb9, 0xfc, 0xba, 0x73, 0xb1, 0x69, 0xb4, + 0x78, 0xba, 0xa6, 0xa7, 0xfa, 0xa4, 0x56, 0xb1, 0x62, 0xbd, 0xe3, 0xa5, 0x4d, + 0xb5, 0xc8, 0xbf, 0x60, 0xbb, 0xd9, 0xa9, 0xdb, 0xac, 0x4c, 0xa7, 0xe4, 0xaa, + 0x68, 0xbb, 0xaf, 0xb7, 0xd3, 0xb8, 0x6e, 0xa5, 0xfc, 0xbb, 0x46, 0xa5, 0x6c, + 0xbe, 0x42, 0xa7, 0xe9, 0xad, 0xf5, 0xee, 0x68, 0xc2, 0xe1, 0xaa, 0xcc, 0xeb, + 0xe3, 0xbd, 0xa9, 0xb3, 0x6f, 0xae, 0xfd, 0xac, 0xc3, 0xb7, 0x72, 0xaf, 0x75, + 0xba, 0xc2, 0xaf, 0x7a, 0xbf, 0xb2, 0xad, 0x73, 0xb0, 0x77, 0xb0, 0xbb, 0xaa, + 0x45, 0xaf, 0x6c, 0xb6, 0x45, 0xbe, 0x5f, 0xae, 0xb6, 0xc2, 0xed, 0xb0, 0x7d, + 0xbb, 0x5d, 0xb1, 0xc3, 0xb8, 0x43, 0xa9, 0xba, 0xb2, 0x75, 0xaa, 0xa7, 0xa9, + 0xc3, 0xbe, 0xe3, 0xac, 0x40, 0xa5, 0xbf, 0xac, 0x46, 0xb4, 0x56, 0xc4, 0x70, + 0xbe, 0x47, 0xb5, 0xfd, 0xaa, 0xdb, 0xaa, 0x4b, 0xa4, 0xe4, 0xa7, 0x73, 0xbb, + 0x6a, 0xaa, 0xbe, 0xaa, 0xcf, 0xaf, 0xd7, 0xa5, 0xc4, 0xa4, 0xa7, 0xc2, 0xb4, + 0xc2, 0xbe, 0xaa, 0xbd, 0xb4, 0xd3, 0xb4, 0xde, 0xb0, 0xf5, 0xad, 0xc8, 0xcb, + 0xbb, 0xa7, 0x7d, 0xab, 0xfc, 0xa4, 0xee, 0xb3, 0x6b, 0xb0, 0xa6, 0xa6, 0xae, + 0xaf, 0xc8, 0xa7, 0xd3, 0xbc, 0xb0, 0xc2, 0x59, 0xa6, 0xdc, 0xad, 0x50, 0xb8, + 0x6d, 0xbc, 0x6d, 0xab, 0xcf, 0xa8, 0xee, 0xb4, 0xbc, 0xaf, 0xb4, 0xb8, 0x58, + 0xbd, 0xe8, 0xaa, 0xa5, 0xb2, 0xa9, 0xba, 0xa2, 0xaa, 0x76, 0xb2, 0xbf, 0xa4, + 0xa4, 0xac, 0xd8, 0xa9, 0xbe, 0xc4, 0xc1, 0xb0, 0x4a, 0xb2, 0xd7, 0xba, 0xd8, + 0xb8, 0x7e, 0xad, 0xab, 0xa5, 0xf2, 0xb2, 0xb3, 0xa6, 0xe0, 0xa9, 0x50, 0xa6, + 0x7b, 0xac, 0x77, 0xee, 0xa4, 0xb5, 0xb0, 0xb6, 0x62, 0xa8, 0x79, 0xa9, 0xaa, + 0xa9, 0x47, 0xbd, 0x4b, 0xa9, 0x7a, 0xb1, 0xde, 0xc6, 0x4a, 0xaf, 0x5d, 0xae, + 0xe8, 0xb5, 0xef, 0xa6, 0xb6, 0xbd, 0xde, 0xbd, 0xd1, 0xb8, 0xdd, 0xb3, 0x76, + 0xa6, 0xcb, 0xc0, 0xeb, 0xb5, 0x4e, 0xa9, 0xd6, 0xc6, 0x66, 0xc5, 0xf1, 0xa5, + 0x44, 0xb5, 0xdb, 0xac, 0x57, 0xa7, 0x55, 0xb3, 0x45, 0xb6, 0x4a, 0xc5, 0xb1, + 0xbf, 0x76, 0xa6, 0xed, 0xaa, 0x60, 0xaf, 0xac, 0xbe, 0x6e, 0xa7, 0xec, 0xa4, + 0xf6, 0xab, 0xfb, 0xb1, 0x4d, 0xbf, 0x6a, 0xc2, 0xe0, 0xbc, 0xb6, 0xc1, 0xc8, + 0xbd, 0x66, 0xbc, 0xce, 0xb2, 0xf8, 0xb8, 0xcb, 0xa7, 0xa9, 0xbc, 0xb2, 0xa7, + 0xa7, 0xaa, 0xac, 0xb4, 0xd5, 0xc0, 0x40, 0xb0, 0x6c, 0xc2, 0xd8, 0xbc, 0x59, + 0xba, 0xf3, 0xbd, 0xce, 0xb7, 0xc7, 0xae, 0xbb, 0xa9, 0xe5, 0xa8, 0xf4, 0xae, + 0xe0, 0xb5, 0x5a, 0xad, 0x5f, 0xb0, 0x75, 0xb0, 0xd6, 0xb5, 0xdb, 0xa8, 0x60, + 0xbf, 0x42, 0xaf, 0xf7, 0xab, 0x74, 0xb8, 0xea, 0xab, 0xba, 0xb4, 0xfe, 0xb2, + 0x64, 0xa7, 0xb6, 0xb5, 0xb5, 0xa5, 0x4a, 0xac, 0xf3, 0xb7, 0xba, 0xa4, 0x6c, + 0xa6, 0xdb, 0xba, 0x7b, 0xa6, 0x72, 0xc3, 0x4f, 0xb4, 0xc4, 0xc2, 0xdc, 0xa9, + 0x76, 0xba, 0xee, 0xc1, 0x60, 0xc1, 0x61, 0xb9, 0x51, 0xa8, 0xab, 0xab, 0xb5, + 0xb4, 0x7e, 0xaf, 0xb2, 0xa8, 0xac, 0xa8, 0xf2, 0xb1, 0xda, 0xaf, 0xaa, 0xb6, + 0x41, 0xaa, 0xfd, 0xb2, 0xd5, 0xc6, 0x70, 0xc4, 0xa1, 0xbc, 0x4c, 0xbe, 0x4b, + 0xb3, 0xcc, 0xb8, 0x6f, 0xb4, 0x4c, 0xbf, 0xed, 0xac, 0x51, 0xa5, 0xaa, 0xa6, + 0xf5, 0xac, 0x67, 0xb0, 0xb5, 0xa7, 0x40, 0xa7, 0xa4, 0xae, 0x79, 0xa1, 0xbc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xc9, 0x48, 0xc9, 0x46, 0xa4, + 0x61, 0xa4, 0xa2, 0xa4, 0xdc, 0xa4, 0xca, 0xa5, 0x41, 0xa5, 0xe5, 0xa5, 0xe0, + 0xb0, 0xac, 0xd1, 0x65, 0xbe, 0xb5, 0xa1, 0xbc, 0xac, 0xeb, 0xa1, 0xbc, 0xa4, + 0x50, 0xc9, 0x47, 0xa4, 0xd4, 0xa4, 0xf8, 0xa5, 0x67, 0xa5, 0xc2, 0xc9, 0xc7, + 0xad, 0x4e, 0xd8, 0x50, 0xb7, 0xb6, 0xe2, 0xe9, 0xa1, 0xbc, 0xa1, 0xbc, 0xab, + 0x45, 0xe8, 0xf3, 0xc9, 0x41, 0xa5, 0xe4, 0xc9, 0x51, 0xaa, 0xcb, 0xa7, 0xb8, + 0xb6, 0xde, 0xe1, 0x4c, 0xa4, 0xb7, 0xcd, 0xf8, 0xad, 0xed, 0xf1, 0xef, 0xb3, + 0xd6, 0xbc, 0x72, 0xc5, 0xe2, 0xc5, 0xac, 0xc9, 0x43, 0xa5, 0x72, 0xd4, 0x6f, + 0xb9, 0xbc, 0xb0, 0xd0, 0xf0, 0xf3, 0xa8, 0xf6, 0xca, 0x72, 0xa1, 0xbc, 0xa4, + 0xc2, 0xa6, 0x46, 0xcd, 0xf0, 0xcb, 0xd2, 0xe4, 0xf3, 0xb3, 0xcf, 0xab, 0x66, + 0xd0, 0xe9, 0xd0, 0xe6, 0xad, 0xe6, 0xe3, 0xc7, 0xb6, 0xd1, 0xb9, 0xbb, 0xe1, + 0x42, 0xa1, 0xbc, 0xbe, 0xb0, 0xa1, 0xbc, 0xaa, 0xc9, 0xa1, 0xbc, 0xa4, 0xb1, + 0xc9, 0x53, 0xc9, 0x52, 0xc9, 0x65, 0xc9, 0x68, 0xa1, 0xbc, 0xa5, 0x51, 0xdc, + 0xba, 0xa5, 0xf6, 0xc9, 0xb7, 0xca, 0x5f, 0xc9, 0xae, 0xad, 0xce, 0xb3, 0xc9, + 0xa5, 0xea, 0xa6, 0xee, 0xa6, 0xf0, 0xca, 0x61, 0xa7, 0xf1, 0xa7, 0x48, 0xa7, + 0x46, 0xca, 0x63, 0xa6, 0xef, 0xa1, 0xbc, 0xa6, 0xf7, 0xcb, 0xb8, 0xcb, 0xb9, + 0xa8, 0xdd, 0xcb, 0xba, 0xa8, 0xd4, 0xa8, 0xdc, 0xa8, 0xdb, 0xa8, 0xd9, 0xbe, + 0xab, 0xcb, 0xb3, 0xbb, 0xfa, 0xcb, 0xc6, 0xbe, 0xa9, 0xc5, 0x6b, 0xc4, 0xd7, + 0xcd, 0xde, 0xab, 0x5a, 0xcd, 0xe3, 0xcd, 0xe5, 0xab, 0x4d, 0xab, 0x53, 0xad, + 0xc4, 0xad, 0xc5, 0xb0, 0xb4, 0xad, 0xd6, 0xd0, 0xd3, 0xb0, 0xbf, 0xa1, 0xbc, + 0xad, 0xd8, 0xad, 0xda, 0xd0, 0xd7, 0xad, 0xbe, 0xad, 0xc3, 0xad, 0xd0, 0xe0, + 0xf3, 0xb0, 0xb3, 0xb0, 0xba, 0xd4, 0x55, 0xb0, 0xb9, 0xb6, 0xcd, 0xdc, 0xbc, + 0xc5, 0x6c, 0xbe, 0xaa, 0xf5, 0xc0, 0xdc, 0xbf, 0xb9, 0xaf, 0xe4, 0xea, 0xb9, + 0xb0, 0xe0, 0xfa, 0xe0, 0xf0, 0xb9, 0xad, 0xe4, 0xeb, 0xe4, 0xee, 0xc9, 0x69, + 0xc9, 0xf8, 0xca, 0x65, 0xdc, 0xc2, 0xab, 0x5b, 0xef, 0xb6, 0xc9, 0xf8, 0xf7, + 0x40, 0xa4, 0xbc, 0xb4, 0x53, 0xc6, 0x64, 0xef, 0x55, 0xf6, 0xd8, 0xc4, 0xdc, + 0xa1, 0xbc, 0xab, 0x6d, 0xd0, 0xb1, 0xb0, 0xcb, 0xe0, 0xed, 0xa6, 0x67, 0xa8, + 0xe1, 0xa1, 0xbc, 0xab, 0x5e, 0xad, 0xbd, 0xb3, 0x4f, 0xd7, 0xc0, 0xc1, 0xb6, + 0xf9, 0x43, 0xb8, 0xcf, 0xb8, 0x5b, 0xbe, 0xc6, 0xf2, 0xdd, 0xc3, 0xbd, 0xa1, + 0xbc, 0xc9, 0xbc, 0xa8, 0xe6, 0xcb, 0xce, 0xa1, 0xbc, 0xa1, 0xbc, 0xb6, 0xef, + 0xad, 0xdf, 0xf3, 0x65, 0xb0, 0x50, 0xb0, 0x52, 0xb0, 0x53, 0xf0, 0xdd, 0xdb, + 0xd6, 0xb3, 0x5b, 0xb5, 0xfe, 0xb6, 0x46, 0xb6, 0x43, 0xdb, 0xdc, 0xb6, 0x40, + 0xdb, 0xdf, 0xe0, 0x46, 0xe0, 0x4c, 0xe0, 0x47, 0xb8, 0xd7, 0xb8, 0xd9, 0xe0, + 0x4d, 0xb8, 0xe1, 0xb8, 0xe0, 0xbd, 0xd8, 0xeb, 0xa1, 0xe0, 0x48, 0xbb, 0xa6, + 0xbb, 0xa2, 0xbb, 0xa5, 0xe4, 0x4d, 0xe7, 0xd4, 0xe7, 0xd8, 0xbd, 0xd3, 0xbd, + 0xdb, 0xe7, 0xdc, 0xbd, 0xd4, 0xbd, 0xd9, 0xbf, 0xdb, 0xbf, 0xcf, 0xeb, 0xa6, + 0xbf, 0xd6, 0xeb, 0xa7, 0xbf, 0xd9, 0xbf, 0xdc, 0xbf, 0xda, 0xbf, 0xcd, 0xbf, + 0xd4, 0xeb, 0xab, 0xc2, 0xd3, 0xc6, 0x6d, 0xee, 0xa2, 0xee, 0xb0, 0xc1, 0xc4, + 0xc2, 0xd6, 0xf7, 0x56, 0xf2, 0xfb, 0xc3, 0xd7, 0xc3, 0xd4, 0xf9, 0xa9, 0xc4, + 0xb8, 0xc6, 0x40, 0xa1, 0xbc, 0xce, 0xaf, 0xa1, 0xbc, 0xca, 0x56, 0xa6, 0xe9, + 0xa8, 0xc0, 0xa8, 0xc1, 0xcd, 0xd9, 0xcd, 0xda, 0xab, 0x40, 0xb0, 0xa4, 0xd0, + 0xc2, 0xd4, 0x46, 0xdc, 0xa1, 0xb3, 0xb5, 0xb6, 0xab, 0xb3, 0xb2, 0xdc, 0x7e, + 0xb6, 0xaa, 0xe0, 0xd4, 0xee, 0xf5, 0xca, 0x52, 0xca, 0x54, 0xf1, 0x4b, 0xca, + 0x51, 0xe0, 0xa9, 0xcb, 0xa8, 0xcd, 0xd4, 0xcd, 0xd6, 0xaa, 0xf5, 0xbf, 0xf3, + 0xaa, 0xf3, 0xcd, 0xd7, 0xd3, 0xf7, 0xd0, 0xbb, 0xd0, 0xbc, 0xeb, 0xd7, 0xa1, + 0xbc, 0xd0, 0xbd, 0xdc, 0x50, 0xc5, 0xb0, 0xb0, 0x72, 0xd3, 0xfc, 0xd3, 0xfb, + 0xd3, 0xfa, 0xd7, 0xef, 0xd7, 0xe8, 0xb6, 0x6e, 0xdc, 0x52, 0xe4, 0x6b, 0xbb, + 0xc2, 0xe4, 0x68, 0xbe, 0x49, 0xe8, 0x54, 0xc1, 0xdd, 0xf4, 0xe1, 0xf6, 0x5a, + 0xaf, 0xec, 0xab, 0xb7, 0xe4, 0xf4, 0xa7, 0x57, 0xca, 0x6f, 0xa8, 0xf0, 0xd0, + 0xf8, 0xa1, 0xbc, 0xd4, 0x6d, 0xbc, 0x45, 0xad, 0xee, 0xc0, 0xe8, 0xf4, 0x77, + 0xa1, 0xbc, 0xc9, 0x42, 0xa1, 0xbc, 0xd4, 0x4a, 0xa1, 0xbc, 0xa5, 0xaf, 0xaf, + 0x63, 0xd0, 0x57, 0xca, 0xac, 0xb0, 0xee, 0xa1, 0xbc, 0xb9, 0xd1, 0xe9, 0x4f, + 0xbe, 0xc3, 0xc0, 0xa4, 0xa6, 0x66, 0xa6, 0x64, 0xc9, 0xc9, 0xa6, 0x60, 0xc2, + 0x52, 0xc9, 0xc8, 0xa6, 0x65, 0xc3, 0x63, 0xa7, 0xa6, 0xa1, 0xbc, 0xa9, 0x58, + 0xa1, 0xbc, 0xcb, 0xf5, 0xf1, 0xf6, 0xa9, 0x5c, 0xcb, 0xfb, 0xcc, 0x40, 0xcb, + 0xf4, 0xcb, 0xf8, 0xcb, 0xfc, 0xd4, 0xc1, 0xce, 0x53, 0xce, 0x54, 0xdc, 0xe5, + 0xd4, 0xba, 0xa1, 0xbc, 0xa1, 0xbc, 0xab, 0xb2, 0xab, 0xad, 0xd1, 0x4c, 0xb6, + 0xf6, 0xb3, 0xfa, 0xdc, 0xe4, 0xd1, 0x4d, 0xd1, 0x52, 0xd4, 0xb2, 0xa1, 0xbc, + 0xd4, 0xb7, 0xb0, 0xf1, 0xa1, 0xbc, 0xd4, 0xb8, 0xd4, 0xcb, 0xd4, 0xb5, 0xd4, + 0xb4, 0xd4, 0xb3, 0xd8, 0xa2, 0xd8, 0xa1, 0xa1, 0xbc, 0xb3, 0xfb, 0xdc, 0xed, + 0xa1, 0xbc, 0xe1, 0x5b, 0xe1, 0x56, 0xa1, 0xbc, 0xbc, 0x55, 0xc4, 0xc9, 0xc5, + 0x67, 0xc5, 0x74, 0xa1, 0xbc, 0xca, 0x4d, 0xca, 0x4e, 0xcb, 0x7a, 0xcb, 0xa1, + 0xcd, 0xbf, 0xcb, 0xa3, 0xcb, 0x7c, 0xcb, 0x7d, 0xeb, 0x52, 0xaa, 0xdc, 0xcd, + 0xb4, 0xea, 0xfc, 0xaa, 0xe8, 0xaa, 0xe7, 0xf4, 0xbe, 0xa1, 0xbc, 0xad, 0x55, + 0xcd, 0xb6, 0xaa, 0xe9, 0xcd, 0xba, 0xb3, 0x41, 0xb5, 0xe7, 0xe7, 0x76, 0xcd, + 0xc1, 0xcd, 0xbe, 0xcd, 0xc0, 0xa1, 0xbc, 0xaa, 0xdf, 0xa1, 0xbc, 0xad, 0x52, + 0xcd, 0xc3, 0xd0, 0x77, 0xad, 0x5b, 0xa1, 0xbc, 0xd0, 0xa1, 0xf4, 0xb8, 0xd0, + 0x6e, 0xad, 0x60, 0xd0, 0x75, 0xad, 0x5c, 0xa1, 0xbc, 0xd0, 0x7a, 0xd0, 0x7b, + 0xad, 0x64, 0xe7, 0x72, 0xa1, 0xbc, 0xad, 0x67, 0xb6, 0xf7, 0xde, 0x72, 0xd0, + 0xa2, 0xd0, 0x71, 0xd3, 0x7d, 0xd3, 0x77, 0xea, 0xfe, 0xe7, 0x6e, 0xd3, 0xa5, + 0xb2, 0xf7, 0xd3, 0xa6, 0xaf, 0xf5, 0xaf, 0xfc, 0xd7, 0x6c, 0xeb, 0x4c, 0xd3, + 0xac, 0xaf, 0xf6, 0xd3, 0xae, 0xaf, 0xfe, 0xee, 0x50, 0xaf, 0xfb, 0xaf, 0xfa, + 0xc2, 0xc9, 0xd3, 0x74, 0xd0, 0x72, 0xd3, 0x73, 0xba, 0xba, 0xe2, 0x6c, 0xeb, + 0x43, 0xd3, 0xa3, 0xf0, 0xb0, 0xa1, 0xbc, 0xbb, 0x5e, 0xdf, 0xd2, 0xa1, 0xbc, + 0xd7, 0x74, 0xb2, 0xf2, 0xe3, 0xc2, 0xb8, 0xb1, 0xb2, 0xfb, 0xd7, 0x6d, 0xb2, + 0xf9, 0xa1, 0xbc, 0xbb, 0x59, 0xb2, 0xfe, 0xee, 0x56, 0xd7, 0x67, 0xd7, 0x68, + 0xeb, 0x4f, 0xb2, 0xfd, 0xb2, 0xf1, 0xb2, 0xf0, 0xd7, 0x5b, 0xc5, 0x61, 0xa1, + 0xbc, 0xb5, 0xd7, 0xdb, 0x6d, 0xdb, 0x6f, 0xdb, 0x70, 0xd4, 0xbb, 0xa1, 0xbc, + 0xb5, 0xd6, 0xdb, 0x6e, 0xb5, 0xe0, 0xdb, 0x75, 0xa1, 0xbc, 0xb5, 0xe3, 0xdb, + 0x7b, 0xdb, 0x7c, 0xb5, 0xe8, 0xb5, 0xe9, 0xdb, 0x79, 0xb5, 0xd1, 0xb5, 0xd2, + 0xdb, 0x5e, 0xdb, 0xa5, 0xb5, 0xd5, 0xdb, 0x60, 0xbf, 0xa2, 0xb5, 0xdd, 0xdb, + 0x72, 0xa1, 0xbc, 0xdf, 0xb1, 0xdf, 0xb8, 0xdf, 0xb9, 0xdf, 0xbb, 0xeb, 0x41, + 0xa1, 0xbc, 0xdf, 0xc2, 0xeb, 0x44, 0xdf, 0xc4, 0xb8, 0xb0, 0xb8, 0xb6, 0xb8, + 0xb4, 0xdf, 0xac, 0xe7, 0x6f, 0xdf, 0xd5, 0xb8, 0xa9, 0xb8, 0xb5, 0xe3, 0xb8, + 0xe3, 0xb9, 0xe3, 0xbd, 0xc5, 0x5a, 0xa1, 0xbc, 0xbb, 0x5f, 0xbb, 0x63, 0xbb, + 0x55, 0xe3, 0xb0, 0xf7, 0xf0, 0xe3, 0xae, 0xe3, 0xb6, 0xe3, 0xb7, 0xe3, 0xac, + 0xf1, 0x6a, 0xee, 0x40, 0xe7, 0x5c, 0xbf, 0x5f, 0xa1, 0xbc, 0xe7, 0x75, 0xf5, + 0xfd, 0xe7, 0x54, 0xc4, 0xa9, 0xea, 0xf8, 0xe7, 0x4d, 0xbd, 0xb6, 0xe7, 0x64, + 0xbf, 0xb7, 0xbf, 0xb8, 0xbf, 0xb9, 0xeb, 0x42, 0xbf, 0xbf, 0xee, 0x44, 0xea, + 0x7b, 0xbf, 0xbb, 0xf4, 0xbf, 0xed, 0xfb, 0xed, 0xfc, 0xc1, 0xa9, 0xc1, 0xa8, + 0xed, 0xf5, 0xee, 0x52, 0xc3, 0xc1, 0xc1, 0xa3, 0xee, 0x51, 0xc2, 0xca, 0xf0, + 0xb8, 0xc2, 0xc8, 0xc4, 0xf6, 0xa1, 0xbc, 0xf2, 0xd4, 0xf4, 0xb9, 0xf5, 0xf8, + 0xf4, 0xc1, 0xf5, 0xfc, 0xc4, 0xf4, 0xf7, 0xf3, 0xa4, 0x7b, 0xab, 0xd9, 0xc9, + 0xcb, 0xb9, 0xdd, 0xd0, 0x55, 0xab, 0xb3, 0xae, 0x4f, 0xae, 0x4e, 0xb0, 0xcc, + 0xa4, 0x71, 0xc9, 0xd5, 0xa7, 0xbc, 0xc0, 0xaa, 0xa1, 0xbc, 0xb1, 0xbf, 0xe1, + 0xde, 0xcc, 0xbd, 0xcc, 0xb9, 0xa9, 0xe9, 0xa9, 0xed, 0xab, 0xfa, 0xe5, 0xb9, + 0xce, 0xdf, 0xd1, 0xba, 0xd1, 0xbb, 0xd1, 0xb8, 0xd5, 0x6d, 0xd9, 0x5e, 0xb1, + 0xba, 0xb1, 0xcc, 0xd5, 0x71, 0xba, 0x51, 0xd5, 0x79, 0xb1, 0xc5, 0xd5, 0x68, + 0xb1, 0xca, 0xd5, 0x7a, 0xe1, 0xe8, 0xd9, 0x60, 0xa1, 0xbc, 0xd9, 0x5d, 0xbc, + 0xc3, 0xd9, 0x67, 0xa1, 0xbc, 0xd9, 0x55, 0xb4, 0xac, 0xb4, 0x7d, 0xd9, 0x64, + 0xef, 0xd2, 0xdd, 0xae, 0xdd, 0xb6, 0xdd, 0xb8, 0xdd, 0x7d, 0xdd, 0xaa, 0xdd, + 0xab, 0xdd, 0xba, 0xe1, 0xe7, 0xf4, 0x4c, 0xba, 0x54, 0xe5, 0xaf, 0xba, 0x50, + 0xc2, 0x5e, 0xef, 0xd7, 0xbc, 0xc1, 0xf5, 0xcd, 0xa1, 0xbc, 0xe9, 0xa6, 0xe9, + 0xa4, 0xec, 0xec, 0xc0, 0xc2, 0xf2, 0x45, 0xf7, 0xdd, 0xf8, 0xef, 0xa4, 0x7c, + 0xca, 0xd6, 0xa1, 0xbc, 0xb7, 0x49, 0xa1, 0xbc, 0xa5, 0x77, 0xbc, 0x54, 0xa5, + 0x6e, 0xa5, 0x6f, 0xa5, 0x7b, 0xa6, 0x5c, 0xa1, 0xbc, 0xa6, 0x5b, 0xa1, 0xbc, + 0xe5, 0x46, 0xc5, 0x6d, 0xca, 0x79, 0xf1, 0xf2, 0xa7, 0x63, 0xa1, 0xbc, 0xd0, + 0xf9, 0xce, 0x4a, 0xa1, 0xbc, 0xa1, 0xbc, 0xcb, 0xdf, 0xa1, 0xbc, 0xa9, 0x45, + 0xa9, 0x4b, 0xcb, 0xef, 0xa9, 0x4e, 0xc0, 0x7b, 0xa9, 0x46, 0xa9, 0x4c, 0xcb, + 0xe7, 0xa1, 0xbc, 0xa1, 0xbc, 0xcd, 0xfc, 0xab, 0x7b, 0xa1, 0xbc, 0xe8, 0xfd, + 0xab, 0xa8, 0xab, 0x78, 0xe4, 0xf9, 0xb9, 0xcd, 0xce, 0x4d, 0xa1, 0xbc, 0xe9, + 0x41, 0xab, 0xa6, 0xab, 0xa9, 0xa1, 0xbc, 0xe9, 0x44, 0xa1, 0xbc, 0xec, 0xc1, + 0xab, 0xa7, 0xab, 0x7d, 0xa1, 0xbc, 0xbe, 0xba, 0xcd, 0xfe, 0xce, 0x4e, 0xe1, + 0x4d, 0xd0, 0xf4, 0xbc, 0x47, 0xae, 0x43, 0xad, 0xf8, 0xd0, 0xf5, 0xdc, 0xd4, + 0xa1, 0xbc, 0xae, 0x44, 0xd0, 0xfc, 0xae, 0x41, 0xd4, 0x77, 0xb9, 0xc9, 0xd8, + 0x6f, 0xd8, 0x70, 0xa1, 0xbc, 0xc4, 0xda, 0xb0, 0xe7, 0xb0, 0xde, 0xa1, 0xbc, + 0xd4, 0x75, 0xd4, 0x73, 0xad, 0xf2, 0xb0, 0xdc, 0xd4, 0x71, 0xd4, 0x72, 0xd8, + 0x6a, 0xb0, 0xe6, 0xd4, 0x7c, 0xb0, 0xe3, 0xb3, 0xe3, 0xdc, 0xd6, 0xb3, 0xe4, + 0xb3, 0xed, 0xa1, 0xbc, 0xd8, 0x6e, 0xd8, 0x71, 0xb3, 0xe7, 0xb3, 0xee, 0xdc, + 0xdb, 0xd8, 0x66, 0xb3, 0xd7, 0xb6, 0xd8, 0xb9, 0xc6, 0xf4, 0x41, 0xb3, 0xe1, + 0xb3, 0xf1, 0xa1, 0xbc, 0xb9, 0xc8, 0xb6, 0xe8, 0xb9, 0xca, 0xb6, 0xdf, 0xc4, + 0xd9, 0xa1, 0xbc, 0xdc, 0xd2, 0xb6, 0xdb, 0xdc, 0xd0, 0xdc, 0xd3, 0xb6, 0xe2, + 0xb6, 0xe7, 0xdc, 0xdd, 0xbe, 0xbc, 0xdc, 0xcc, 0xdc, 0xde, 0xb6, 0xd9, 0xa1, + 0xbc, 0xb6, 0xe1, 0xc5, 0xaf, 0xa1, 0xbc, 0xb9, 0xcb, 0xe1, 0x49, 0xe1, 0x4e, + 0xc4, 0x58, 0xa1, 0xbc, 0xb9, 0xbe, 0xb9, 0xbf, 0xe1, 0x47, 0xa1, 0xbc, 0xe4, + 0xfe, 0xbc, 0x49, 0xbc, 0x50, 0xe5, 0x44, 0xa1, 0xbc, 0xbe, 0xbe, 0xbe, 0xb2, + 0xc2, 0x50, 0xe4, 0xf8, 0xa1, 0xbc, 0xec, 0xc3, 0xbe, 0xb6, 0xbe, 0xbb, 0xbe, + 0xb3, 0xa1, 0xbc, 0xa1, 0xbc, 0xc0, 0x7d, 0xec, 0xc0, 0xa1, 0xbc, 0xf8, 0xee, + 0xc9, 0x49, 0xa6, 0x5f, 0xc9, 0xc6, 0xd4, 0xac, 0xa7, 0x7a, 0xcb, 0xf1, 0xab, + 0xaa, 0xae, 0x46, 0xd4, 0xab, 0xb0, 0xeb, 0xe9, 0x47, 0xb4, 0x57, 0xcc, 0x6f, + 0xcc, 0x6e, 0xa9, 0xae, 0xec, 0xdb, 0xe1, 0xb2, 0xb9, 0xf6, 0xb1, 0x63, 0xd8, + 0xf2, 0xb9, 0xf7, 0xb9, 0xf3, 0xa1, 0xbc, 0xbc, 0x6e, 0xa7, 0xc4, 0xc9, 0xd7, + 0xca, 0xc0, 0xa7, 0xc1, 0xb9, 0xf2, 0xca, 0xc2, 0xae, 0x73, 0xa1, 0xbc, 0xa7, + 0xc2, 0xb4, 0x50, 0xa1, 0xbc, 0xcc, 0x5e, 0xcc, 0x65, 0xa1, 0xbc, 0xcc, 0x61, + 0xa9, 0xa6, 0xa9, 0xa7, 0xcc, 0x63, 0xa1, 0xbc, 0xa9, 0xa2, 0xe9, 0x61, 0xab, + 0xd0, 0xe5, 0x69, 0xce, 0x7d, 0xb1, 0x57, 0xe5, 0x63, 0xd4, 0xfb, 0xb1, 0x5d, + 0xd4, 0xfc, 0xd5, 0x44, 0xb1, 0x5c, 0xd4, 0xf4, 0xb1, 0x53, 0xb1, 0x55, 0xc0, + 0xaf, 0xa1, 0xbc, 0xb4, 0x51, 0xd8, 0xe6, 0xdd, 0x52, 0xd8, 0xe3, 0xb7, 0x44, + 0xe1, 0xa8, 0xd8, 0xdb, 0xd8, 0xdd, 0xdd, 0x4f, 0xb7, 0x43, 0xa1, 0xbc, 0xe1, + 0xa3, 0xe5, 0x62, 0xbc, 0x6a, 0xc1, 0xc7, 0xec, 0xda, 0xc5, 0x71, 0xc9, 0x4c, + 0xa7, 0xcf, 0xcc, 0x75, 0xab, 0xe0, 0xab, 0xe2, 0xab, 0xe1, 0xb1, 0x74, 0xb1, + 0x70, 0xb1, 0x75, 0xb4, 0x61, 0xdd, 0x64, 0xbc, 0x78, 0xe9, 0x75, 0xc5, 0xfc, + 0xa1, 0xbc, 0xa1, 0xbc, 0xc9, 0xa6, 0xca, 0x43, 0xc2, 0x78, 0xa1, 0xbc, 0xcb, + 0x63, 0xcb, 0x65, 0xaa, 0xad, 0xa1, 0xbc, 0xcd, 0x61, 0xcf, 0xc0, 0xea, 0x61, + 0xac, 0xbc, 0xde, 0xac, 0xd2, 0xa5, 0xaf, 0x58, 0xd2, 0xaa, 0xd2, 0xa8, 0xea, + 0x60, 0xd2, 0xa4, 0xd2, 0xa9, 0xd6, 0x61, 0xb2, 0x74, 0xc5, 0x7a, 0xd6, 0x65, + 0xd6, 0x69, 0xd6, 0x60, 0xf4, 0x6e, 0xda, 0x70, 0xa1, 0xbc, 0xb5, 0x54, 0xa1, + 0xbc, 0xa1, 0xbc, 0xda, 0x71, 0xba, 0xbc, 0xe2, 0xcb, 0xbc, 0xfb, 0xe6, 0x79, + 0xea, 0x5e, 0xed, 0x65, 0xf5, 0xdd, 0xa6, 0xdf, 0xb9, 0xd9, 0xb6, 0xb8, 0xb9, + 0xdb, 0xa1, 0xbc, 0xa1, 0xbc, 0xef, 0x4f, 0xb6, 0xbb, 0xf1, 0xad, 0xb6, 0xb9, + 0xdc, 0xae, 0xb6, 0xbd, 0xb9, 0x7e, 0xbb, 0xe8, 0xe8, 0xc1, 0xbe, 0x6c, 0xc0, + 0x5f, 0xa1, 0xbc, 0xc3, 0x49, 0xf3, 0xb1, 0xf3, 0xaf, 0xc4, 0x44, 0xa1, 0xbc, + 0xf5, 0x57, 0xa1, 0xbc, 0xc9, 0x79, 0xe5, 0x75, 0xca, 0xcd, 0xa9, 0xb4, 0xce, + 0xba, 0xab, 0xd6, 0xd5, 0x49, 0xb1, 0x67, 0xb1, 0x68, 0xd5, 0x4b, 0xbd, 0xe9, + 0xe1, 0xbc, 0xe1, 0xb6, 0xe5, 0x73, 0xe9, 0x72, 0xe9, 0x6f, 0xc1, 0x74, 0xa1, + 0xbc, 0xc9, 0x7b, 0xa6, 0xa4, 0xc4, 0x62, 0xbc, 0xad, 0xca, 0xdb, 0xe1, 0xd3, + 0xca, 0xdd, 0xca, 0xde, 0xb7, 0x5a, 0xb1, 0xa3, 0xb7, 0x5b, 0xa7, 0xd8, 0xca, + 0xd9, 0xa7, 0xd7, 0xcc, 0x7c, 0xa9, 0xc5, 0xcc, 0x7b, 0xa9, 0xcd, 0xa9, 0xc2, + 0xcc, 0xa9, 0xa9, 0xcb, 0xa9, 0xcc, 0xcc, 0xa2, 0xe9, 0x7d, 0xa9, 0xc9, 0xba, + 0x45, 0xec, 0xe6, 0xb4, 0x6c, 0xb7, 0x5f, 0xce, 0xcb, 0xab, 0xf1, 0xd9, 0x40, + 0xae, 0xaf, 0xae, 0xaa, 0xe1, 0xc7, 0xd1, 0xa7, 0xd1, 0xa8, 0xd1, 0xa5, 0xae, + 0xad, 0xd1, 0xaa, 0xb4, 0x67, 0xb1, 0xa2, 0xd5, 0x5e, 0xd5, 0x5c, 0xb1, 0xa6, + 0xb1, 0xa8, 0xb1, 0xab, 0xb1, 0x7c, 0xb7, 0x59, 0xe5, 0xa6, 0xb4, 0x6a, 0xb4, + 0x68, 0xb4, 0x6d, 0xb4, 0x73, 0xb4, 0x70, 0xdd, 0x68, 0xdd, 0x67, 0xba, 0x48, + 0xbc, 0xa9, 0xbc, 0xac, 0xbc, 0xa5, 0xa1, 0xbc, 0xbe, 0xcf, 0xc3, 0x6a, 0xa9, + 0xbd, 0xf1, 0x6f, 0xad, 0xac, 0xd8, 0x45, 0xc1, 0xf2, 0xb6, 0xa3, 0xb6, 0x7b, + 0xdc, 0x7a, 0xf6, 0x6b, 0xbe, 0x5b, 0xe8, 0xa7, 0xf9, 0xc4, 0xe8, 0xa6, 0xec, + 0x48, 0xec, 0x4b, 0xf1, 0xbe, 0xec, 0x4c, 0xec, 0x4e, 0xec, 0x46, 0xee, 0xf1, + 0xc1, 0xf0, 0xc2, 0xf3, 0xc2, 0xf5, 0xc2, 0xf6, 0xf5, 0x45, 0xa1, 0xbc, 0xc9, + 0x62, 0xa9, 0xcf, 0xa1, 0xbc, 0xc9, 0xfd, 0xc9, 0xfa, 0xc9, 0xfc, 0xf5, 0xd3, + 0xa8, 0x4a, 0xa8, 0x4e, 0xa8, 0x5c, 0xa8, 0x50, 0xa8, 0x51, 0xcb, 0x53, 0xa8, + 0x58, 0xa8, 0x5a, 0xa8, 0x59, 0xd9, 0xec, 0xcc, 0xf8, 0xcc, 0xf4, 0xcc, 0xf5, + 0xf2, 0x5d, 0xc3, 0x79, 0xaa, 0x74, 0xaa, 0x72, 0xa1, 0xbc, 0xaa, 0x7e, 0xaa, + 0x7d, 0xef, 0xf6, 0xcc, 0xf0, 0xcc, 0xf1, 0xaa, 0x62, 0xaa, 0x6c, 0xaa, 0x7b, + 0xae, 0xf9, 0xac, 0xa7, 0xac, 0xa8, 0xac, 0x7b, 0xaf, 0x48, 0xd9, 0xfe, 0xcf, + 0xa7, 0xcf, 0x77, 0xcf, 0x78, 0xac, 0xad, 0xac, 0xae, 0xe9, 0xf8, 0xac, 0xab, + 0xac, 0xac, 0xcf, 0x7a, 0xc2, 0x73, 0xe2, 0x71, 0xbc, 0xf1, 0xcf, 0x76, 0xd2, + 0x50, 0xd2, 0x4f, 0xd5, 0xe9, 0xe6, 0x5c, 0xd2, 0x55, 0xae, 0xfe, 0xaf, 0x4b, + 0xa1, 0xbc, 0xd2, 0x57, 0xd2, 0x5a, 0xd2, 0x46, 0xb2, 0x5a, 0xb2, 0x4e, 0xb2, + 0x58, 0xb2, 0x53, 0xc2, 0x70, 0xb2, 0x67, 0xd5, 0xed, 0xbf, 0x49, 0xb2, 0x68, + 0xd5, 0xf3, 0xb2, 0x46, 0xc2, 0x6e, 0xd5, 0xe1, 0xd5, 0xf1, 0xb2, 0x52, 0xd9, + 0xf1, 0xb4, 0xf3, 0xb5, 0x42, 0xda, 0x47, 0xde, 0x59, 0xb5, 0x47, 0xe2, 0xa9, + 0xda, 0x4b, 0xb4, 0xe6, 0xb4, 0xe8, 0xb4, 0xec, 0xb5, 0x44, 0xf9, 0xd0, 0xde, + 0x4c, 0xb7, 0xc2, 0xf5, 0xd4, 0xe2, 0xa5, 0xef, 0xef, 0xb7, 0xc1, 0xb7, 0xcc, + 0xde, 0x50, 0xa1, 0xbc, 0xde, 0x54, 0xe6, 0x5f, 0xb7, 0xcd, 0xde, 0x58, 0xde, + 0x46, 0xb7, 0xbc, 0xde, 0x48, 0xe6, 0x43, 0xf2, 0x5e, 0xc3, 0x74, 0xa1, 0xbc, + 0xba, 0xa8, 0xe2, 0xa3, 0xba, 0xaa, 0xe2, 0xa1, 0xc4, 0x6b, 0xef, 0xf5, 0xba, + 0xac, 0xe2, 0x75, 0xba, 0x78, 0xe6, 0x41, 0xe6, 0x40, 0xe6, 0x42, 0xbc, 0xe8, + 0xe6, 0x4c, 0xbc, 0xe0, 0xbc, 0xeb, 0xc3, 0x75, 0xea, 0x41, 0xbf, 0x43, 0xbf, + 0x46, 0xbf, 0x47, 0xbe, 0xfc, 0xc0, 0xe1, 0xc0, 0xe4, 0xed, 0x57, 0xc0, 0xda, + 0xc0, 0xde, 0xc3, 0x76, 0xf2, 0x63, 0xc3, 0x73, 0xf4, 0x65, 0xf4, 0x5c, 0xf8, + 0xaf, 0xc5, 0xf4, 0xa1, 0xbc, 0xc9, 0x73, 0xcc, 0x58, 0xcc, 0x57, 0xab, 0xc9, + 0xae, 0x66, 0xda, 0xac, 0xc4, 0xca, 0xba, 0x53, 0xb9, 0xed, 0xbc, 0x64, 0xeb, + 0x72, 0xbe, 0xc8, 0xee, 0xbf, 0xee, 0xaa, 0xa1, 0xbc, 0xcd, 0xce, 0xcd, 0xd1, + 0xad, 0x7e, 0xd0, 0xb5, 0xad, 0xa3, 0xc2, 0xe2, 0xad, 0x7b, 0xb3, 0x77, 0xad, + 0xa4, 0xb0, 0x6d, 0xd3, 0xef, 0xd7, 0xe3, 0xc5, 0xdd, 0xd7, 0xe4, 0xb3, 0x70, + 0xb3, 0x7c, 0xd7, 0xe7, 0xb6, 0x66, 0xb6, 0x6a, 0xdc, 0x4d, 0xdc, 0x4f, 0xe0, + 0xa1, 0xb9, 0x4e, 0xe0, 0x7d, 0xb9, 0x49, 0xbe, 0x43, 0xbb, 0xb8, 0xbb, 0xbd, + 0xbb, 0xbf, 0xbe, 0xe6, 0xbf, 0xee, 0xc1, 0xd8, 0xc1, 0xdb, 0xc2, 0xe4, 0xc2, + 0xe3, 0xc3, 0xe5, 0xa1, 0xbc, 0xb1, 0x6b, 0xce, 0xbd, 0xd8, 0xf4, 0xc9, 0x75, + 0xab, 0xa4, 0xae, 0x6a, 0xd4, 0xf3, 0xb4, 0x47, 0xe1, 0xa2, 0xc0, 0xab, 0xc4, + 0xf3, 0xd1, 0x79, 0xa9, 0xb8, 0xab, 0xda, 0xd7, 0x58, 0xb4, 0x5d, 0xf7, 0xa7, + 0xc9, 0x4b, 0xa6, 0x71, 0xa6, 0x6d, 0xa7, 0xb0, 0xbc, 0x61, 0xb9, 0xe1, 0xa7, + 0xad, 0xca, 0xb5, 0xa9, 0x6e, 0xd8, 0xb5, 0xa7, 0xac, 0xa7, 0xb1, 0xa9, 0x71, + 0xcc, 0x48, 0xa9, 0x6f, 0xa9, 0x6b, 0xa9, 0x63, 0xd4, 0xd5, 0xbc, 0x63, 0xce, + 0x67, 0xf6, 0xdc, 0xab, 0xbb, 0xab, 0xb9, 0xa1, 0xbc, 0xae, 0x5b, 0xae, 0x5c, + 0xb4, 0x45, 0xbc, 0x5f, 0xae, 0x50, 0xae, 0x58, 0xae, 0x55, 0xb0, 0xfe, 0xd4, + 0xd1, 0xb1, 0x44, 0xd4, 0xd0, 0xb1, 0x40, 0xb1, 0x41, 0xbc, 0x60, 0xa1, 0xbc, + 0xb6, 0xfe, 0xb4, 0x44, 0xb4, 0x40, 0xd8, 0xb8, 0xb6, 0xfc, 0xe1, 0x72, 0xb7, + 0x42, 0xe9, 0x54, 0xc0, 0xa7, 0xdc, 0xf7, 0xe1, 0x75, 0xb9, 0xe4, 0xe9, 0x52, + 0xb9, 0xe2, 0xb9, 0xdf, 0xb9, 0xe3, 0xe1, 0x6b, 0xbc, 0x5e, 0xe9, 0x51, 0xe9, + 0x58, 0xec, 0xd0, 0xc0, 0xa8, 0xc4, 0x5c, 0xc9, 0xd4, 0xa1, 0xbc, 0xa7, 0xb7, + 0xcc, 0x56, 0xb4, 0x46, 0xa4, 0x6d, 0xa4, 0x6e, 0xcc, 0x55, 0xe8, 0xca, 0xbe, + 0x6f, 0xbe, 0x74, 0xf5, 0x5f, 0xc5, 0xe6, 0xbe, 0x71, 0xe8, 0xce, 0xc5, 0xbb, + 0xf7, 0x7e, 0xc0, 0x63, 0xc6, 0x7a, 0xf1, 0xaf, 0xf1, 0xb2, 0xf1, 0xb6, 0xf6, + 0x7c, 0xf5, 0x63, 0xc4, 0x45, 0xf6, 0x7d, 0xf5, 0x61, 0xf5, 0x62, 0xc5, 0x59, + 0xf6, 0x7b, 0xf7, 0x7c, 0xc6, 0x6b, 0xf9, 0xb3, 0xa1, 0xbc, 0xac, 0xfa, 0xac, + 0xf4, 0xac, 0xf8, 0xd0, 0x4b, 0xf5, 0xe7, 0xaf, 0xc6, 0xaf, 0xc4, 0xd3, 0x56, + 0xd6, 0xe6, 0xb2, 0xd8, 0xb2, 0xd9, 0xbf, 0xa8, 0xb2, 0xd1, 0xb2, 0xd2, 0xd6, + 0xed, 0xa1, 0xbc, 0xda, 0xfb, 0xb5, 0xbc, 0xdf, 0x58, 0xdf, 0x60, 0xdf, 0x57, + 0xba, 0xf0, 0xba, 0xf6, 0xe3, 0x6e, 0xa1, 0xbc, 0xe3, 0x6c, 0xbd, 0x78, 0xba, + 0xfe, 0xe3, 0x71, 0xe3, 0x65, 0xba, 0xed, 0xba, 0xfd, 0xbd, 0x79, 0xe6, 0xe7, + 0xbd, 0x7b, 0xbd, 0x7a, 0xf0, 0x72, 0xe6, 0xeb, 0xe6, 0xec, 0xe6, 0xed, 0xea, + 0xd8, 0xe6, 0xe8, 0xbf, 0xa7, 0xbf, 0xa6, 0xea, 0xd0, 0xbf, 0xa5, 0xed, 0xd0, + 0xbf, 0x7e, 0xbf, 0xa1, 0xc4, 0x7d, 0xc1, 0x65, 0xc1, 0x67, 0xc1, 0x5d, 0xc1, + 0x5b, 0xc1, 0x62, 0xf5, 0xe9, 0xc2, 0xb7, 0xc2, 0xb9, 0xc5, 0xb7, 0xf4, 0xad, + 0xf2, 0xb2, 0xf2, 0xb4, 0xf9, 0x40, 0xa1, 0xbc, 0xbd, 0x42, 0xa1, 0xbc, 0xcd, + 0x72, 0xb0, 0x6f, 0xca, 0x45, 0xbf, 0x59, 0xde, 0xb3, 0xcd, 0x6a, 0xaa, 0xb3, + 0xaa, 0xb2, 0xcf, 0xc8, 0xc4, 0x6e, 0xac, 0xbf, 0xac, 0xc5, 0xac, 0xc4, 0xa1, + 0xbc, 0xcf, 0xc9, 0xd2, 0xad, 0xd2, 0xac, 0xb9, 0x7a, 0xb2, 0x78, 0xd2, 0xb2, + 0xd2, 0xb0, 0xaf, 0x5f, 0xc3, 0xa2, 0xb7, 0xe9, 0xe6, 0xa3, 0xb5, 0x58, 0xb7, + 0xeb, 0xb5, 0x61, 0xb5, 0x5b, 0xb5, 0x62, 0xda, 0x7c, 0xda, 0x7a, 0xda, 0x7b, + 0xb5, 0x60, 0xda, 0xa1, 0xb7, 0xe8, 0xb7, 0xec, 0xde, 0xb6, 0xb7, 0xe5, 0xb7, + 0xea, 0xc0, 0xf5, 0xba, 0xc1, 0xbd, 0x40, 0xbf, 0x58, 0xc4, 0xed, 0xbd, 0x41, + 0xe6, 0xa6, 0xe6, 0xa2, 0xbc, 0xfd, 0xbf, 0x5c, 0xc0, 0xf6, 0xc0, 0xf3, 0xed, + 0x69, 0xc2, 0x7a, 0xc5, 0xd0, 0xf4, 0x6f, 0xf1, 0xa4, 0xf3, 0xa5, 0xc3, 0xfc, + 0xcb, 0x42, 0xa8, 0x40, 0xa7, 0xfb, 0xcb, 0x43, 0xe2, 0x59, 0xf4, 0x55, 0xaa, + 0x4a, 0xaa, 0x57, 0xaa, 0x48, 0xcc, 0xd9, 0xa1, 0xbc, 0xaa, 0x53, 0xd9, 0xb3, + 0xbc, 0xd7, 0xb1, 0xfa, 0xaa, 0x44, 0xaa, 0x49, 0xaa, 0x56, 0xcf, 0x55, 0xc0, + 0xcd, 0xcf, 0x43, 0xf4, 0x53, 0xac, 0x5e, 0xac, 0x69, 0xf4, 0x56, 0xac, 0x6a, + 0xcf, 0x4a, 0xac, 0x63, 0xcf, 0x4c, 0xac, 0x6c, 0xb1, 0xf7, 0xcf, 0x61, 0xac, + 0x65, 0xac, 0x6b, 0xf2, 0x52, 0xce, 0xfb, 0xec, 0xf7, 0xd1, 0xdc, 0xd1, 0xdd, + 0xd9, 0xb2, 0xbe, 0xf8, 0xd1, 0xe8, 0xb7, 0xa9, 0xd1, 0xe9, 0xe2, 0x4e, 0xb1, + 0xf2, 0xd1, 0xeb, 0xa1, 0xbc, 0xbe, 0xec, 0xae, 0xec, 0xc0, 0xcc, 0xae, 0xe5, + 0xf7, 0xe1, 0xa1, 0xbc, 0xd1, 0xdb, 0xae, 0xdd, 0xb1, 0xeb, 0xd5, 0xc0, 0xd5, + 0xbe, 0xd5, 0xc1, 0xb1, 0xea, 0xd5, 0xc4, 0xf9, 0xbb, 0xb4, 0xd8, 0xd9, 0xc8, + 0xc3, 0x70, 0xe5, 0xde, 0xb4, 0xcd, 0xf7, 0xe2, 0xdd, 0xde, 0xd9, 0xca, 0xbc, + 0xcd, 0xdd, 0xd4, 0xb4, 0xd0, 0xd9, 0xb9, 0xdd, 0xce, 0xdd, 0xd2, 0xb7, 0xa3, + 0xdd, 0xd3, 0xb7, 0xaf, 0xc6, 0x56, 0xb7, 0xaa, 0xa1, 0xbc, 0xa1, 0xbc, 0xdd, + 0xdf, 0xdd, 0xe0, 0xba, 0x6c, 0xc4, 0x68, 0xc3, 0x71, 0xe2, 0x41, 0xf5, 0xd1, + 0xdd, 0xc9, 0xb7, 0xb0, 0xb7, 0xad, 0xba, 0x64, 0xe2, 0x49, 0xba, 0x66, 0xba, + 0x67, 0xba, 0x6b, 0xe2, 0x52, 0xe1, 0xfc, 0xba, 0x60, 0xe2, 0x54, 0xc2, 0x62, + 0xba, 0x5f, 0xf2, 0x4c, 0xe2, 0x4a, 0xe5, 0xd3, 0xc0, 0xce, 0xbc, 0xd8, 0xe5, + 0xcc, 0xe5, 0xe8, 0xf2, 0x55, 0xe5, 0xda, 0xbe, 0xf1, 0xe9, 0xc4, 0xc0, 0xd2, + 0xe9, 0xd1, 0xe9, 0xc8, 0xbe, 0xf6, 0xec, 0xfe, 0xc3, 0x72, 0xbe, 0xea, 0xe9, + 0xca, 0xbe, 0xef, 0xf2, 0x58, 0xed, 0x44, 0xc0, 0xd1, 0xec, 0xf5, 0xc0, 0xd0, + 0xa1, 0xbc, 0xb7, 0xdf, 0xe6, 0x76, 0xaa, 0x5c, 0xcf, 0x65, 0xbc, 0xdc, 0xcf, + 0x66, 0xe2, 0x66, 0xc0, 0xd4, 0xd5, 0xdc, 0xe9, 0xe3, 0xdd, 0xfb, 0xc2, 0x6c, + 0xe9, 0xe2, 0xb0, 0x62, 0xb3, 0x6d, 0xa1, 0xbc, 0xb6, 0x61, 0xf8, 0x47, 0xdc, + 0x40, 0xb6, 0x63, 0xdc, 0x48, 0xa1, 0xbc, 0xf7, 0x65, 0xdb, 0xfe, 0xb8, 0xfd, + 0xb8, 0xfe, 0xe0, 0x79, 0xe0, 0x78, 0xbb, 0xb3, 0xbd, 0xfb, 0xbd, 0xfe, 0xbd, + 0xf9, 0xbd, 0xfd, 0xbf, 0xea, 0xf1, 0x46, 0xc3, 0xe1, 0xa1, 0xbc, 0xcc, 0xb1, + 0xe1, 0xd7, 0xb1, 0xae, 0xb4, 0x75, 0xb7, 0x61, 0xb7, 0x60, 0xdd, 0x75, 0xdd, + 0x76, 0xe1, 0xd6, 0xbb, 0x4e, 0xbf, 0x5e, 0xd2, 0xbe, 0xde, 0xc0, 0xed, 0x72, + 0xed, 0x70, 0xf0, 0x49, 0xa1, 0xbc, 0xc9, 0xee, 0xc9, 0xed, 0xca, 0xf8, 0xa9, + 0xfe, 0xbe, 0xe8, 0xaa, 0x58, 0xcc, 0xca, 0xa9, 0xfd, 0xa9, 0xfb, 0xcd, 0x52, + 0xac, 0x54, 0xce, 0xf5, 0xce, 0xf6, 0xac, 0x52, 0xce, 0xeb, 0xbc, 0xca, 0xaf, + 0xcf, 0xd1, 0xd4, 0xbe, 0xe7, 0xae, 0xd0, 0xae, 0xcb, 0xb7, 0x75, 0xd5, 0xaa, + 0xa1, 0xbc, 0xb4, 0xbe, 0xb7, 0x79, 0xdd, 0xc0, 0xc0, 0xc7, 0xba, 0x5c, 0xe9, + 0xb4, 0xef, 0xdb, 0xc2, 0x60, 0xc4, 0x66, 0xc4, 0xe4, 0xb6, 0x4e, 0xdb, 0xea, + 0xdb, 0xe8, 0xb6, 0x4d, 0xf0, 0xf4, 0xb8, 0xed, 0xb8, 0xf0, 0xf6, 0x52, 0xbb, + 0xac, 0xe7, 0xec, 0xe4, 0x53, 0xa1, 0xbc, 0xe7, 0xee, 0xc1, 0xcc, 0xdb, 0xd1, + 0xc1, 0xbb, 0xe4, 0x44, 0xf7, 0x53, 0xbf, 0xcc, 0xee, 0x7a, 0xc2, 0xd1, 0xf2, + 0xf3, 0xcf, 0xbd, 0xa1, 0xbc, 0xa6, 0xc9, 0xa1, 0xbc, 0xac, 0xba, 0xd6, 0x5c, + 0xd6, 0x5f, 0xb5, 0x51, 0xda, 0x6c, 0xde, 0xa5, 0xa1, 0xbc, 0xba, 0xb9, 0xae, + 0xb2, 0xd5, 0x66, 0xd9, 0x54, 0xe1, 0xee, 0xc0, 0xbc, 0xac, 0xfe, 0xa1, 0xbc, + 0xd9, 0xe5, 0xb7, 0xb7, 0xe5, 0xf7, 0xde, 0x40, 0xbe, 0xfb, 0xf2, 0x5b, 0xe9, + 0xe8, 0xf6, 0xe7, 0xc9, 0x7e, 0xc9, 0xf7, 0xcb, 0x49, 0xcb, 0x4a, 0xcf, 0x6c, + 0xb4, 0xe3, 0xae, 0xf4, 0xd5, 0xdf, 0xba, 0x72, 0xa1, 0xbc, 0xb1, 0xd5, 0xa1, + 0xbc, 0xc3, 0x7c, 0xb7, 0xde, 0xbc, 0xf8, 0xac, 0xb8, 0xe7, 0x7e, 0xa6, 0x47, + 0xa1, 0xbc, 0xcb, 0x78, 0xa8, 0x77, 0xa1, 0xbc, 0xcc, 0xd2, 0xa1, 0xbc, 0xaa, + 0xd0, 0xaa, 0xd2, 0xcd, 0xb0, 0xaa, 0xd4, 0xa1, 0xbc, 0xc4, 0x67, 0xa1, 0xbc, + 0xa1, 0xbc, 0xc4, 0xa4, 0xad, 0x4b, 0xd0, 0x5b, 0xad, 0x48, 0xd0, 0x5f, 0xd0, + 0x67, 0xd0, 0x65, 0xce, 0xfa, 0xad, 0x4f, 0xd7, 0x48, 0xaf, 0xd6, 0xaf, 0xdb, + 0xaf, 0xda, 0xc1, 0x7a, 0xa1, 0xbc, 0xd3, 0x6a, 0xaf, 0xe2, 0xae, 0xd3, 0xa1, + 0xbc, 0xb3, 0x62, 0xdf, 0xa2, 0xd7, 0x4c, 0xd7, 0x4b, 0xd7, 0x45, 0xa1, 0xbc, + 0xa1, 0xbc, 0xb5, 0xcb, 0xb5, 0xcc, 0xb5, 0xcd, 0xa1, 0xbc, 0xa1, 0xbc, 0xb8, + 0x78, 0xdf, 0x73, 0xdf, 0x76, 0xa1, 0xbc, 0xe3, 0xa6, 0xa1, 0xbc, 0xdf, 0x7d, + 0xdc, 0xe6, 0xdc, 0xf9, 0xbb, 0x4a, 0xbb, 0x4d, 0xc2, 0xc1, 0xbc, 0xf0, 0xe6, + 0xfd, 0xa1, 0xbc, 0xed, 0xea, 0xc2, 0x61, 0xed, 0xeb, 0xed, 0xe8, 0xa1, 0xbc, + 0xea, 0xe9, 0xc2, 0x6a, 0xd5, 0xd8, 0xd9, 0xda, 0xdd, 0xf7, 0xdd, 0xf5, 0xbe, + 0xf9, 0xe4, 0xcd, 0xbb, 0xe3, 0xc1, 0xfc, 0xc4, 0x42, 0xf6, 0x74, 0xa1, 0xbc, + 0xc9, 0x5f, 0xdd, 0x62, 0xc1, 0xd4, 0xee, 0x7d, 0xb4, 0xb4, 0xf8, 0x7e, 0xc4, + 0xe3, 0xa9, 0xf3, 0xd1, 0xcf, 0xd1, 0xd1, 0xd1, 0xd0, 0xb1, 0xdc, 0xb1, 0xdd, + 0xd9, 0x7e, 0xba, 0x59, 0xb7, 0xd5, 0xde, 0x6d, 0xbf, 0x4c, 0xe2, 0xc4, 0xa1, + 0xbc, 0xa1, 0xbc, 0xcf, 0xae, 0xac, 0xaf, 0xcf, 0xb1, 0xea, 0x4d, 0xaf, 0x4c, + 0xd6, 0x51, 0xd6, 0x55, 0xbf, 0x54, 0xda, 0x5a, 0xda, 0x5d, 0xa1, 0xbc, 0xb7, + 0xd4, 0xb7, 0xdb, 0xa1, 0xbc, 0xde, 0x73, 0xa1, 0xbc, 0xde, 0x74, 0xa1, 0xbc, + 0xa1, 0xbc, 0xe6, 0x72, 0xe6, 0x69, 0xbc, 0xf7, 0xe6, 0x66, 0xc0, 0xee, 0xea, + 0x4f, 0xc0, 0xe6, 0xef, 0xfb, 0xf5, 0xda, 0xc6, 0x79, 0xa1, 0xbc, 0xc2, 0x76, + 0xb7, 0xd6, 0xbf, 0x51, 0xa9, 0xd1, 0xcc, 0xb2, 0xce, 0xd3, 0xb1, 0xaf, 0xb4, + 0x76, 0xa1, 0xbc, 0xaa, 0xc1, 0xac, 0xe6, 0xac, 0xe7, 0xd7, 0xb6, 0xd2, 0xe9, + 0xd2, 0xea, 0xaf, 0xae, 0xf2, 0xa5, 0xaf, 0xad, 0xaf, 0xa8, 0xba, 0xd5, 0xd6, + 0xbd, 0xb8, 0x52, 0xc1, 0x49, 0xe2, 0xf9, 0xe6, 0xcb, 0xc1, 0x48, 0xc5, 0xa1, + 0xca, 0xd7, 0xca, 0xd8, 0xef, 0xc8, 0xd1, 0x7c, 0xd1, 0x7d, 0xd1, 0x7e, 0xd1, + 0xa1, 0xae, 0x7e, 0xae, 0xa1, 0xe1, 0xc3, 0xb7, 0x5e, 0xb7, 0x5d, 0xbc, 0x7c, + 0xbe, 0xcd, 0xe9, 0x76, 0xc0, 0xb7, 0xc2, 0x56, 0xf9, 0xba, 0xa1, 0xbc, 0xa6, + 0xd6, 0xcc, 0xee, 0xed, 0x4f, 0xd9, 0xe7, 0xc1, 0x46, 0xcd, 0x7a, 0xe2, 0xee, + 0xcf, 0xf1, 0xda, 0xcf, 0xa1, 0xbc, 0xcf, 0xeb, 0xac, 0x48, 0xaf, 0xa2, 0xa1, + 0xbc, 0xaf, 0x7c, 0xa1, 0xbc, 0xc4, 0x72, 0xf5, 0xe2, 0xaf, 0xa4, 0xa1, 0xbc, + 0xaf, 0xa1, 0xd2, 0xda, 0xd2, 0xd9, 0xd2, 0xe2, 0xb2, 0xba, 0xda, 0xc9, 0xda, + 0xc6, 0xed, 0xa6, 0xd6, 0xb9, 0xd6, 0xbb, 0xa1, 0xbc, 0xd6, 0xb8, 0xda, 0xcb, + 0xbf, 0x6c, 0xb8, 0x50, 0xde, 0xe5, 0xde, 0xe4, 0xea, 0xa7, 0xde, 0xec, 0xba, + 0xd4, 0xe2, 0xeb, 0xa1, 0xbc, 0xe2, 0xf3, 0xe6, 0xc6, 0xa1, 0xbc, 0xe6, 0xca, + 0xbf, 0x6b, 0xed, 0xaa, 0xed, 0xab, 0xc1, 0x45, 0xf0, 0x58, 0xf4, 0x7d, 0xf2, + 0xa4, 0xf2, 0xa1, 0xf7, 0xce, 0xdc, 0xb0, 0xef, 0xb0, 0xf3, 0xf5, 0xcd, 0x77, + 0xcf, 0xe2, 0xa1, 0xbc, 0xac, 0xda, 0xac, 0xe0, 0xcf, 0xe0, 0xd2, 0xd6, 0xd2, + 0xd7, 0xd2, 0xd5, 0xd6, 0xaa, 0xd6, 0xb0, 0xd6, 0xb2, 0xb2, 0xb6, 0xb7, 0xfd, + 0xc2, 0xa5, 0xda, 0xbb, 0xa1, 0xbc, 0xde, 0xdd, 0xb8, 0x45, 0xb8, 0x46, 0xb8, + 0x44, 0xba, 0xcd, 0xe6, 0xbc, 0xba, 0xcc, 0xe2, 0xe7, 0xbd, 0x4f, 0xbd, 0x50, + 0xbf, 0x67, 0xbf, 0x65, 0xc0, 0xfd, 0xed, 0x7a, 0xc2, 0xa2, 0xcb, 0x6d, 0xcd, + 0x71, 0xac, 0xca, 0xac, 0xcb, 0xcf, 0xdb, 0xd2, 0xc1, 0xda, 0xae, 0xde, 0xc4, + 0xa1, 0xbc, 0xd0, 0x4d, 0xd3, 0x5c, 0xaf, 0xcb, 0xdb, 0xe0, 0xdf, 0x6a, 0xf2, + 0xbc, 0xa1, 0xbc, 0xbf, 0xa9, 0xc5, 0xf9, 0xed, 0xe3, 0xaf, 0x72, 0xbf, 0x64, + 0xf7, 0xf8, 0xa1, 0xbc, 0xd0, 0xc1, 0xd0, 0xc0, 0xb0, 0x7a, 0xb0, 0x78, 0xd4, + 0x42, 0xd8, 0x41, 0xb3, 0xa9, 0xd7, 0xfc, 0xeb, 0xea, 0xb3, 0xa6, 0xd7, 0xfd, + 0xa1, 0xbc, 0xdc, 0x67, 0xb9, 0x64, 0xb6, 0x7a, 0xb6, 0x78, 0xdc, 0x62, 0xdc, + 0x70, 0xdc, 0x6f, 0xdc, 0x64, 0xdc, 0x6a, 0xe0, 0xb1, 0xe0, 0xb2, 0xb9, 0x57, + 0xe0, 0xb3, 0xa1, 0xbc, 0xb9, 0x5a, 0xb9, 0x59, 0xe0, 0xb5, 0xe0, 0xbb, 0xe0, + 0xba, 0xb9, 0x66, 0xc5, 0xe0, 0xe0, 0xb0, 0xb9, 0x62, 0xe0, 0xae, 0xb9, 0x63, + 0xe0, 0xb7, 0xb9, 0x65, 0xc5, 0x4d, 0xbe, 0x52, 0xe4, 0x7b, 0xe4, 0x7a, 0xe4, + 0x7d, 0xe4, 0xa8, 0xe8, 0x68, 0xc4, 0xc2, 0xa1, 0xbc, 0xc5, 0x4c, 0xa1, 0xbc, + 0xe4, 0xa1, 0xf1, 0x5a, 0xbb, 0xcb, 0xe8, 0x6f, 0xe4, 0xb7, 0xf4, 0xf3, 0xbb, + 0xcd, 0xe4, 0xa6, 0xf3, 0x6a, 0xe4, 0xa2, 0xbf, 0xfe, 0xe4, 0xa3, 0xe0, 0xb6, + 0xf4, 0xe7, 0xbb, 0xcf, 0xe4, 0xa7, 0xf4, 0xf9, 0xeb, 0xe4, 0xe8, 0x69, 0xc3, + 0xf4, 0xa1, 0xbc, 0xbe, 0x59, 0xe8, 0x70, 0xe8, 0x72, 0xbe, 0x56, 0xe8, 0x6e, + 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xe8, 0x63, 0xe8, 0x6a, 0xe8, 0x76, 0xeb, + 0xe8, 0xeb, 0xe1, 0xa1, 0xbc, 0xeb, 0xe6, 0xa1, 0xbc, 0xeb, 0xe9, 0xc0, 0x43, + 0xc0, 0x44, 0xa1, 0xbc, 0xa1, 0xbc, 0xeb, 0xdf, 0xeb, 0xe0, 0xc0, 0x45, 0xc1, + 0xe6, 0xee, 0xd2, 0xee, 0xd6, 0xc1, 0xee, 0xee, 0xd0, 0xf1, 0x5c, 0xc1, 0xec, + 0xa1, 0xbc, 0xc3, 0xf3, 0xc3, 0xf2, 0xf4, 0xf0, 0xa1, 0xbc, 0xf3, 0x68, 0xc2, + 0xf0, 0xc5, 0x4f, 0xa1, 0xbc, 0xf1, 0x5e, 0xc2, 0xef, 0xf1, 0x53, 0xf7, 0x67, + 0xc3, 0xf0, 0xc3, 0xed, 0xc3, 0xee, 0xc3, 0xf1, 0xf3, 0x60, 0xc3, 0xeb, 0xf3, + 0x61, 0xc3, 0xe9, 0xf4, 0xec, 0xa1, 0xbc, 0xf4, 0xf5, 0xa1, 0xbc, 0xf4, 0xe8, + 0xf9, 0x53, 0xf4, 0xea, 0xa1, 0xbc, 0xf3, 0x66, 0xf4, 0xf1, 0xf7, 0x69, 0xc5, + 0x4e, 0xf6, 0x5e, 0xa1, 0xbc, 0xc5, 0xdf, 0xc1, 0xe9, 0xcf, 0xe8, 0xda, 0xc4, + 0xb9, 0x6e, 0xcf, 0xf9, 0xd2, 0xf1, 0xaf, 0xb0, 0xd2, 0xed, 0xa1, 0xbc, 0xb4, + 0x52, 0xda, 0xd8, 0xda, 0xd6, 0xb8, 0x5c, 0xb8, 0x5a, 0xe6, 0xd2, 0xbd, 0x5e, + 0xc2, 0xa8, 0xc2, 0x48, 0xc3, 0x4c, 0xf6, 0xf8, 0xac, 0xd4, 0xb2, 0xae, 0xb5, + 0x71, 0xde, 0xd5, 0xed, 0x78, 0xd2, 0xbc, 0xb2, 0x7d, 0xa8, 0x69, 0xb9, 0xa7, + 0xbb, 0xf0, 0xe8, 0xe9, 0xbe, 0x7d, 0xc0, 0x6c, 0xf3, 0xf0, 0xf9, 0xb7, 0xec, + 0xa9, 0xec, 0xae, 0xc5, 0xee, 0xef, 0x7b, 0xf7, 0xc1, 0xef, 0x7e, 0xef, 0xa2, + 0xc6, 0x7d, 0xf1, 0xd0, 0xf9, 0xcf, 0xc3, 0x5b, 0xf1, 0xd9, 0xf8, 0x71, 0xf1, + 0xcf, 0xc4, 0x4d, 0xa1, 0xbc, 0xc4, 0x4f, 0xf3, 0xed, 0xc4, 0x4c, 0xf5, 0x7c, + 0xf5, 0xa7, 0xa1, 0xbc, 0xa1, 0xbc, 0xf5, 0xad, 0xc5, 0x63, 0xf6, 0xb4, 0xc6, + 0x78, 0xc5, 0xc2, 0xf7, 0xba, 0xf8, 0x63, 0xf8, 0x6b, 0xf8, 0x6c, 0xf8, 0x66, + 0xa1, 0xbc, 0xc6, 0x4f, 0xc6, 0x7c, 0xa1, 0xbc, 0xcb, 0x6f, 0xf0, 0x4b, 0xc2, + 0x7e, 0xaa, 0xb7, 0xa1, 0xbc, 0xac, 0xd0, 0xaf, 0x69, 0xde, 0xcb, 0xaf, 0x6e, + 0xd2, 0xc6, 0xaf, 0x70, 0xd2, 0xc3, 0xa1, 0xbc, 0xaf, 0x6d, 0xa1, 0xbc, 0xb2, + 0xad, 0xb5, 0x69, 0xc0, 0xf7, 0xda, 0xb2, 0xda, 0xb5, 0xed, 0x77, 0xda, 0xaf, + 0xde, 0xc9, 0xb7, 0xf3, 0xde, 0xcc, 0xb7, 0xf5, 0xde, 0xcf, 0xb7, 0xef, 0xed, + 0x76, 0xe2, 0xdc, 0xe6, 0xb0, 0xe2, 0xdf, 0xe6, 0xaf, 0xa1, 0xbc, 0xe2, 0xdd, + 0xe6, 0xb1, 0xe6, 0xb7, 0xea, 0x70, 0xbd, 0x49, 0xbd, 0x43, 0xa1, 0xbc, 0xea, + 0x6c, 0xea, 0x73, 0xf6, 0xf4, 0xea, 0x71, 0xed, 0x74, 0xc5, 0x7d, 0xea, 0x6f, + 0xa1, 0xbc, 0xc4, 0xee, 0xa1, 0xbc, 0xf0, 0x4a, 0xc2, 0x7d, 0xc5, 0xf6, 0xa1, + 0xbc, 0xd6, 0xf6, 0xda, 0xdc, 0xcd, 0xa5, 0xaa, 0xc6, 0xcf, 0xfe, 0xd2, 0xf6, + 0xaf, 0xb7, 0xb2, 0xc0, 0xc4, 0x75, 0xb8, 0x5e, 0xe3, 0x4c, 0xe3, 0x4a, 0xea, + 0xb2, 0xe6, 0xd5, 0xa1, 0xbc, 0xd0, 0xae, 0xd3, 0xd4, 0xb0, 0x4d, 0xd3, 0xd7, + 0xb0, 0x4c, 0xd7, 0xb5, 0xc3, 0xcb, 0xdb, 0xcb, 0xdb, 0xca, 0xdb, 0xcf, 0xee, + 0x72, 0xdf, 0xf4, 0xf2, 0xf0, 0xf0, 0xd9, 0xe3, 0xf7, 0xbb, 0x75, 0xe3, 0xfc, + 0xbb, 0x74, 0xe3, 0xfa, 0xe4, 0x40, 0xbf, 0xca, 0xe7, 0xc8, 0xbd, 0xc8, 0xc1, + 0xb9, 0xbd, 0xca, 0xc4, 0xb0, 0xbf, 0xc9, 0xc1, 0xb7, 0xee, 0x75, 0xf4, 0xcb, + 0xf9, 0x4b, 0xa5, 0xd4, 0xad, 0x45, 0xe2, 0xe1, 0xb5, 0x72, 0xac, 0xe1, 0xa6, + 0xd4, 0xd0, 0x54, 0xd3, 0x66, 0xb2, 0xe0, 0xa1, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, + 0xbd, 0xa2, 0xed, 0xe7, 0xea, 0xe6, 0xbf, 0xae, 0xa1, 0xbc, 0xb5, 0xc0, 0xcd, + 0xaa, 0xd7, 0x43, 0xb2, 0xe2, 0xf4, 0xb2, 0xb5, 0xc1, 0xf0, 0x7c, 0xc1, 0x6d, + 0xb5, 0xf7, 0xdc, 0xac, 0xe0, 0xe0, 0xe0, 0xde, 0xbe, 0x65, 0xbe, 0x67, 0xbf, + 0x6f, 0xe8, 0xb8, 0xc0, 0x58, 0xc3, 0x45, 0xc3, 0x46, 0xf9, 0xae, 0xf5, 0x4f, + 0xf3, 0xa8, 0xc5, 0x56, 0xa1, 0xbc, 0xc6, 0x49, 0xca, 0x4f, 0xb0, 0x40, 0xcd, + 0xc8, 0xf0, 0xca, 0xf2, 0xe3, 0xad, 0x6b, 0xd0, 0xa8, 0xad, 0x6a, 0xd3, 0xba, + 0xd3, 0xbc, 0xd3, 0xc2, 0xb8, 0xc3, 0xc4, 0xae, 0xd3, 0xc8, 0xb0, 0x47, 0xb0, + 0x42, 0xb0, 0x43, 0xb0, 0x45, 0xb3, 0x46, 0xb3, 0x47, 0xb3, 0x48, 0xc4, 0xf7, + 0xd7, 0xa5, 0xd7, 0xa4, 0xb3, 0x4b, 0xb3, 0x4c, 0xb3, 0x4d, 0xf2, 0xde, 0xd7, + 0xab, 0xdb, 0xbc, 0xdf, 0xe6, 0xc2, 0xcc, 0xb5, 0xed, 0xeb, 0x6b, 0xb5, 0xf1, + 0xb8, 0xbb, 0xb5, 0xf2, 0xf4, 0xc5, 0xb5, 0xeb, 0xdb, 0xb1, 0xdb, 0xbf, 0xb8, + 0xc2, 0xb8, 0xbd, 0xdf, 0xea, 0xb8, 0xbc, 0xb8, 0xc4, 0xdf, 0xef, 0xdf, 0xec, + 0xe3, 0xd6, 0xbb, 0x66, 0xe3, 0xdb, 0xbb, 0x68, 0xe3, 0xda, 0xe3, 0xf2, 0xe3, + 0xe2, 0xc1, 0xb4, 0xbb, 0x69, 0xe3, 0xeb, 0xbb, 0x6d, 0xbb, 0x6c, 0xbb, 0x64, + 0xbd, 0xb8, 0xbb, 0x67, 0xa1, 0xbc, 0xf4, 0xc6, 0xe7, 0xbc, 0xbd, 0xbb, 0xa1, + 0xbc, 0xbd, 0xc1, 0xe7, 0xb8, 0xa1, 0xbc, 0xbd, 0xc2, 0xe7, 0xa2, 0xc1, 0xb2, + 0xe7, 0xa3, 0xbd, 0xbf, 0xe7, 0xba, 0xeb, 0x5e, 0xee, 0x67, 0xa1, 0xbc, 0xc1, + 0xaf, 0xc1, 0xb0, 0xeb, 0x60, 0xeb, 0x67, 0xee, 0x5a, 0xeb, 0x5d, 0xbf, 0xc0, + 0xc1, 0xb1, 0xf0, 0xc1, 0xee, 0x5d, 0xee, 0x5f, 0xc1, 0xae, 0xc1, 0xb5, 0xf0, + 0xc7, 0xee, 0x6e, 0xc1, 0xad, 0xc1, 0xac, 0xee, 0x69, 0xf0, 0xbe, 0xf0, 0xc0, + 0xc2, 0xcf, 0xa1, 0xbc, 0xf4, 0xc9, 0xf4, 0xc8, 0xc3, 0xca, 0xf2, 0xe7, 0xf6, + 0x42, 0xc4, 0xf9, 0xc5, 0xfb, 0xf9, 0x6e, 0xa6, 0xce, 0xc4, 0xa2, 0xc1, 0x6a, + 0xed, 0xe1, 0xaf, 0xe7, 0xaa, 0xc7, 0xac, 0xf2, 0xd3, 0x44, 0xbf, 0x77, 0xd3, + 0x40, 0xb8, 0x63, 0xd3, 0x45, 0xd6, 0xd7, 0xd3, 0x43, 0xd6, 0xcc, 0xd6, 0xdb, + 0xd6, 0xd4, 0xb2, 0xc6, 0xb2, 0xc8, 0xd6, 0xd6, 0xb2, 0xc1, 0xd6, 0xce, 0xd6, + 0xd1, 0xd6, 0xd2, 0xf8, 0xfb, 0xb2, 0xc7, 0xda, 0xe5, 0xed, 0xc3, 0xda, 0xe6, + 0xba, 0xe1, 0xda, 0xe2, 0xba, 0xe5, 0xb8, 0x61, 0xb8, 0x62, 0xa1, 0xbc, 0xa1, + 0xbc, 0xdf, 0x4b, 0xdf, 0x4e, 0xe3, 0x52, 0xed, 0xbd, 0xe6, 0xd7, 0xba, 0xe6, + 0xe6, 0xd9, 0xba, 0xe3, 0xf6, 0xfb, 0xe3, 0x58, 0xc2, 0xb0, 0xe3, 0x4f, 0xa1, + 0xbc, 0xc2, 0xad, 0xbd, 0x65, 0xc2, 0xb1, 0xbd, 0x68, 0xbd, 0x6a, 0xea, 0xba, + 0xea, 0xbd, 0xea, 0xbc, 0xbf, 0x7b, 0xea, 0xc1, 0xc1, 0x50, 0xc1, 0x4e, 0xa1, + 0xbc, 0xed, 0xbb, 0xf8, 0xb8, 0xed, 0xc2, 0xf0, 0x65, 0xc2, 0xaf, 0xf0, 0x68, + 0xc3, 0xb0, 0xc5, 0xa3, 0xc3, 0xb3, 0xaa, 0xd8, 0xd3, 0x70, 0xb2, 0xea, 0xbc, + 0xf3, 0xaf, 0xe5, 0xd3, 0xd0, 0xd0, 0x69, 0xad, 0x51, 0xf2, 0xc3, 0xa1, 0xbc, + 0xd3, 0x71, 0xaf, 0xea, 0xaf, 0xe9, 0xd7, 0x53, 0xf7, 0x46, 0xd7, 0x54, 0xd7, + 0x56, 0xa1, 0xbc, 0xdf, 0xa5, 0xdf, 0xa4, 0xbb, 0x53, 0xe7, 0x46, 0xed, 0xf1, + 0xf0, 0xa2, 0xf4, 0xb6, 0xd3, 0xda, 0xb8, 0xcd, 0xb3, 0x50, 0xb8, 0xca, 0xb8, + 0xc6, 0xc3, 0xce, 0xd6, 0xf4, 0xdf, 0x6d, 0xdf, 0x6e, 0xbd, 0x7e, 0xe6, 0xf3, + 0xbf, 0xaa, 0xaa, 0xc4, 0xae, 0xc5, 0xd3, 0x4a, 0xf5, 0xe6, 0xf8, 0xfd, 0xda, + 0xe8, 0xda, 0xe7, 0xdf, 0x54, 0xe3, 0x60, 0xba, 0xea, 0xc1, 0x58, 0xa1, 0xbc, + 0xe6, 0xe1, 0xa1, 0xbc, 0xe6, 0xe0, 0xe6, 0xdf, 0xea, 0xc9, 0xed, 0xcf, 0xa6, + 0xe1, 0xba, 0x5b, 0xac, 0xfd, 0xb2, 0xde, 0xb5, 0xbf, 0xe3, 0x7d, 0xbb, 0x42, + 0xe6, 0xf9, 0xbd, 0xa1, 0xbf, 0xad, 0xc1, 0x6b, 0xa6, 0xcd, 0xed, 0xde, 0xe3, + 0x75, 0xe3, 0x76, 0xed, 0xd9, 0xf9, 0x41, 0xbe, 0xa2, 0xc4, 0x54, 0xad, 0x76, + 0xdb, 0xed, 0xe0, 0x64, 0xe0, 0x5e, 0xf9, 0x6f, 0xb3, 0x69, 0xbd, 0xea, 0xd3, + 0xde, 0xb3, 0x61, 0xad, 0xaa, 0xd3, 0xfe, 0xd4, 0x40, 0xd4, 0x41, 0xdc, 0x5e, + 0xdc, 0x60, 0xdc, 0x5d, 0xa1, 0xbc, 0xb9, 0x55, 0xe0, 0xad, 0xc6, 0x6f, 0xf9, + 0x71, 0xe4, 0x73, 0xbb, 0xc6, 0xe4, 0x74, 0xa1, 0xbc, 0xe8, 0x5b, 0xeb, 0xd9, + 0xeb, 0xdb, 0xeb, 0xda, 0xee, 0xc6, 0xc1, 0xde, 0xf1, 0x52, 0xf3, 0x5f, 0xc3, + 0xe7, 0xf1, 0x51, 0xf4, 0xe4, 0xc4, 0xbf, 0xc5, 0x48, 0xa8, 0xa8, 0xf6, 0xc9, + 0xc4, 0xbb, 0xe0, 0x72, 0xe4, 0x60, 0xc2, 0xd9, 0xf1, 0x44, 0xd3, 0xe5, 0xd7, + 0xd9, 0xd7, 0xd6, 0xb3, 0x6c, 0xee, 0xbe, 0xdb, 0xf4, 0xdb, 0xfa, 0xb6, 0x5c, + 0xf7, 0x60, 0xb6, 0x59, 0xdb, 0xf6, 0xb6, 0x5f, 0xb6, 0x60, 0xe0, 0x69, 0xc3, + 0xdf, 0xc2, 0xde, 0xe0, 0x6e, 0xf7, 0x5f, 0xc5, 0x45, 0xb8, 0xf8, 0xe4, 0x57, + 0xe4, 0x5b, 0xe8, 0x40, 0xbd, 0xef, 0xbd, 0xf3, 0xc5, 0xae, 0xe7, 0xf7, 0xe7, + 0xf4, 0xc5, 0xad, 0xa1, 0xbc, 0xeb, 0xc0, 0xbf, 0xe5, 0xbf, 0xe6, 0xeb, 0xc4, + 0xbf, 0xe2, 0xc1, 0xce, 0xeb, 0xc5, 0xbf, 0xe4, 0xc6, 0x5c, 0xc2, 0xda, 0xc1, + 0xd1, 0xf7, 0x5d, 0xc3, 0xdd, 0xc3, 0xda, 0xf3, 0x53, 0xc3, 0xe0, 0xc4, 0xbd, + 0xc6, 0x6e, 0xf7, 0x5e, 0xf7, 0x61, 0xf9, 0x70, 0xf8, 0xc3, 0xcb, 0xa4, 0xb6, + 0x49, 0xb8, 0xe7, 0xe0, 0x5a, 0xf0, 0xf1, 0xee, 0xb7, 0xb1, 0xd8, 0xd7, 0xc6, + 0xc2, 0xd2, 0xdb, 0xd4, 0xe0, 0x43, 0xdf, 0xfd, 0xe4, 0x48, 0xf2, 0xf5, 0xb8, + 0xe4, 0xf0, 0xe7, 0xe8, 0xb0, 0xb3, 0xb8, 0xc6, 0x45, 0xb6, 0xb2, 0xbe, 0x5e, + 0xc5, 0xb4, 0xe8, 0xae, 0xc0, 0x50, 0xc0, 0x4b, 0xc3, 0xf9, 0xc6, 0x47, 0xc4, + 0xc5, 0xc5, 0xb5, 0xef, 0xb5, 0xc4, 0xd4, 0xf5, 0xbe, 0xf5, 0xbb, 0xc5, 0x68, + 0xc5, 0x69, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0x53, 0xe0, 0xef, 0xef, 0xb1, 0xf9, + 0x65, 0xab, 0x41, 0xd4, 0x47, 0xb9, 0x6d, 0xe0, 0xd5, 0xbb, 0xdc, 0xc2, 0xa3, + 0xf8, 0x41, 0xe4, 0xa9, 0xc6, 0x71, 0xe8, 0x74, 0xc3, 0xf5, 0xee, 0xde, 0xf3, + 0x6c, 0xee, 0xdc, 0xa1, 0xbc, 0xf8, 0xca, 0xbe, 0x7b, 0xe8, 0xdb, 0xf8, 0x5b, + 0xa1, 0xbc, 0xa1, 0xbc, 0xc6, 0x74, 0xbf, 0x71, 0xec, 0x7b, 0xc6, 0x4d, 0xec, + 0x7c, 0xc2, 0x44, 0xef, 0x6a, 0xc2, 0x43, 0xef, 0x6c, 0xf9, 0x5c, 0xc2, 0x42, + 0xf3, 0xd0, 0xf8, 0x58, 0xf1, 0xc7, 0xf9, 0xce, 0xc5, 0xbf, 0xf7, 0xae, 0xf6, + 0xad, 0xf7, 0xb2, 0xc3, 0x58, 0xc3, 0x54, 0xf1, 0xc3, 0xc3, 0x56, 0xc4, 0x4a, + 0xf3, 0xc7, 0xf3, 0xc8, 0xf3, 0xd6, 0xf3, 0xcb, 0xc4, 0x49, 0xa1, 0xbc, 0xf3, + 0xcd, 0xf3, 0xce, 0xc4, 0x4b, 0xa1, 0xbc, 0xf3, 0xcf, 0xa1, 0xbc, 0xf5, 0x6b, + 0xc6, 0x73, 0xc4, 0xcf, 0xf5, 0x6e, 0xf5, 0x76, 0xa1, 0xbc, 0xa1, 0xbc, 0xf7, + 0xb4, 0xc5, 0x5f, 0xf6, 0xae, 0xc5, 0x60, 0xf6, 0xaf, 0xf7, 0xaf, 0xc5, 0xc0, + 0xf7, 0xab, 0xc5, 0xc1, 0xa1, 0xbc, 0xa1, 0xbc, 0xc5, 0xed, 0xc5, 0xeb, 0xf8, + 0x57, 0xf8, 0xd7, 0xbb, 0xde, 0xbb, 0xdf, 0xc5, 0xb6, 0xa1, 0xbc, 0xec, 0x56, + 0xc6, 0x69, 0xf1, 0x7c, 0xc2, 0xfd, 0xa1, 0xbc, 0xa1, 0xbc, 0xe4, 0xda, 0xbb, + 0xeb, 0xbe, 0x75, 0xf6, 0xbc, 0xa1, 0xbc, 0xa1, 0xbc, 0xc0, 0x66, 0xc3, 0x4e, + 0xf1, 0xb9, 0xc5, 0x5c, 0xf3, 0xc1, 0xc6, 0x62, 0xf8, 0xd4, 0xc5, 0xea, 0xbe, + 0x79, 0xe8, 0xd9, 0xc6, 0x4c, 0xc3, 0x52, 0xef, 0x69, 0xc3, 0x53, 0xc5, 0x5e, + 0xc5, 0x57, 0xc5, 0xe4, 0xc3, 0x4b, 0xc5, 0xb9, 0xf7, 0x76, 0xd4, 0x49, 0xb9, + 0xa6, 0xbb, 0xec, 0xbe, 0x77, 0xe8, 0xd4, 0xc0, 0x67, 0xc0, 0x68, 0xec, 0x70, + 0xf1, 0xbb, 0xa1, 0xbc, 0xc6, 0x4b, 0xf8, 0x55, 0xc6, 0x63, 0xbb, 0xf2, 0xbe, + 0xa3, 0xed, 0xdd, 0xb9, 0xa8, 0xec, 0xb1, 0xec, 0xaf, 0xc2, 0x47, 0xc4, 0x51, + 0xc3, 0xef, 0xc5, 0x65, 0xc5, 0xef, 0xc2, 0x4c, 0xc2, 0x4a, 0xc2, 0x4b, 0xc3, + 0x5c, 0xf1, 0xe0, 0xa1, 0xbc, 0xc6, 0x75, 0xf5, 0xb6, 0xf5, 0xb4, 0xf8, 0x76, + 0xc5, 0x66, 0xef, 0xb4, 0xc3, 0x5e, 0xc4, 0xd3, 0xc5, 0xc4, 0xf8, 0x7b, 0xec, + 0xb8, 0xc2, 0x4d, 0xa1, 0xbc, +}; + +unsigned char FQTermConvert::BtoG[] = { + 0xa1, 0xa1, 0xa3, 0xac, 0xa1, 0xa2, 0xa1, 0xa3, 0xa3, 0xae, 0xa3, 0xae, 0xa3, + 0xbb, 0xa3, 0xba, 0xa3, 0xbf, 0xa3, 0xa1, 0xa1, 0xc3, 0xa1, 0xad, 0xa1, 0xa7, + 0xa3, 0xac, 0xa1, 0xa2, 0xa1, 0xa4, 0xa1, 0xa4, 0xa3, 0xbb, 0xa3, 0xba, 0xa3, + 0xbf, 0xa3, 0xa1, 0xa3, 0xfc, 0xa1, 0xf5, 0xa3, 0xfc, 0xa1, 0xf5, 0xa3, 0xfc, + 0xa3, 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa3, 0xa8, 0xa3, 0xa9, 0xa3, 0xa8, 0xa3, + 0xa9, 0xa3, 0xfb, 0xa3, 0xfd, 0xa3, 0xfb, 0xa3, 0xfd, 0xa1, 0xb2, 0xa1, 0xb3, + 0xa1, 0xb2, 0xa1, 0xb3, 0xa1, 0xbe, 0xa1, 0xbf, 0xa1, 0xbe, 0xa1, 0xbf, 0xa1, + 0xb6, 0xa1, 0xb7, 0xa1, 0xb6, 0xa1, 0xb7, 0xa1, 0xb4, 0xa1, 0xb5, 0xa3, 0xde, + 0xa1, 0xb5, 0xa1, 0xb8, 0xa1, 0xb9, 0xa1, 0xb8, 0xa1, 0xb9, 0xa1, 0xba, 0xa1, + 0xbb, 0xa1, 0xba, 0xa1, 0xbb, 0xa3, 0xa8, 0xa3, 0xa9, 0xa3, 0xfb, 0xa3, 0xfd, + 0xa3, 0xdb, 0xa3, 0xdd, 0xa1, 0xae, 0xa1, 0xaf, 0xa1, 0xb0, 0xa1, 0xb1, 0xa3, + 0xa2, 0xa1, 0xe5, 0xa3, 0xe0, 0xa1, 0xe4, 0xa3, 0xa3, 0xa3, 0xa6, 0xa3, 0xaa, + 0xa1, 0xf9, 0xa1, 0xec, 0xa1, 0xa8, 0xa1, 0xf0, 0xa1, 0xf1, 0xa1, 0xf7, 0xa1, + 0xf8, 0xa1, 0xf2, 0xa1, 0xee, 0xa1, 0xef, 0xa1, 0xf3, 0xa1, 0xf4, 0xa1, 0xf5, + 0xa1, 0xf6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xa5, 0xa1, + 0xf5, 0xa3, 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa3, 0xa3, 0xa3, 0xa6, 0xa3, 0xaa, 0xa3, 0xab, 0xa3, + 0xad, 0xa1, 0xc1, 0xa1, 0xc2, 0xa1, 0xc0, 0xa1, 0xcc, 0xa3, 0xbc, 0xa3, 0xbe, + 0xa3, 0xbd, 0xa1, 0xdc, 0xa1, 0xdd, 0xa1, 0xd9, 0xa1, 0xde, 0xa1, 0xd6, 0xa1, + 0xd4, 0xa3, 0xab, 0xa3, 0xad, 0xa3, 0xbc, 0xa3, 0xbe, 0xa3, 0xbd, 0xa1, 0xab, + 0xa1, 0xc9, 0xa1, 0xc8, 0xa1, 0xf5, 0xa1, 0xcf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xd2, 0xa1, 0xd3, 0xa1, 0xdf, 0xa1, 0xe0, 0xa1, 0xe2, + 0xa1, 0xe1, 0xa1, 0xf5, 0xa1, 0xd1, 0xa1, 0xfc, 0xa1, 0xfd, 0xa1, 0xfb, 0xa1, + 0xfa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xac, 0xa1, 0xf5, + 0xa3, 0xaf, 0xa3, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xe7, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xe9, 0xa1, 0xea, 0xa3, 0xa5, 0xa3, 0xc0, 0xa1, 0xe6, 0xa1, 0xf5, + 0xa1, 0xe7, 0xa3, 0xa5, 0xa3, 0xc0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xe3, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa9, 0xe0, 0xa9, 0xd8, + 0xa9, 0xd0, 0xa9, 0xc8, 0xa9, 0xc0, 0xa1, 0xf5, 0xa1, 0xaa, 0xa9, 0xa6, 0xa1, + 0xf5, 0xa9, 0xb0, 0xa9, 0xb4, 0xa9, 0xb8, 0xa9, 0xbc, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xfe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa3, 0xb0, 0xa3, 0xb1, 0xa3, 0xb2, 0xa3, 0xb3, 0xa3, 0xb4, 0xa3, 0xb5, 0xa3, + 0xb6, 0xa3, 0xb7, 0xa3, 0xb8, 0xa3, 0xb9, 0xa2, 0xf1, 0xa2, 0xf2, 0xa2, 0xf3, + 0xa2, 0xf4, 0xa2, 0xf5, 0xa2, 0xf6, 0xa2, 0xf7, 0xa2, 0xf8, 0xa2, 0xf9, 0xa2, + 0xfa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa3, + 0xc1, 0xa3, 0xc2, 0xa3, 0xc3, 0xa3, 0xc4, 0xa3, 0xc5, 0xa3, 0xc6, 0xa3, 0xc7, + 0xa3, 0xc8, 0xa3, 0xc9, 0xa3, 0xca, 0xa3, 0xcb, 0xa3, 0xcc, 0xa3, 0xcd, 0xa3, + 0xce, 0xa3, 0xcf, 0xa3, 0xd0, 0xa3, 0xd1, 0xa3, 0xd2, 0xa3, 0xd3, 0xa3, 0xd4, + 0xa3, 0xd5, 0xa3, 0xd6, 0xa3, 0xd7, 0xa3, 0xd8, 0xa3, 0xd9, 0xa3, 0xda, 0xa3, + 0xe1, 0xa3, 0xe2, 0xa3, 0xe3, 0xa3, 0xe4, 0xa3, 0xe5, 0xa3, 0xe6, 0xa3, 0xe7, + 0xa3, 0xe8, 0xa3, 0xe9, 0xa3, 0xea, 0xa3, 0xeb, 0xa3, 0xec, 0xa3, 0xed, 0xa3, + 0xee, 0xa3, 0xef, 0xa3, 0xf0, 0xa3, 0xf1, 0xa3, 0xf2, 0xa3, 0xf3, 0xa3, 0xf4, + 0xa3, 0xf5, 0xa3, 0xf6, 0xa3, 0xf7, 0xa3, 0xf8, 0xa3, 0xf9, 0xa3, 0xfa, 0xa6, + 0xa1, 0xa6, 0xa2, 0xa6, 0xa3, 0xa6, 0xa4, 0xa6, 0xa5, 0xa6, 0xa6, 0xa6, 0xa7, + 0xa6, 0xa8, 0xa6, 0xa9, 0xa6, 0xaa, 0xa1, 0xc4, 0xa6, 0xac, 0xa6, 0xad, 0xa6, + 0xae, 0xa6, 0xaf, 0xa1, 0xc7, 0xa6, 0xb1, 0xa1, 0xc6, 0xa6, 0xb3, 0xa6, 0xb4, + 0xa6, 0xb5, 0xa6, 0xb6, 0xa6, 0xb7, 0xa6, 0xb8, 0xa6, 0xc1, 0xa6, 0xc2, 0xa6, + 0xc3, 0xa6, 0xc4, 0xa6, 0xc5, 0xa6, 0xc6, 0xa6, 0xc7, 0xa6, 0xc8, 0xa6, 0xc9, + 0xa6, 0xca, 0xa6, 0xcb, 0xa6, 0xcc, 0xa6, 0xcd, 0xa6, 0xce, 0xa6, 0xcf, 0xa6, + 0xd0, 0xa6, 0xd1, 0xa6, 0xd2, 0xa6, 0xd3, 0xa6, 0xd4, 0xa6, 0xd5, 0xa6, 0xd6, + 0xa6, 0xd7, 0xa6, 0xd8, 0xa8, 0xc5, 0xa8, 0xc6, 0xa8, 0xc7, 0xa8, 0xc8, 0xa8, + 0xc9, 0xa8, 0xca, 0xa8, 0xcb, 0xa8, 0xcc, 0xa8, 0xcd, 0xa8, 0xce, 0xa8, 0xcf, + 0xa8, 0xd0, 0xa8, 0xd1, 0xa8, 0xd2, 0xa8, 0xd3, 0xa8, 0xd4, 0xa8, 0xd5, 0xa8, + 0xd6, 0xa8, 0xd7, 0xa8, 0xd8, 0xa8, 0xd9, 0xa8, 0xda, 0xa8, 0xdb, 0xa8, 0xdc, + 0xa8, 0xdd, 0xa8, 0xde, 0xa8, 0xdf, 0xa8, 0xe0, 0xa8, 0xe1, 0xa8, 0xe2, 0xa8, + 0xe3, 0xa8, 0xe4, 0xa8, 0xe5, 0xa8, 0xe6, 0xa8, 0xe7, 0xa8, 0xe8, 0xa8, 0xe9, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd2, 0xbb, 0xd2, 0xd2, 0xb6, 0xa1, 0xc6, + 0xdf, 0xc4, 0xcb, 0xbe, 0xc5, 0xc1, 0xcb, 0xb6, 0xfe, 0xc8, 0xcb, 0xb6, 0xf9, + 0xc8, 0xeb, 0xb0, 0xcb, 0xbc, 0xb8, 0xb5, 0xb6, 0xb5, 0xf3, 0xc1, 0xa6, 0xd8, + 0xb0, 0xca, 0xae, 0xb2, 0xb7, 0xd3, 0xd6, 0xc8, 0xfd, 0xcf, 0xc2, 0xd5, 0xc9, + 0xc9, 0xcf, 0xd1, 0xbe, 0xcd, 0xe8, 0xb7, 0xb2, 0xbe, 0xc3, 0xc3, 0xb4, 0xd2, + 0xb2, 0xc6, 0xf2, 0xd3, 0xda, 0xcd, 0xf6, 0xd8, 0xa3, 0xc8, 0xd0, 0xc9, 0xd7, + 0xc7, 0xa7, 0xb2, 0xe6, 0xbf, 0xda, 0xcd, 0xc1, 0xca, 0xbf, 0xcf, 0xa6, 0xb4, + 0xf3, 0xc5, 0xae, 0xd7, 0xd3, 0xe6, 0xdd, 0xe6, 0xde, 0xb4, 0xe7, 0xd0, 0xa1, + 0xde, 0xcc, 0xca, 0xac, 0xc9, 0xbd, 0xb4, 0xa8, 0xb9, 0xa4, 0xbc, 0xba, 0xd2, + 0xd1, 0xcb, 0xc8, 0xbd, 0xed, 0xb8, 0xc9, 0xde, 0xc3, 0xdf, 0xae, 0xb9, 0xad, + 0xb2, 0xc5, 0xb3, 0xf3, 0xd8, 0xa4, 0xb2, 0xbb, 0xd6, 0xd0, 0xb7, 0xe1, 0xb5, + 0xa4, 0xd6, 0xae, 0xd2, 0xfc, 0xd3, 0xe8, 0xd4, 0xc6, 0xbe, 0xae, 0xbb, 0xa5, + 0xce, 0xe5, 0xbf, 0xba, 0xc8, 0xca, 0xca, 0xb2, 0xd8, 0xea, 0xc6, 0xcd, 0xb3, + 0xf0, 0xc8, 0xd4, 0xbd, 0xf1, 0xbd, 0xe9, 0xd8, 0xc6, 0xd4, 0xaa, 0xd4, 0xca, + 0xc4, 0xda, 0xc1, 0xf9, 0xd9, 0xe2, 0xb9, 0xab, 0xc8, 0xdf, 0xd0, 0xd7, 0xb7, + 0xd6, 0xc7, 0xd0, 0xd8, 0xd7, 0xd4, 0xc8, 0xb9, 0xb4, 0xce, 0xf0, 0xbb, 0xaf, + 0xc6, 0xa5, 0xce, 0xe7, 0xc9, 0xfd, 0xd8, 0xa6, 0xb1, 0xe5, 0xb6, 0xf2, 0xd3, + 0xd1, 0xbc, 0xb0, 0xb7, 0xb4, 0xc8, 0xc9, 0xcc, 0xec, 0xb7, 0xf2, 0xcc, 0xab, + 0xd8, 0xb2, 0xbf, 0xd7, 0xc9, 0xd9, 0xd3, 0xc8, 0xb3, 0xdf, 0xcd, 0xcd, 0xb0, + 0xcd, 0xbb, 0xc3, 0xd8, 0xa5, 0xb5, 0xf5, 0xd2, 0xfd, 0xd0, 0xc4, 0xb8, 0xea, + 0xbb, 0xa7, 0xca, 0xd6, 0xd4, 0xfa, 0xd6, 0xa7, 0xce, 0xc4, 0xb6, 0xb7, 0xbd, + 0xef, 0xb7, 0xbd, 0xc8, 0xd5, 0xd4, 0xbb, 0xd4, 0xc2, 0xc4, 0xbe, 0xc7, 0xb7, + 0xd6, 0xb9, 0xb4, 0xf5, 0xce, 0xe3, 0xb1, 0xc8, 0xc3, 0xab, 0xca, 0xcf, 0xcb, + 0xae, 0xbb, 0xf0, 0xd7, 0xa6, 0xb8, 0xb8, 0xd8, 0xb3, 0xc6, 0xac, 0xd1, 0xc0, + 0xc5, 0xa3, 0xc8, 0xae, 0xcd, 0xf5, 0xb1, 0xfb, 0xca, 0xc0, 0xd8, 0xa7, 0xc7, + 0xd2, 0xc7, 0xf0, 0xd6, 0xf7, 0xd5, 0xa7, 0xb7, 0xa6, 0xba, 0xf5, 0xd2, 0xd4, + 0xb8, 0xb6, 0xd7, 0xd0, 0xca, 0xcb, 0xcb, 0xfb, 0xd5, 0xcc, 0xb4, 0xfa, 0xc1, + 0xee, 0xcf, 0xc9, 0xd8, 0xf0, 0xb3, 0xe4, 0xd0, 0xd6, 0xc8, 0xbd, 0xb2, 0xe1, + 0xb6, 0xac, 0xb0, 0xbc, 0xb3, 0xf6, 0xcd, 0xb9, 0xbf, 0xaf, 0xbc, 0xd3, 0xb9, + 0xa6, 0xb0, 0xfc, 0xb4, 0xd2, 0xb1, 0xb1, 0xd4, 0xd1, 0xc7, 0xaa, 0xb0, 0xeb, + 0xbb, 0xdc, 0xbf, 0xa8, 0xd5, 0xbc, 0xc3, 0xae, 0xd8, 0xb4, 0xc8, 0xa5, 0xbf, + 0xc9, 0xb9, 0xc5, 0xd3, 0xd2, 0xd5, 0xd9, 0xb6, 0xa3, 0xdf, 0xb5, 0xdf, 0xb6, + 0xb5, 0xf0, 0xcb, 0xbe, 0xd8, 0xcf, 0xbd, 0xd0, 0xc1, 0xed, 0xd6, 0xbb, 0xca, + 0xb7, 0xdf, 0xb3, 0xcc, 0xa8, 0xbe, 0xe4, 0xb0, 0xc8, 0xdf, 0xb7, 0xcb, 0xc4, + 0xc7, 0xf4, 0xcd, 0xe2, 0xd1, 0xeb, 0xca, 0xa7, 0xc5, 0xab, 0xc4, 0xcc, 0xd4, + 0xd0, 0xcb, 0xfc, 0xc4, 0xe1, 0xbe, 0xde, 0xc7, 0xc9, 0xd7, 0xf3, 0xca, 0xd0, + 0xb2, 0xbc, 0xc6, 0xbd, 0xd3, 0xd7, 0xdb, 0xcd, 0xba, 0xeb, 0xb8, 0xa5, 0xb1, + 0xd8, 0xce, 0xec, 0xb4, 0xf2, 0xc8, 0xd3, 0xb0, 0xc7, 0xc6, 0xcb, 0xb3, 0xe2, + 0xb5, 0xa9, 0xca, 0xf5, 0xb1, 0xbe, 0xce, 0xb4, 0xc4, 0xa9, 0xd4, 0xfd, 0xd5, + 0xfd, 0xc4, 0xb8, 0xc3, 0xf1, 0xd8, 0xb5, 0xd3, 0xc0, 0xd6, 0xad, 0xcd, 0xa1, + 0xb7, 0xba, 0xb7, 0xb8, 0xd0, 0xfe, 0xd3, 0xf1, 0xb9, 0xcf, 0xcd, 0xdf, 0xb8, + 0xca, 0xc9, 0xfa, 0xd3, 0xc3, 0xcb, 0xa6, 0xcc, 0xef, 0xd3, 0xc9, 0xbc, 0xd7, + 0xc9, 0xea, 0xf1, 0xe2, 0xb0, 0xd7, 0xc6, 0xa4, 0xc3, 0xf3, 0xc4, 0xbf, 0xc3, + 0xac, 0xca, 0xb8, 0xca, 0xaf, 0xca, 0xbe, 0xba, 0xcc, 0xd1, 0xa8, 0xc1, 0xa2, + 0xd8, 0xa9, 0xb6, 0xaa, 0xc6, 0xb9, 0xc5, 0xd2, 0xd8, 0xc0, 0xd8, 0xa8, 0xbd, + 0xbb, 0xd2, 0xe0, 0xba, 0xa5, 0xb7, 0xc2, 0xd8, 0xf8, 0xbb, 0xef, 0xd2, 0xc1, + 0xb7, 0xf2, 0xce, 0xe9, 0xb7, 0xa5, 0xd0, 0xdd, 0xb7, 0xfc, 0xd6, 0xd9, 0xbc, + 0xfe, 0xc8, 0xce, 0xd1, 0xf6, 0xd8, 0xf2, 0xb7, 0xdd, 0xc6, 0xf3, 0xa1, 0xf5, + 0xb9, 0xe2, 0xd0, 0xd7, 0xd5, 0xd7, 0xcf, 0xc8, 0xc8, 0xab, 0xb9, 0xb2, 0xd4, + 0xd9, 0xb1, 0xf9, 0xc1, 0xd0, 0xd0, 0xcc, 0xbb, 0xae, 0xd8, 0xd8, 0xeb, 0xbe, + 0xc1, 0xd3, 0xd0, 0xd9, 0xbf, 0xef, 0xbd, 0xb3, 0xd3, 0xa1, 0xce, 0xa3, 0xbc, + 0xaa, 0xc0, 0xf4, 0xcd, 0xac, 0xb5, 0xf5, 0xcd, 0xc2, 0xd3, 0xf5, 0xb4, 0xe7, + 0xb8, 0xf7, 0xcf, 0xf2, 0xc3, 0xfb, 0xba, 0xcf, 0xb3, 0xd4, 0xba, 0xf3, 0xdf, + 0xba, 0xdf, 0xb8, 0xd2, 0xf2, 0xbb, 0xd8, 0xe0, 0xee, 0xdb, 0xda, 0xb5, 0xd8, + 0xd4, 0xda, 0xb9, 0xe7, 0xdb, 0xd8, 0xdb, 0xdd, 0xdb, 0xd7, 0xd9, 0xed, 0xb6, + 0xe0, 0xd2, 0xc4, 0xbf, 0xe4, 0xcd, 0xfd, 0xbc, 0xe9, 0xe5, 0xfa, 0xba, 0xc3, + 0xcb, 0xfd, 0xc8, 0xe7, 0xe5, 0xf9, 0xd7, 0xd6, 0xb4, 0xe6, 0xd3, 0xee, 0xca, + 0xd8, 0xd5, 0xac, 0xb0, 0xb2, 0xcb, 0xc2, 0xbc, 0xe2, 0xd2, 0xd9, 0xd6, 0xdd, + 0xb7, 0xab, 0xb2, 0xa2, 0xc4, 0xea, 0xca, 0xbd, 0xb3, 0xda, 0xc3, 0xa6, 0xe2, + 0xe2, 0xc8, 0xd6, 0xd0, 0xe7, 0xca, 0xf9, 0xb3, 0xc9, 0xbf, 0xdb, 0xbf, 0xb8, + 0xcd, 0xd0, 0xca, 0xd5, 0xd4, 0xe7, 0xd6, 0xbc, 0xd1, 0xae, 0xd0, 0xf1, 0xc7, + 0xfa, 0xd2, 0xb7, 0xd3, 0xd0, 0xd0, 0xe0, 0xc6, 0xd3, 0xd6, 0xec, 0xb6, 0xe4, + 0xb4, 0xce, 0xb4, 0xcb, 0xcb, 0xc0, 0xc4, 0xca, 0xc8, 0xea, 0xba, 0xb9, 0xce, + 0xdb, 0xbd, 0xad, 0xb3, 0xd8, 0xcf, 0xab, 0xc9, 0xc7, 0xce, 0xdb, 0xd1, 0xb4, + 0xa1, 0xf5, 0xb7, 0xba, 0xbb, 0xd2, 0xc4, 0xb2, 0xea, 0xf2, 0xb0, 0xd9, 0xd6, + 0xf1, 0xc3, 0xd7, 0xf4, 0xe9, 0xf3, 0xbe, 0xd1, 0xf2, 0xd3, 0xf0, 0xc0, 0xcf, + 0xbf, 0xbc, 0xb6, 0xf8, 0xf1, 0xe7, 0xb6, 0xfa, 0xed, 0xb2, 0xc8, 0xe2, 0xc0, + 0xdf, 0xbc, 0xa1, 0xb3, 0xbc, 0xd7, 0xd4, 0xd6, 0xc1, 0xbe, 0xca, 0xc9, 0xe0, + 0xe2, 0xb6, 0xd6, 0xdb, 0xf4, 0xde, 0xc9, 0xab, 0xb0, 0xac, 0xb3, 0xe6, 0xd1, + 0xaa, 0xd0, 0xd0, 0xd2, 0xc2, 0xce, 0xf7, 0xda, 0xe4, 0xb4, 0xae, 0xba, 0xe0, + 0xce, 0xbb, 0xd7, 0xa1, 0xd8, 0xf9, 0xd9, 0xa2, 0xd8, 0xfa, 0xb0, 0xe9, 0xb7, + 0xf0, 0xba, 0xce, 0xb9, 0xc0, 0xd7, 0xf4, 0xd3, 0xd3, 0xd9, 0xa4, 0xcb, 0xc5, + 0xc9, 0xec, 0xb5, 0xe8, 0xd5, 0xbc, 0xcb, 0xc6, 0xb5, 0xab, 0xd3, 0xb6, 0xd7, + 0xf7, 0xc4, 0xe3, 0xb2, 0xae, 0xb5, 0xcd, 0xc1, 0xe6, 0xd3, 0xe0, 0xd8, 0xfe, + 0xb2, 0xbc, 0xd8, 0xfd, 0xb6, 0xd2, 0xbf, 0xcb, 0xc3, 0xe2, 0xb1, 0xf8, 0xd2, + 0xb1, 0xc0, 0xe4, 0xb1, 0xf0, 0xc5, 0xd0, 0xc0, 0xfb, 0xc9, 0xbe, 0xc5, 0xd9, + 0xbd, 0xd9, 0xd6, 0xfa, 0xc5, 0xac, 0xdb, 0xbe, 0xcf, 0xbb, 0xbc, 0xb4, 0xc2, + 0xd1, 0xc1, 0xdf, 0xbf, 0xd4, 0xcd, 0xcc, 0xce, 0xe1, 0xb7, 0xf1, 0xb3, 0xdf, + 0xb0, 0xc9, 0xb4, 0xf4, 0xdf, 0xc0, 0xce, 0xe2, 0xb3, 0xca, 0xc2, 0xc0, 0xbe, + 0xfd, 0xb7, 0xd4, 0xb8, 0xe6, 0xb4, 0xb5, 0xce, 0xc7, 0xce, 0xfc, 0xcb, 0xb1, + 0xb3, 0xb3, 0xc4, 0xc5, 0xb7, 0xcd, 0xba, 0xf0, 0xd1, 0xbd, 0xd6, 0xa8, 0xba, + 0xac, 0xd2, 0xf7, 0xcc, 0xfd, 0xb4, 0xd1, 0xc0, 0xa7, 0xb6, 0xda, 0xe0, 0xf1, + 0xb7, 0xbb, 0xbf, 0xd3, 0xd6, 0xb7, 0xcc, 0xae, 0xbe, 0xf9, 0xbf, 0xb2, 0xbb, + 0xf8, 0xd7, 0xf8, 0xbb, 0xb5, 0xdb, 0xdf, 0xd7, 0xb3, 0xbc, 0xd0, 0xd7, 0xb1, + 0xb6, 0xca, 0xb7, 0xc1, 0xe6, 0xa4, 0xe5, 0xfe, 0xc3, 0xee, 0xd1, 0xfd, 0xe5, + 0xfb, 0xe6, 0xa5, 0xbc, 0xcb, 0xc8, 0xd1, 0xcd, 0xd7, 0xd0, 0xa2, 0xd7, 0xce, + 0xe6, 0xda, 0xd8, 0xc3, 0xcd, 0xea, 0xcb, 0xce, 0xba, 0xea, 0xde, 0xce, 0xbe, + 0xd6, 0xc6, 0xa8, 0xc4, 0xf2, 0xce, 0xb2, 0xe1, 0xaa, 0xe1, 0xaf, 0xb2, 0xed, + 0xe1, 0xa7, 0xce, 0xd7, 0xcf, 0xa3, 0xd0, 0xf2, 0xb1, 0xd3, 0xb4, 0xb2, 0xcd, + 0xa2, 0xc5, 0xaa, 0xb5, 0xdc, 0xcd, 0xae, 0xd0, 0xce, 0xe1, 0xdd, 0xd2, 0xdb, + 0xcd, 0xfc, 0xbc, 0xc9, 0xd6, 0xbe, 0xc8, 0xcc, 0xb3, 0xc0, 0xbf, 0xec, 0xe2, + 0xee, 0xe2, 0xec, 0xbd, 0xe4, 0xce, 0xd2, 0xb3, 0xad, 0xbf, 0xb9, 0xb6, 0xb6, + 0xbc, 0xbc, 0xb7, 0xf6, 0xbe, 0xf1, 0xc5, 0xa4, 0xb0, 0xd1, 0xb6, 0xf3, 0xd5, + 0xd2, 0xc5, 0xfa, 0xb0, 0xe2, 0xca, 0xe3, 0xb3, 0xb6, 0xd5, 0xdb, 0xb0, 0xe7, + 0xcd, 0xb6, 0xd7, 0xa5, 0xd2, 0xd6, 0xa1, 0xf5, 0xb8, 0xc4, 0xb9, 0xa5, 0xd8, + 0xfc, 0xba, 0xb5, 0xb8, 0xfc, 0xca, 0xf8, 0xc0, 0xee, 0xd0, 0xd3, 0xb2, 0xc4, + 0xb4, 0xe5, 0xb6, 0xc5, 0xd5, 0xc8, 0xe8, 0xbd, 0xc9, 0xbc, 0xb8, 0xcb, 0xb8, + 0xdc, 0xe8, 0xbc, 0xa1, 0xf5, 0xb2, 0xbd, 0xc3, 0xbf, 0xc7, 0xf3, 0xb9, 0xaf, + 0xc9, 0xb3, 0xc7, 0xdf, 0xc9, 0xf2, 0xb3, 0xc1, 0xe3, 0xe4, 0xc5, 0xe6, 0xcd, + 0xf4, 0xbe, 0xf6, 0xe3, 0xe5, 0xcc, 0xad, 0xe3, 0xe7, 0xe3, 0xe8, 0xb3, 0xe5, + 0xc3, 0xbb, 0xc6, 0xfb, 0xce, 0xd6, 0xbc, 0xb3, 0xb7, 0xda, 0xe3, 0xea, 0xe3, + 0xec, 0xe3, 0xeb, 0xa1, 0xf5, 0xe3, 0xe6, 0xa1, 0xf5, 0xd2, 0xca, 0xd4, 0xee, + 0xd7, 0xc6, 0xd4, 0xd6, 0xbe, 0xc4, 0xc0, 0xce, 0xc4, 0xb5, 0xcb, 0xfc, 0xb5, + 0xd2, 0xbf, 0xf1, 0xbe, 0xc1, 0xf0, 0xae, 0xb8, 0xa6, 0xc4, 0xd0, 0xb5, 0xe9, + 0xd4, 0xed, 0xb6, 0xa2, 0xd2, 0xd3, 0xcb, 0xbd, 0xd0, 0xe3, 0xcd, 0xba, 0xbe, + 0xbf, 0xcf, 0xb5, 0xba, 0xb1, 0xd0, 0xa4, 0xeb, 0xc1, 0xb8, 0xce, 0xd6, 0xe2, + 0xb8, 0xd8, 0xb6, 0xc7, 0xd3, 0xfd, 0xc1, 0xbc, 0xc3, 0xa2, 0xd3, 0xf3, 0xc9, + 0xd6, 0xbc, 0xfb, 0xbd, 0xc7, 0xd1, 0xd4, 0xb9, 0xc8, 0xb6, 0xb9, 0xf5, 0xb9, + 0xb1, 0xb4, 0xb3, 0xe0, 0xd7, 0xdf, 0xd7, 0xe3, 0xc9, 0xed, 0xb3, 0xb5, 0xd0, + 0xc1, 0xb3, 0xbd, 0xd3, 0xd8, 0xe5, 0xc6, 0xd1, 0xb8, 0xc6, 0xf9, 0xd1, 0xb2, + 0xd2, 0xd8, 0xd0, 0xcf, 0xd0, 0xb0, 0xb0, 0xee, 0xc4, 0xc7, 0xd3, 0xcf, 0xb2, + 0xc9, 0xc0, 0xef, 0xb7, 0xc0, 0xc8, 0xee, 0xda, 0xe5, 0xda, 0xe6, 0xa1, 0xf5, + 0xb2, 0xa2, 0xb9, 0xd4, 0xc8, 0xe9, 0xca, 0xc2, 0xd0, 0xa9, 0xd1, 0xc7, 0xcf, + 0xed, 0xbe, 0xa9, 0xd1, 0xf0, 0xd2, 0xc0, 0xca, 0xcc, 0xbc, 0xd1, 0xca, 0xb9, + 0xc0, 0xd0, 0xb9, 0xa9, 0xc0, 0xfd, 0xc0, 0xb4, 0xd9, 0xa9, 0xb0, 0xdb, 0xb2, + 0xa2, 0xb3, 0xde, 0xc5, 0xe5, 0xd9, 0xac, 0xc2, 0xd8, 0xd9, 0xab, 0xd9, 0xaa, + 0xd9, 0xa7, 0xa1, 0xf5, 0xcd, 0xc3, 0xb6, 0xf9, 0xd9, 0xee, 0xc1, 0xbd, 0xbe, + 0xdf, 0xc6, 0xe4, 0xb5, 0xe4, 0xd9, 0xfd, 0xba, 0xaf, 0xbf, 0xcc, 0xc8, 0xaf, + 0xcb, 0xa2, 0xb4, 0xcc, 0xb5, 0xbd, 0xb9, 0xce, 0xd6, 0xc6, 0xb6, 0xe7, 0xdb, + 0xc0, 0xa1, 0xf5, 0xd7, 0xe4, 0xd0, 0xad, 0xd7, 0xbf, 0xb1, 0xb0, 0xd8, 0xd4, + 0xbe, 0xed, 0xd0, 0xb6, 0xd0, 0xf4, 0xc8, 0xa1, 0xca, 0xe5, 0xca, 0xdc, 0xce, + 0xb6, 0xba, 0xc7, 0xbf, 0xa7, 0xc5, 0xde, 0xb9, 0xbe, 0xbe, 0xd7, 0xc9, 0xeb, + 0xdf, 0xc8, 0xdf, 0xcd, 0xd6, 0xe4, 0xc5, 0xd8, 0xba, 0xf4, 0xb8, 0xc0, 0xdf, + 0xc9, 0xdf, 0xce, 0xba, 0xcd, 0xdf, 0xcb, 0xc4, 0xd8, 0xd6, 0xdc, 0xd5, 0xa6, + 0xc3, 0xfc, 0xbe, 0xcc, 0xb9, 0xcc, 0xc0, 0xac, 0xbf, 0xc0, 0xc6, 0xba, 0xdb, + 0xe1, 0xc6, 0xc2, 0xcc, 0xb9, 0xc0, 0xa4, 0xdb, 0xe5, 0xd2, 0xb9, 0xb7, 0xee, + 0xc6, 0xe6, 0xc4, 0xce, 0xd1, 0xd9, 0xb1, 0xbc, 0xe6, 0xaa, 0xc6, 0xde, 0xce, + 0xaf, 0xc3, 0xc3, 0xc4, 0xdd, 0xb9, 0xc3, 0xc4, 0xb7, 0xbd, 0xe3, 0xe6, 0xa9, + 0xca, 0xbc, 0xd0, 0xd5, 0xe6, 0xa2, 0xe6, 0xa8, 0xc4, 0xe3, 0xe6, 0xa6, 0xa1, + 0xf5, 0xc3, 0xcf, 0xb9, 0xc2, 0xbc, 0xbe, 0xd7, 0xda, 0xb6, 0xa8, 0xb9, 0xd9, + 0xd2, 0xcb, 0xd6, 0xe6, 0xcd, 0xf0, 0xc9, 0xd0, 0xc7, 0xfc, 0xbe, 0xd3, 0xbd, + 0xec, 0xe1, 0xba, 0xb8, 0xd4, 0xb0, 0xb6, 0xd1, 0xd2, 0xe1, 0xb6, 0xe1, 0xb7, + 0xd4, 0xc0, 0xc1, 0xb1, 0xd6, 0xe3, 0xcc, 0xfb, 0xc5, 0xc1, 0xb2, 0xaf, 0xe0, + 0xfb, 0xd0, 0xd2, 0xb8, 0xfd, 0xb5, 0xea, 0xb8, 0xae, 0xb5, 0xd7, 0xe2, 0xd2, + 0xd1, 0xd3, 0xcf, 0xd2, 0xbb, 0xa1, 0xe5, 0xf3, 0xcd, 0xf9, 0xd5, 0xf7, 0xb7, + 0xf0, 0xb1, 0xcb, 0xe3, 0xc3, 0xd6, 0xd2, 0xba, 0xf6, 0xc4, 0xee, 0xb7, 0xde, + 0xe2, 0xf3, 0xd5, 0xfa, 0xc7, 0xd3, 0xe2, 0xf0, 0xb2, 0xc0, 0xb9, 0xd6, 0xc5, + 0xc2, 0xe2, 0xf9, 0xd0, 0xd4, 0xe2, 0xf5, 0xe2, 0xf6, 0xe2, 0xf2, 0xbb, 0xf2, + 0xe3, 0xde, 0xb7, 0xbf, 0xec, 0xe5, 0xcb, 0xf9, 0xb3, 0xd0, 0xc0, 0xad, 0xb0, + 0xe8, 0xd6, 0xf4, 0xc3, 0xf2, 0xb7, 0xf7, 0xc4, 0xa8, 0xbe, 0xdc, 0xd5, 0xd0, + 0xc5, 0xfb, 0xcd, 0xd8, 0xb0, 0xce, 0xc5, 0xd7, 0xc4, 0xe9, 0xc5, 0xea, 0xb3, + 0xe9, 0xd1, 0xba, 0xb9, 0xd5, 0xd7, 0xbe, 0xc4, 0xb4, 0xc5, 0xc4, 0xb5, 0xd6, + 0xde, 0xd5, 0xb1, 0xa7, 0xbe, 0xd0, 0xcd, 0xcf, 0xde, 0xd6, 0xb2, 0xf0, 0xcc, + 0xa7, 0xc1, 0xe0, 0xb7, 0xc5, 0xb8, 0xab, 0xd3, 0xda, 0xcd, 0xfa, 0xce, 0xf4, + 0xd2, 0xd7, 0xb2, 0xfd, 0xc0, 0xa5, 0xb0, 0xba, 0xc3, 0xf7, 0xea, 0xc0, 0xbb, + 0xe8, 0xea, 0xbf, 0xea, 0xbb, 0xc9, 0xfd, 0xb7, 0xfe, 0xc5, 0xf3, 0xba, 0xbc, + 0xe8, 0xca, 0xd5, 0xed, 0xb6, 0xab, 0xb9, 0xfb, 0xe8, 0xc3, 0xe8, 0xcb, 0xe8, + 0xc1, 0xd6, 0xa6, 0xc1, 0xd6, 0xb1, 0xad, 0xbd, 0xdc, 0xb0, 0xe5, 0xcd, 0xf7, + 0xcb, 0xc9, 0xce, 0xf6, 0xe8, 0xc6, 0xc3, 0xb6, 0xa1, 0xf5, 0xe8, 0xcc, 0xe8, + 0xc2, 0xea, 0xbd, 0xd0, 0xc0, 0xce, 0xe4, 0xc6, 0xe7, 0xe9, 0xe2, 0xc3, 0xa5, + 0xb7, 0xd5, 0xc6, 0xfc, 0xd7, 0xa2, 0xd3, 0xbe, 0xe3, 0xfb, 0xc3, 0xda, 0xc4, + 0xe0, 0xba, 0xd3, 0xb9, 0xc1, 0xd5, 0xb4, 0xd5, 0xd3, 0xb2, 0xa8, 0xc4, 0xad, + 0xb7, 0xa8, 0xe3, 0xfc, 0xb7, 0xd0, 0xd0, 0xb9, 0xd3, 0xcd, 0xbf, 0xf6, 0xbe, + 0xda, 0xe3, 0xf4, 0xc7, 0xf6, 0xe3, 0xf3, 0xd1, 0xd8, 0xd6, 0xce, 0xc5, 0xdd, + 0xb7, 0xba, 0xb2, 0xb4, 0xa1, 0xf5, 0xe3, 0xfd, 0xa1, 0xf5, 0xe3, 0xf7, 0xe3, + 0xf6, 0xbf, 0xbb, 0xd1, 0xd7, 0xb3, 0xb4, 0xb4, 0xb6, 0xd6, 0xcb, 0xc5, 0xc0, + 0xd5, 0xf9, 0xb0, 0xd6, 0xb0, 0xe6, 0xc4, 0xc1, 0xce, 0xef, 0xd7, 0xb4, 0xe1, + 0xf2, 0xbe, 0xd1, 0xb9, 0xb7, 0xba, 0xfc, 0xcd, 0xe6, 0xe7, 0xe5, 0xe7, 0xe4, + 0xc3, 0xb5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xde, 0xb8, 0xed, 0xbe, 0xce, 0xb5, + 0xc4, 0xd3, 0xdb, 0xc3, 0xa4, 0xd6, 0xb1, 0xd6, 0xaa, 0xce, 0xf9, 0xc9, 0xe7, + 0xec, 0xeb, 0xc6, 0xee, 0xb1, 0xfc, 0xf4, 0xcc, 0xbf, 0xd5, 0xf1, 0xb7, 0xf3, + 0xc3, 0xbe, 0xc0, 0xd8, 0xe8, 0xc7, 0xbc, 0xd8, 0xc2, 0xd5, 0xdf, 0xb7, 0xce, + 0xb7, 0xca, 0xd6, 0xab, 0xeb, 0xc5, 0xb9, 0xc9, 0xeb, 0xc6, 0xbc, 0xe7, 0xeb, + 0xc8, 0xb7, 0xbe, 0xbf, 0xcf, 0xce, 0xd4, 0xf4, 0xa7, 0xc9, 0xe1, 0xb7, 0xbc, + 0xd6, 0xa5, 0xdc, 0xbd, 0xb0, 0xc5, 0xd1, 0xbf, 0xdc, 0xcf, 0xc7, 0xdb, 0xbb, + 0xa8, 0xb7, 0xd2, 0xbd, 0xe6, 0xd0, 0xbe, 0xdc, 0xbf, 0xa1, 0xf5, 0xdc, 0xc1, + 0xdc, 0xc0, 0xdc, 0xc6, 0xbb, 0xa2, 0xca, 0xad, 0xb3, 0xf5, 0xb1, 0xed, 0xd4, + 0xfe, 0xd3, 0xad, 0xb7, 0xb5, 0xbd, 0xfc, 0xc9, 0xdb, 0xdb, 0xa1, 0xc7, 0xf1, + 0xda, 0xfd, 0xb2, 0xc9, 0xbd, 0xf0, 0xb3, 0xa4, 0xc3, 0xc5, 0xb8, 0xb7, 0xcd, + 0xd3, 0xb0, 0xa2, 0xd7, 0xe8, 0xb8, 0xbd, 0xda, 0xe9, 0xf6, 0xbf, 0xd3, 0xea, + 0xc7, 0xe0, 0xb7, 0xc7, 0xd8, 0xbd, 0xcd, 0xa4, 0xc1, 0xc1, 0xd0, 0xc5, 0xc7, + 0xd6, 0xba, 0xee, 0xb1, 0xe3, 0xcf, 0xc0, 0xd9, 0xb8, 0xc7, 0xce, 0xb1, 0xa3, + 0xb4, 0xd9, 0xc2, 0xc2, 0xb7, 0xfd, 0xd9, 0xb9, 0xbf, 0xa1, 0xcb, 0xd7, 0xce, + 0xea, 0xc0, 0xfe, 0xb6, 0xed, 0xcf, 0xb5, 0xd9, 0xb5, 0xd9, 0xde, 0xd3, 0xe1, + 0xbe, 0xd6, 0xd9, 0xf0, 0xc3, 0xb0, 0xeb, 0xd0, 0xb9, 0xda, 0xc9, 0xb2, 0xcc, + 0xea, 0xcf, 0xf7, 0xc7, 0xb0, 0xd8, 0xdd, 0xbf, 0xcb, 0xd4, 0xf2, 0xd3, 0xc2, + 0xc3, 0xe3, 0xb2, 0xaa, 0xbe, 0xa2, 0xd9, 0xe9, 0xc4, 0xcf, 0xc8, 0xb4, 0xba, + 0xf1, 0xc5, 0xd1, 0xd2, 0xa7, 0xb0, 0xa7, 0xd7, 0xc9, 0xb0, 0xa5, 0xd4, 0xd5, + 0xcf, 0xcc, 0xdf, 0xd7, 0xbf, 0xc8, 0xcd, 0xdb, 0xdf, 0xd3, 0xd1, 0xca, 0xdf, + 0xe4, 0xc6, 0xb7, 0xba, 0xe5, 0xb9, 0xfe, 0xbf, 0xa9, 0xe5, 0xeb, 0xd4, 0xdb, + 0xdf, 0xdd, 0xdf, 0xe3, 0xdf, 0xd6, 0xdf, 0xde, 0xe0, 0xf3, 0xb4, 0xb9, 0xd0, + 0xcd, 0xdb, 0xf3, 0xd4, 0xab, 0xb9, 0xb8, 0xb3, 0xc7, 0xbf, 0xe5, 0xdb, 0xf2, + 0xde, 0xc8, 0xc6, 0xf5, 0xd7, 0xe0, 0xbf, 0xfc, 0xdb, 0xbc, 0xbd, 0xaa, 0xe6, + 0xb0, 0xd7, 0xcb, 0xe6, 0xaf, 0xd2, 0xcc, 0xcd, 0xde, 0xc0, 0xd1, 0xd6, 0xb6, + 0xd2, 0xa6, 0xbc, 0xe9, 0xcd, 0xfe, 0xd2, 0xf6, 0xba, 0xa2, 0xd0, 0xfb, 0xbb, + 0xc2, 0xca, 0xd2, 0xbf, 0xcd, 0xe5, 0xb6, 0xb7, 0xe2, 0xca, 0xba, 0xc6, 0xc1, + 0xca, 0xac, 0xce, 0xdd, 0xd6, 0xc5, 0xe1, 0xbc, 0xcf, 0xef, 0xb5, 0xdb, 0xcb, + 0xa7, 0xa1, 0xf5, 0xd3, 0xc4, 0xe2, 0xd4, 0xb6, 0xc8, 0xbd, 0xa8, 0xde, 0xc4, + 0xe5, 0xf4, 0xd1, 0xe5, 0xba, 0xdc, 0xb4, 0xfd, 0xbb, 0xb2, 0xc2, 0xc9, 0xe1, + 0xdf, 0xba, 0xf3, 0xe1, 0xe0, 0xc5, 0xad, 0xcb, 0xbc, 0xb5, 0xa1, 0xbc, 0xb1, + 0xd4, 0xf5, 0xd4, 0xb9, 0xbb, 0xd0, 0xc7, 0xa1, 0xba, 0xde, 0xbb, 0xd6, 0xba, + 0xe3, 0xca, 0xd1, 0xcc, 0xf1, 0xb6, 0xb2, 0xe3, 0xa1, 0xd0, 0xf4, 0xb1, 0xe2, + 0xb0, 0xdd, 0xcd, 0xda, 0xb0, 0xb4, 0xc6, 0xb4, 0xca, 0xc3, 0xb3, 0xd6, 0xde, + 0xd7, 0xd7, 0xa7, 0xd6, 0xb8, 0xb9, 0xb0, 0xbf, 0xbd, 0xd5, 0xfc, 0xc0, 0xa8, + 0xca, 0xb0, 0xcb, 0xa9, 0xcc, 0xf4, 0xb9, 0xd2, 0xd5, 0xfe, 0xb9, 0xca, 0xed, + 0xbd, 0xca, 0xa9, 0xbc, 0xc8, 0xb4, 0xba, 0xd5, 0xd1, 0xd3, 0xb3, 0xc3, 0xc1, + 0xca, 0xc7, 0xd0, 0xc7, 0xd7, 0xf2, 0xea, 0xc5, 0xa1, 0xf5, 0xea, 0xc2, 0xca, + 0xc1, 0xc8, 0xbe, 0xd6, 0xf9, 0xc8, 0xe1, 0xc4, 0xb3, 0xbc, 0xed, 0xbc, 0xdc, + 0xbf, 0xdd, 0xd5, 0xa4, 0xe8, 0xd1, 0xbf, 0xc2, 0xb1, 0xfa, 0xb8, 0xcc, 0xb9, + 0xd5, 0xe8, 0xd6, 0xb2, 0xe9, 0xe8, 0xdb, 0xb0, 0xd8, 0xd7, 0xf5, 0xc1, 0xf8, + 0xe8, 0xd2, 0xe8, 0xd4, 0xe8, 0xdc, 0xe8, 0xd8, 0xc6, 0xe2, 0xcd, 0xe1, 0xd1, + 0xea, 0xb4, 0xf9, 0xb6, 0xce, 0xb6, 0xbe, 0xc5, 0xfe, 0xb7, 0xfa, 0xc8, 0xaa, + 0xd1, 0xf3, 0xd6, 0xde, 0xba, 0xe9, 0xc1, 0xf7, 0xbd, 0xf2, 0xe4, 0xa3, 0xb6, + 0xfd, 0xb6, 0xb4, 0xcf, 0xb4, 0xbb, 0xee, 0xc7, 0xa2, 0xc5, 0xc9, 0xd0, 0xda, + 0xc2, 0xe5, 0xb1, 0xc3, 0xe4, 0xa1, 0xe4, 0xa2, 0xa1, 0xf5, 0xd0, 0xb9, 0xe4, + 0xac, 0xe4, 0xad, 0xe4, 0xa9, 0xe4, 0xaa, 0xec, 0xc5, 0xce, 0xaa, 0xb1, 0xfe, + 0xbe, 0xe6, 0xbe, 0xbc, 0xcc, 0xbf, 0xd5, 0xa8, 0xc5, 0xda, 0xa1, 0xf5, 0xeb, + 0xbc, 0xc9, 0xfc, 0xea, 0xf4, 0xb5, 0xd6, 0xe1, 0xf7, 0xba, 0xdd, 0xbd, 0xc6, + 0xe7, 0xe8, 0xc9, 0xba, 0xb2, 0xa3, 0xc1, 0xe1, 0xd5, 0xe4, 0xe7, 0xea, 0xe7, + 0xe9, 0xc9, 0xf5, 0xb1, 0xc2, 0xce, 0xb7, 0xbd, 0xe7, 0xee, 0xb0, 0xee, 0xb1, + 0xd2, 0xdf, 0xb0, 0xcc, 0xbd, 0xea, 0xa1, 0xf5, 0xf0, 0xe0, 0xb9, 0xef, 0xbd, + 0xd4, 0xbb, 0xca, 0xf0, 0xa7, 0xd3, 0xaf, 0xc5, 0xe8, 0xb1, 0xad, 0xd6, 0xd1, + 0xca, 0xa1, 0xed, 0xef, 0xcf, 0xe0, 0xc3, 0xbc, 0xbf, 0xb4, 0xb6, 0xdc, 0xc5, + 0xce, 0xed, 0xf0, 0xf1, 0xe6, 0xc9, 0xb0, 0xd1, 0xd0, 0xc6, 0xf6, 0xbf, 0xb3, + 0xec, 0xec, 0xec, 0xed, 0xc6, 0xed, 0xa1, 0xf5, 0xd3, 0xed, 0xd8, 0xae, 0xbf, + 0xc6, 0xc3, 0xeb, 0xc7, 0xef, 0xb4, 0xa9, 0xcd, 0xbb, 0xb8, 0xcd, 0xf3, 0xc4, + 0xd7, 0xd1, 0xe6, 0xfb, 0xba, 0xec, 0xbc, 0xcd, 0xc8, 0xd2, 0xe6, 0xfc, 0xd4, + 0xbc, 0xe6, 0xfa, 0xb8, 0xd7, 0xc3, 0xc0, 0xf4, 0xe0, 0xeb, 0xa3, 0xc4, 0xcd, + 0xcb, 0xa3, 0xd7, 0xa8, 0xd2, 0xae, 0xc5, 0xd6, 0xf1, 0xe3, 0xc5, 0xdf, 0xce, + 0xb8, 0xeb, 0xd0, 0xb1, 0xb3, 0xba, 0xfa, 0xeb, 0xce, 0xcc, 0xa5, 0xb0, 0xfb, + 0xd8, 0xb7, 0xeb, 0xd5, 0xd6, 0xc2, 0xf4, 0xae, 0xdc, 0xd1, 0xb7, 0xb6, 0xc3, + 0xa9, 0xdc, 0xc4, 0xbf, 0xc1, 0xbf, 0xe0, 0xc7, 0xd1, 0xc8, 0xf4, 0xc3, 0xaf, + 0xdc, 0xd4, 0xdc, 0xdb, 0xc3, 0xe7, 0xd3, 0xa2, 0xd7, 0xc2, 0xdc, 0xd9, 0xcc, + 0xa6, 0xd4, 0xb7, 0xb0, 0xfa, 0xdc, 0xdf, 0xb9, 0xb6, 0xb1, 0xbd, 0xdc, 0xe2, + 0xc5, 0xb0, 0xba, 0xe7, 0xf2, 0xb5, 0xf2, 0xb3, 0xd1, 0xdc, 0xc9, 0xc0, 0xd2, + 0xaa, 0xbd, 0xee, 0xbc, 0xc6, 0xb6, 0xa9, 0xb8, 0xbc, 0xd5, 0xea, 0xb8, 0xba, + 0xb8, 0xb0, 0xf4, 0xf1, 0xc5, 0xbf, 0xbe, 0xfc, 0xb9, 0xec, 0xca, 0xf6, 0xe5, + 0xc8, 0xcc, 0xf6, 0xb5, 0xcf, 0xe5, 0xc4, 0xb5, 0xfc, 0xc6, 0xc8, 0xe5, 0xc6, + 0xe5, 0xca, 0xbd, 0xbc, 0xc0, 0xc9, 0xd3, 0xf4, 0xa1, 0xf5, 0xc7, 0xf5, 0xf4, + 0xfa, 0xd6, 0xd8, 0xe3, 0xc5, 0xcf, 0xde, 0xc2, 0xaa, 0xc4, 0xb0, 0xbd, 0xb5, + 0xc3, 0xe6, 0xb8, 0xef, 0xce, 0xa4, 0xbe, 0xc2, 0xd2, 0xf4, 0xd2, 0xb3, 0xb7, + 0xe7, 0xb7, 0xc9, 0xca, 0xb3, 0xca, 0xd7, 0xcf, 0xe3, 0xb3, 0xcb, 0xd9, 0xf1, + 0xd9, 0xc4, 0xb1, 0xb6, 0xb7, 0xc2, 0xb8, 0xa9, 0xbe, 0xeb, 0xd9, 0xc5, 0xd9, + 0xba, 0xd9, 0xbb, 0xd0, 0xd2, 0xc1, 0xa9, 0xd6, 0xb5, 0xbd, 0xe8, 0xd2, 0xd0, + 0xb5, 0xb9, 0xc3, 0xc7, 0xb0, 0xb3, 0xd8, 0xf6, 0xbe, 0xf3, 0xd9, 0xc6, 0xbe, + 0xe3, 0xb3, 0xab, 0xb8, 0xf6, 0xba, 0xf2, 0xcc, 0xc8, 0xd9, 0xbd, 0xd0, 0xde, + 0xd9, 0xc1, 0xc4, 0xdf, 0xd9, 0xc2, 0xc2, 0xd7, 0xb2, 0xd6, 0xbc, 0xe6, 0xd4, + 0xa9, 0xda, 0xa4, 0xda, 0xa3, 0xb6, 0xb3, 0xc1, 0xe8, 0xd7, 0xbc, 0xb5, 0xf2, + 0xc6, 0xca, 0xd8, 0xe0, 0xcc, 0xde, 0xb8, 0xd5, 0xb0, 0xfe, 0xb7, 0xcb, 0xc7, + 0xe4, 0xd4, 0xad, 0xd8, 0xc8, 0xdb, 0xc5, 0xc9, 0xda, 0xcc, 0xc6, 0xd1, 0xe4, + 0xe0, 0xa1, 0xba, 0xdf, 0xb8, 0xe7, 0xd5, 0xdc, 0xcb, 0xf4, 0xb2, 0xb8, 0xdf, + 0xed, 0xc1, 0xa8, 0xbf, 0xde, 0xd4, 0xb1, 0xb0, 0xa6, 0xcf, 0xf8, 0xc4, 0xc4, + 0xc5, 0xb6, 0xdf, 0xf3, 0xb4, 0xbd, 0xdf, 0xec, 0xdf, 0xf1, 0xc6, 0xd4, 0xe0, + 0xf4, 0xb9, 0xa1, 0xc6, 0xd2, 0xc2, 0xf1, 0xb0, 0xa3, 0xa1, 0xf5, 0xcf, 0xc4, + 0xcc, 0xd7, 0xde, 0xca, 0xde, 0xc9, 0xe6, 0xb6, 0xc4, 0xef, 0xc4, 0xc8, 0xbe, + 0xea, 0xd3, 0xe9, 0xe6, 0xb8, 0xbc, 0xa7, 0xc9, 0xef, 0xe6, 0xb7, 0xc3, 0xe4, + 0xb6, 0xf0, 0xe6, 0xb2, 0xe6, 0xb3, 0xcb, 0xef, 0xa1, 0xf5, 0xd4, 0xd7, 0xba, + 0xa6, 0xbc, 0xd2, 0xd1, 0xe7, 0xb9, 0xac, 0xcf, 0xfc, 0xc8, 0xdd, 0xe5, 0xb7, + 0xc9, 0xe4, 0xd0, 0xbc, 0xd5, 0xb9, 0xe5, 0xec, 0xc7, 0xcd, 0xcf, 0xbf, 0xbe, + 0xfe, 0xd3, 0xf8, 0xb6, 0xeb, 0xb7, 0xe5, 0xb5, 0xba, 0xa1, 0xf5, 0xe1, 0xad, + 0xb2, 0xee, 0xcf, 0xaf, 0xca, 0xa6, 0xbf, 0xe2, 0xcd, 0xa5, 0xd7, 0xf9, 0xc8, + 0xf5, 0xcd, 0xbd, 0xbe, 0xb6, 0xd0, 0xec, 0xed, 0xa6, 0xed, 0xa7, 0xb3, 0xdc, + 0xbf, 0xd6, 0xcb, 0xa1, 0xb9, 0xa7, 0xb6, 0xf7, 0xcf, 0xa2, 0xc7, 0xc4, 0xce, + 0xf2, 0xe3, 0xa4, 0xba, 0xb7, 0xbb, 0xda, 0xe3, 0xa9, 0xd4, 0xc3, 0xe3, 0xa3, + 0xc9, 0xc8, 0xc8, 0xad, 0xea, 0xfc, 0xc4, 0xc3, 0xc9, 0xd3, 0xd0, 0xae, 0xd5, + 0xf1, 0xb2, 0xb6, 0xce, 0xe6, 0xc0, 0xa6, 0xc4, 0xf3, 0xd7, 0xbd, 0xcd, 0xa6, + 0xbe, 0xe8, 0xcd, 0xec, 0xc5, 0xb2, 0xb4, 0xec, 0xb0, 0xa4, 0xba, 0xb4, 0xb0, + 0xc6, 0xd0, 0xa7, 0xf4, 0xcd, 0xc1, 0xcf, 0xc5, 0xd4, 0xc2, 0xc3, 0xca, 0xb1, + 0xbd, 0xfa, 0xea, 0xcc, 0xbb, 0xce, 0xc9, 0xb9, 0xc9, 0xce, 0xa1, 0xf5, 0xea, + 0xcb, 0xca, 0xe9, 0xcb, 0xb7, 0xeb, 0xde, 0xc0, 0xca, 0xd0, 0xa3, 0xba, 0xcb, + 0xb0, 0xb8, 0xbf, 0xf2, 0xbb, 0xb8, 0xb8, 0xf9, 0xb9, 0xf0, 0xbd, 0xdb, 0xe8, + 0xf2, 0xca, 0xe1, 0xc0, 0xf5, 0xd7, 0xc0, 0xc9, 0xa3, 0xd4, 0xd4, 0xb2, 0xf1, + 0xcd, 0xa9, 0xe8, 0xee, 0xb8, 0xf1, 0xcc, 0xd2, 0xd6, 0xea, 0xce, 0xa6, 0xcb, + 0xa8, 0xa1, 0xf5, 0xe8, 0xec, 0xca, 0xe2, 0xd1, 0xb3, 0xd2, 0xf3, 0xc6, 0xf8, + 0xd1, 0xf5, 0xb0, 0xb1, 0xba, 0xa4, 0xeb, 0xb3, 0xcc, 0xa9, 0xc0, 0xcb, 0xcc, + 0xe9, 0xcf, 0xfb, 0xe3, 0xfe, 0xc6, 0xd6, 0xbd, 0xfe, 0xba, 0xa3, 0xd5, 0xe3, + 0xe4, 0xb8, 0xc0, 0xef, 0xc9, 0xe6, 0xb8, 0xa1, 0xbf, 0xa3, 0xd4, 0xa1, 0xba, + 0xc6, 0xd3, 0xbf, 0xa1, 0xf5, 0xe4, 0xa4, 0xc4, 0xf9, 0xa1, 0xf5, 0xe4, 0xb9, + 0xec, 0xc8, 0xba, 0xe6, 0xbf, 0xbe, 0xc0, 0xd3, 0xc1, 0xd2, 0xce, 0xda, 0xb5, + 0xf9, 0xcc, 0xd8, 0xc0, 0xc7, 0xcf, 0xc1, 0xb1, 0xb7, 0xc0, 0xea, 0xe1, 0xfa, + 0xd7, 0xc8, 0xb0, 0xe0, 0xc1, 0xf0, 0xc5, 0xe5, 0xd6, 0xe9, 0xb9, 0xe7, 0xe7, + 0xf3, 0xc5, 0xcf, 0xc4, 0xb6, 0xd0, 0xf3, 0xdb, 0xce, 0xc1, 0xf4, 0xbc, 0xb2, + 0xb2, 0xa1, 0xd6, 0xa2, 0xc6, 0xa3, 0xf0, 0xe1, 0xbe, 0xd2, 0xcc, 0xdb, 0xd5, + 0xee, 0xf0, 0xe8, 0xf0, 0xe3, 0xb8, 0xde, 0xf0, 0xe5, 0xd2, 0xe6, 0xee, 0xc1, + 0xb0, 0xbb, 0xd1, 0xa3, 0xd5, 0xe6, 0xc3, 0xdf, 0xd5, 0xa3, 0xbe, 0xd8, 0xc5, + 0xe9, 0xd5, 0xe8, 0xd4, 0xd2, 0xed, 0xc0, 0xc6, 0xc6, 0xc9, 0xe9, 0xed, 0xc6, + 0xed, 0xbe, 0xa1, 0xf5, 0xed, 0xc4, 0xc5, 0xda, 0xc3, 0xd8, 0xd3, 0xd3, 0xec, + 0xf4, 0xcb, 0xee, 0xd7, 0xe6, 0xc9, 0xf1, 0xd7, 0xa3, 0xec, 0xf3, 0xec, 0xf1, + 0xb3, 0xd3, 0xef, 0xf7, 0xd1, 0xed, 0xd7, 0xe2, 0xc7, 0xd8, 0xd6, 0xc8, 0xc3, + 0xd8, 0xd5, 0xad, 0xf1, 0xba, 0xd5, 0xbe, 0xb0, 0xca, 0xd0, 0xa6, 0xb7, 0xdb, + 0xb7, 0xc4, 0xc9, 0xb4, 0xce, 0xc6, 0xce, 0xc9, 0xcb, 0xd8, 0xcb, 0xf7, 0xb4, + 0xbf, 0xc5, 0xa6, 0xe7, 0xa2, 0xbc, 0xb6, 0xe7, 0xa1, 0xc4, 0xc9, 0xd6, 0xbd, + 0xb7, 0xd7, 0xc8, 0xb1, 0xee, 0xb9, 0xb8, 0xe1, 0xb3, 0xe1, 0xce, 0xcc, 0xea, + 0xc8, 0xd4, 0xc5, 0xb8, 0xfb, 0xb0, 0xd2, 0xba, 0xc4, 0xb5, 0xa2, 0xb9, 0xa2, + 0xeb, 0xd7, 0xd6, 0xac, 0xd2, 0xc8, 0xd0, 0xb2, 0xeb, 0xd9, 0xeb, 0xd8, 0xb4, + 0xe0, 0xd0, 0xd8, 0xb8, 0xec, 0xc2, 0xf6, 0xc4, 0xdc, 0xbc, 0xb9, 0xeb, 0xdd, + 0xbf, 0xe8, 0xb3, 0xf4, 0xf4, 0xab, 0xd2, 0xa8, 0xf3, 0xc2, 0xba, 0xbd, 0xf4, + 0xb3, 0xf4, 0xb2, 0xb0, 0xe3, 0xdb, 0xbb, 0xc3, 0xa3, 0xbb, 0xc4, 0xc0, 0xf3, + 0xbe, 0xa3, 0xc8, 0xd7, 0xbc, 0xf6, 0xb2, 0xdd, 0xd2, 0xf0, 0xdc, 0xee, 0xdc, + 0xf3, 0xd7, 0xc8, 0xc8, 0xe3, 0xb2, 0xe8, 0xdc, 0xf8, 0xdc, 0xf7, 0xdc, 0xef, + 0xb4, 0xc4, 0xdc, 0xf5, 0xf2, 0xaf, 0xce, 0xc3, 0xf2, 0xbd, 0xf2, 0xbe, 0xd4, + 0xe9, 0xf2, 0xbf, 0xb0, 0xf6, 0xf2, 0xbc, 0xd1, 0xc1, 0xcb, 0xa5, 0xd6, 0xd4, + 0xd4, 0xac, 0xf1, 0xc7, 0xf1, 0xc5, 0xd6, 0xbb, 0xbc, 0xc7, 0xda, 0xa6, 0xcc, + 0xd6, 0xda, 0xa7, 0xda, 0xa8, 0xd1, 0xb6, 0xcd, 0xd0, 0xd1, 0xb5, 0xc6, 0xfd, + 0xa1, 0xf5, 0xa1, 0xf5, 0xc6, 0xf1, 0xb2, 0xf2, 0xb1, 0xaa, 0xb2, 0xc6, 0xb9, + 0xb1, 0xc6, 0xf0, 0xb9, 0xaa, 0xd0, 0xf9, 0xe9, 0xed, 0xa1, 0xf5, 0xc8, 0xe8, + 0xcb, 0xcd, 0xc4, 0xe6, 0xc3, 0xd4, 0xcd, 0xcb, 0xc4, 0xcb, 0xbb, 0xd8, 0xcc, + 0xd3, 0xd7, 0xb7, 0xe5, 0xcb, 0xb1, 0xc5, 0xe7, 0xdf, 0xbf, 0xa4, 0xba, 0xc2, + 0xdb, 0xab, 0xbe, 0xc6, 0xc5, 0xe4, 0xd7, 0xc3, 0xb6, 0xa4, 0xd5, 0xeb, 0xee, + 0xc8, 0xb8, 0xaa, 0xee, 0xc7, 0xc9, 0xc1, 0xd4, 0xba, 0xd5, 0xf3, 0xb6, 0xb8, + 0xb1, 0xdd, 0xc9, 0xc2, 0xb3, 0xfd, 0xda, 0xea, 0xc9, 0xfd, 0xd6, 0xbb, 0xbc, + 0xa2, 0xc2, 0xed, 0xb9, 0xc7, 0xb8, 0xdf, 0xb6, 0xb7, 0xd8, 0xaa, 0xb9, 0xed, + 0xc7, 0xac, 0xa1, 0xf5, 0xce, 0xb1, 0xcd, 0xa3, 0xbc, 0xd9, 0xd9, 0xc8, 0xd9, + 0xbc, 0xd7, 0xf6, 0xce, 0xb0, 0xbd, 0xa1, 0xc5, 0xbc, 0xd9, 0xcb, 0xd9, 0xc9, + 0xd5, 0xec, 0xb2, 0xe0, 0xcd, 0xb5, 0xc6, 0xab, 0xd9, 0xbf, 0xa1, 0xf5, 0xa1, + 0xf5, 0xb6, 0xb5, 0xc3, 0xe1, 0xbb, 0xcb, 0xbc, 0xf4, 0xb8, 0xb1, 0xc0, 0xd5, + 0xce, 0xf1, 0xbf, 0xb1, 0xb6, 0xaf, 0xd9, 0xeb, 0xde, 0xcb, 0xb3, 0xd7, 0xc4, + 0xe4, 0xc7, 0xf8, 0xd8, 0xd2, 0xb2, 0xce, 0xc2, 0xfc, 0xc9, 0xcc, 0xc5, 0xbe, + 0xc0, 0xb2, 0xd7, 0xc4, 0xd1, 0xc6, 0xb7, 0xc8, 0xbf, 0xd0, 0xb0, 0xa1, 0xb3, + 0xaa, 0xe0, 0xa2, 0xce, 0xca, 0xdf, 0xfb, 0xce, 0xa8, 0xc6, 0xa1, 0xc4, 0xee, + 0xca, 0xdb, 0xe0, 0xa8, 0xbb, 0xa3, 0xcf, 0xce, 0xe0, 0xa6, 0xdf, 0xfa, 0xa1, + 0xf5, 0xc8, 0xa6, 0xb9, 0xfa, 0xe0, 0xf6, 0xd3, 0xf2, 0xbc, 0xe1, 0xdb, 0xd1, + 0xb6, 0xd1, 0xb2, 0xba, 0xdb, 0xfd, 0xbb, 0xf9, 0xcc, 0xc3, 0xb6, 0xc2, 0xd6, + 0xb4, 0xc5, 0xe0, 0xb9, 0xbb, 0xc9, 0xdd, 0xc8, 0xa2, 0xc2, 0xa6, 0xcd, 0xf1, + 0xb8, 0xbe, 0xc0, 0xb7, 0xe6, 0xb9, 0xe6, 0xbd, 0xe6, 0xbe, 0xbb, 0xe9, 0xc6, + 0xc5, 0xe6, 0xbb, 0xca, 0xeb, 0xbf, 0xdc, 0xd2, 0xfa, 0xbc, 0xc4, 0xbc, 0xc5, + 0xcb, 0xde, 0xc3, 0xdc, 0xce, 0xbe, 0xd7, 0xa8, 0xbd, 0xab, 0xcd, 0xc0, 0xcc, + 0xeb, 0xa1, 0xf5, 0xb3, 0xe7, 0xe1, 0xc7, 0xc6, 0xe9, 0xe1, 0xc8, 0xd1, 0xc2, + 0xe1, 0xbf, 0xc0, 0xa5, 0xb1, 0xc0, 0xb4, 0xde, 0xc2, 0xd8, 0xe1, 0xc5, 0xe1, + 0xc2, 0xb8, 0xda, 0xb3, 0xb2, 0xb3, 0xa3, 0xb4, 0xf8, 0xd5, 0xca, 0xe1, 0xa1, + 0xbf, 0xb5, 0xd3, 0xb9, 0xca, 0xfc, 0xe2, 0xd6, 0xe2, 0xd7, 0xd5, 0xc5, 0xc7, + 0xbf, 0xe5, 0xe7, 0xb1, 0xf2, 0xb2, 0xca, 0xb5, 0xf1, 0xb5, 0xc3, 0xe1, 0xe3, + 0xb4, 0xd3, 0xc5, 0xc7, 0xd3, 0xf9, 0xe1, 0xe2, 0xe1, 0xe4, 0xd3, 0xc1, 0xbb, + 0xbc, 0xcf, 0xa4, 0xd3, 0xc6, 0xc4, 0xfa, 0xcd, 0xef, 0xe3, 0xb2, 0xb5, 0xeb, + 0xc6, 0xe0, 0xc7, 0xe9, 0xe3, 0xac, 0xe2, 0xea, 0xcf, 0xa7, 0xb5, 0xbf, 0xe3, + 0xaf, 0xcc, 0xe8, 0xe3, 0xb0, 0xce, 0xa9, 0xbc, 0xc2, 0xe3, 0xb1, 0xb6, 0xd8, + 0xc6, 0xdd, 0xea, 0xa9, 0xec, 0xe8, 0xc2, 0xd3, 0xbf, 0xd8, 0xbe, 0xed, 0xd2, + 0xb4, 0xcc, 0xbd, 0xbd, 0xd3, 0xbd, 0xdd, 0xc5, 0xf5, 0xbe, 0xf2, 0xb4, 0xeb, + 0xde, 0xdf, 0xd1, 0xda, 0xb5, 0xf4, 0xc9, 0xa8, 0xb9, 0xd2, 0xde, 0xd1, 0xcd, + 0xc6, 0xc2, 0xd5, 0xca, 0xda, 0xd5, 0xf5, 0xb2, 0xc9, 0xde, 0xe4, 0xc5, 0xc5, + 0xcc, 0xcd, 0xcf, 0xc6, 0xc4, 0xed, 0xde, 0xe6, 0xc9, 0xe1, 0xde, 0xe0, 0xb1, + 0xd6, 0xb0, 0xbd, 0xbe, 0xc8, 0xbd, 0xcc, 0xb0, 0xdc, 0xc6, 0xf4, 0xc3, 0xf4, + 0xd0, 0xf0, 0xeb, 0xb7, 0xa1, 0xf5, 0xd0, 0xb1, 0xf5, 0xfa, 0xd5, 0xb6, 0xd7, + 0xe5, 0xd0, 0xfd, 0xec, 0xba, 0xec, 0xbb, 0xd6, 0xe7, 0xcd, 0xed, 0xce, 0xee, + 0xb3, 0xbf, 0xbb, 0xde, 0xa1, 0xf5, 0xb2, 0xdc, 0xa1, 0xf5, 0xcd, 0xfb, 0xc1, + 0xba, 0xcc, 0xdd, 0xc9, 0xd2, 0xe8, 0xf7, 0xe8, 0xf3, 0xb8, 0xcb, 0xcd, 0xb0, + 0xc0, 0xa6, 0xce, 0xe0, 0xb9, 0xa3, 0xd0, 0xb5, 0xe8, 0xe8, 0xc6, 0xfa, 0xcb, + 0xf3, 0xb0, 0xf0, 0xc3, 0xb7, 0xe8, 0xd9, 0xcc, 0xf5, 0xc0, 0xe6, 0xe8, 0xc9, + 0xa1, 0xf5, 0xa1, 0xf5, 0xd3, 0xfb, 0xc9, 0xb1, 0xba, 0xc1, 0xc7, 0xf2, 0xc7, + 0xe2, 0xcf, 0xd1, 0xc1, 0xb9, 0xb4, 0xbe, 0xe4, 0xc8, 0xd2, 0xba, 0xb5, 0xad, + 0xcc, 0xca, 0xd3, 0xd9, 0xcc, 0xed, 0xc7, 0xb3, 0xc7, 0xe5, 0xe4, 0xbf, 0xc1, + 0xdc, 0xd1, 0xc4, 0xca, 0xe7, 0xe4, 0xcc, 0xe4, 0xc1, 0xd1, 0xcd, 0xba, 0xd4, + 0xbb, 0xec, 0xd4, 0xa8, 0xe4, 0xc0, 0xc6, 0xe0, 0xe4, 0xbe, 0xba, 0xad, 0xc0, + 0xe1, 0xd2, 0xf9, 0xcc, 0xd4, 0xc2, 0xd9, 0xc9, 0xee, 0xbb, 0xb4, 0xbe, 0xbb, + 0xcf, 0xfd, 0xd7, 0xcd, 0xb8, 0xa2, 0xb4, 0xe3, 0xe4, 0xc3, 0xe4, 0xc6, 0xc5, + 0xeb, 0xd1, 0xc9, 0xba, 0xb8, 0xb7, 0xe9, 0xcf, 0xa9, 0xcb, 0xac, 0xc7, 0xa3, + 0xc0, 0xe7, 0xb2, 0xc2, 0xc3, 0xcd, 0xb2, 0xfe, 0xe2, 0xa3, 0xd5, 0xf8, 0xc2, + 0xca, 0xc0, 0xc5, 0xe7, 0xf0, 0xc7, 0xf2, 0xc0, 0xed, 0xcf, 0xd6, 0xa1, 0xf5, + 0xf0, 0xad, 0xc6, 0xbf, 0xb4, 0xc9, 0xcc, 0xf0, 0xb2, 0xfa, 0xc2, 0xd4, 0xc6, + 0xe8, 0xb1, 0xcf, 0xd2, 0xec, 0xca, 0xe8, 0xd6, 0xcc, 0xba, 0xdb, 0xb4, 0xc3, + 0xc8, 0xac, 0xf0, 0xea, 0xf0, 0xa8, 0xbf, 0xf8, 0xba, 0xd0, 0xca, 0xa2, 0xbe, + 0xec, 0xd6, 0xda, 0xd1, 0xdb, 0xbf, 0xf4, 0xed, 0xf8, 0xcc, 0xf7, 0xc1, 0xf2, + 0xd6, 0xec, 0xed, 0xca, 0xcf, 0xe9, 0xc6, 0xb1, 0xbc, 0xc0, 0xd2, 0xc6, 0xd6, + 0xcf, 0xf1, 0xbb, 0xf3, 0xd2, 0xb1, 0xbf, 0xb5, 0xd1, 0xb5, 0xda, 0xb7, 0xfb, + 0xf3, 0xcf, 0xf3, 0xd7, 0xf3, 0xd0, 0xc1, 0xa3, 0xb4, 0xd6, 0xc6, 0xc9, 0xb0, + 0xed, 0xcf, 0xd2, 0xcd, 0xb3, 0xd4, 0xfa, 0xc9, 0xdc, 0xe7, 0xa8, 0xe7, 0xa9, + 0xcf, 0xb8, 0xc9, 0xf0, 0xd7, 0xe9, 0xc0, 0xdb, 0xd6, 0xd5, 0xe7, 0xa5, 0xe7, + 0xa6, 0xb2, 0xa7, 0xd0, 0xdf, 0xc1, 0xe7, 0xd2, 0xee, 0xf4, 0xe1, 0xcf, 0xb0, + 0xf1, 0xea, 0xc1, 0xc4, 0xf1, 0xf6, 0xb8, 0xac, 0xb2, 0xb1, 0xb4, 0xbd, 0xcd, + 0xd1, 0xd0, 0xde, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xa9, 0xb6, 0xe6, 0xcf, 0xcf, + 0xb2, 0xb0, 0xb4, 0xac, 0xc9, 0xaf, 0xdd, 0xb8, 0xdd, 0xb7, 0xdd, 0xa9, 0xbc, + 0xd4, 0xbe, 0xa5, 0xc3, 0xa7, 0xc4, 0xaa, 0xdc, 0xec, 0xd7, 0xaf, 0xdd, 0xae, + 0xc0, 0xf2, 0xdd, 0xac, 0xba, 0xc9, 0xdd, 0xb6, 0xdd, 0xb1, 0xc6, 0xce, 0xdc, + 0xc8, 0xb4, 0xa6, 0xb1, 0xeb, 0xc9, 0xdf, 0xd6, 0xfb, 0xf2, 0xc0, 0xf2, 0xc1, + 0xf2, 0xc2, 0xc7, 0xf9, 0xb5, 0xb0, 0xf2, 0xc6, 0xf2, 0xc7, 0xf2, 0xc8, 0xca, + 0xf5, 0xd9, 0xf2, 0xf4, 0xc2, 0xb1, 0xbb, 0xcc, 0xbb, 0xd0, 0xe4, 0xc5, 0xdb, + 0xb4, 0xfc, 0xc3, 0xd9, 0xb9, 0xe6, 0xb7, 0xc3, 0xd1, 0xc8, 0xbe, 0xf7, 0xda, + 0xab, 0xd0, 0xed, 0xc9, 0xe8, 0xcb, 0xcf, 0xb6, 0xef, 0xd0, 0xc0, 0xf4, 0xf9, + 0xeb, 0xe0, 0xb7, 0xb7, 0xd4, 0xf0, 0xb9, 0xe1, 0xbb, 0xf5, 0xcc, 0xb0, 0xc6, + 0xb6, 0xf4, 0xf6, 0xc9, 0xe2, 0xd6, 0xba, 0xf5, 0xc3, 0xe9, 0xee, 0xc8, 0xed, + 0xd5, 0xe2, 0xe5, 0xd0, 0xcd, 0xa8, 0xb6, 0xba, 0xc1, 0xac, 0xcb, 0xd9, 0xca, + 0xc5, 0xd6, 0xf0, 0xe5, 0xc9, 0xb3, 0xd1, 0xd4, 0xec, 0xcd, 0xb8, 0xb7, 0xea, + 0xe5, 0xd1, 0xb9, 0xe4, 0xcd, 0xbe, 0xb2, 0xbf, 0xb9, 0xf9, 0xb6, 0xbc, 0xd0, + 0xef, 0xd2, 0xb0, 0xee, 0xce, 0xbf, 0xdb, 0xb5, 0xf6, 0xee, 0xcb, 0xa1, 0xf5, + 0xb7, 0xb0, 0xb1, 0xd5, 0xc5, 0xe3, 0xc1, 0xea, 0xb3, 0xc2, 0xc2, 0xbd, 0xd2, + 0xf5, 0xda, 0xf0, 0xcc, 0xd5, 0xcf, 0xdd, 0xda, 0xee, 0xc8, 0xb8, 0xd1, 0xa9, + 0xf6, 0xa7, 0xd5, 0xc2, 0xbe, 0xb9, 0xb6, 0xa5, 0xc7, 0xea, 0xd3, 0xe3, 0xc4, + 0xf1, 0xc2, 0xb1, 0xc2, 0xb9, 0xc2, 0xf3, 0xc2, 0xe9, 0xbc, 0xd2, 0xb0, 0xf8, + 0xb8, 0xb5, 0xb1, 0xb8, 0xbd, 0xdc, 0xbf, 0xfe, 0xd8, 0xf7, 0xc9, 0xa1, 0xd0, + 0xa7, 0xd7, 0xee, 0xbf, 0xad, 0xb8, 0xee, 0xd8, 0xdc, 0xb4, 0xb4, 0xca, 0xa3, + 0xc0, 0xcd, 0xca, 0xa4, 0xd1, 0xab, 0xb2, 0xa9, 0xd8, 0xca, 0xe0, 0xb4, 0xbf, + 0xa6, 0xd0, 0xfa, 0xcc, 0xe4, 0xba, 0xb0, 0xba, 0xc8, 0xb4, 0xad, 0xce, 0xb9, + 0xcf, 0xb2, 0xc9, 0xa5, 0xe0, 0xb8, 0xc0, 0xae, 0xe0, 0xa9, 0xe0, 0xab, 0xd4, + 0xfb, 0xb5, 0xa5, 0xe0, 0xb0, 0xcd, 0xd9, 0xd3, 0xb4, 0xbb, 0xbd, 0xd3, 0xf7, + 0xc7, 0xc7, 0xe0, 0xac, 0xe0, 0xb1, 0xba, 0xed, 0xa1, 0xf5, 0xe0, 0xb9, 0xce, + 0xa7, 0xd2, 0xa2, 0xbf, 0xb0, 0xb3, 0xa1, 0xb5, 0xcc, 0xd1, 0xdf, 0xb1, 0xa8, + 0xb1, 0xa4, 0xdb, 0xf6, 0xdc, 0xa9, 0xd2, 0xbc, 0xba, 0xf8, 0xb5, 0xec, 0xe6, + 0xc3, 0xc3, 0xc4, 0xd0, 0xf6, 0xc3, 0xbd, 0xe6, 0xc2, 0xe6, 0xb4, 0xe6, 0xdc, + 0xe5, 0xee, 0xba, 0xae, 0xb8, 0xbb, 0xd4, 0xa2, 0xc3, 0xc2, 0xd7, 0xf0, 0xd1, + 0xb0, 0xbe, 0xcd, 0xc7, 0xb6, 0xe1, 0xb0, 0xe1, 0xcb, 0xef, 0xfa, 0xd9, 0xe3, + 0xb7, 0xf9, 0xc3, 0xb1, 0xd6, 0xa1, 0xe0, 0xf8, 0xbc, 0xb8, 0xc0, 0xc8, 0xb2, + 0xde, 0xcf, 0xe1, 0xbe, 0xc7, 0xe5, 0xf6, 0xc5, 0xed, 0xb8, 0xb4, 0xd1, 0xad, + 0xe1, 0xe5, 0xbb, 0xf3, 0xb6, 0xf1, 0xb1, 0xaf, 0xc3, 0xc6, 0xbb, 0xdd, 0xe3, + 0xab, 0xe3, 0xb6, 0xd0, 0xca, 0xe3, 0xb5, 0xb6, 0xe8, 0xe2, 0xfc, 0xe3, 0xb7, + 0xbf, 0xae, 0xc4, 0xd5, 0xe3, 0xb9, 0xbb, 0xcc, 0xd3, 0xe4, 0xe3, 0xb8, 0xa1, + 0xf5, 0xea, 0xaa, 0xec, 0xe9, 0xb3, 0xb8, 0xd5, 0xc6, 0xc3, 0xe8, 0xbc, 0xf0, + 0xbf, 0xab, 0xc8, 0xe0, 0xde, 0xf1, 0xd7, 0xe1, 0xb2, 0xe5, 0xb4, 0xa7, 0xcc, + 0xe1, 0xce, 0xd5, 0xd2, 0xbe, 0xbd, 0xd2, 0xbb, 0xd3, 0xb4, 0xb7, 0xd4, 0xae, + 0xbe, 0xbe, 0xbb, 0xbb, 0xde, 0xf0, 0xd1, 0xef, 0xb1, 0xb3, 0xb3, 0xa8, 0xb6, + 0xd8, 0xb8, 0xd2, 0xc9, 0xa2, 0xb0, 0xdf, 0xec, 0xb3, 0xcb, 0xb9, 0xc6, 0xd5, + 0xce, 0xfa, 0xc7, 0xe7, 0xbe, 0xa7, 0xbe, 0xb0, 0xca, 0xee, 0xd6, 0xc7, 0xc1, + 0xc0, 0xea, 0xd0, 0xd4, 0xf8, 0xcc, 0xe6, 0xc6, 0xda, 0xb3, 0xaf, 0xb9, 0xd7, + 0xd7, 0xd8, 0xcc, 0xc4, 0xbc, 0xac, 0xd4, 0xe6, 0xd2, 0xce, 0xb6, 0xb0, 0xbf, + 0xc3, 0xc9, 0xad, 0xd5, 0xbb, 0xe8, 0xfe, 0xb0, 0xf4, 0xc6, 0xdc, 0xe9, 0xa6, + 0xc6, 0xe5, 0xb9, 0xf7, 0xd6, 0xb2, 0xbd, 0xb7, 0xd7, 0xb5, 0xc3, 0xde, 0xc5, + 0xef, 0xe8, 0xfa, 0xa1, 0xf5, 0xbf, 0xee, 0xc6, 0xdb, 0xc7, 0xd5, 0xb2, 0xd0, + 0xd6, 0xb3, 0xbf, 0xc7, 0xcc, 0xba, 0xb5, 0xaa, 0xc2, 0xc8, 0xeb, 0xb2, 0xb8, + 0xdb, 0xd3, 0xce, 0xe4, 0xd5, 0xb6, 0xc9, 0xe4, 0xd6, 0xd3, 0xbf, 0xb4, 0xd5, + 0xc7, 0xfe, 0xe4, 0xd7, 0xd4, 0xfc, 0xbc, 0xf5, 0xd5, 0xbf, 0xcf, 0xe6, 0xb2, + 0xb3, 0xba, 0xfe, 0xe4, 0xce, 0xce, 0xbc, 0xce, 0xd0, 0xcc, 0xc0, 0xbf, 0xca, + 0xcd, 0xc4, 0xc3, 0xec, 0xb2, 0xe2, 0xc5, 0xc8, 0xd3, 0xe5, 0xbb, 0xeb, 0xd7, + 0xcc, 0xb8, 0xc8, 0xbb, 0xc1, 0xe4, 0xcf, 0xe3, 0xfd, 0xe4, 0xd8, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe4, 0xd2, 0xb1, 0xba, 0xb7, 0xd9, 0xbd, 0xb9, 0xd1, 0xe6, 0xce, + 0xde, 0xc8, 0xbb, 0xd6, 0xf3, 0xa1, 0xf5, 0xc5, 0xc6, 0xea, 0xf7, 0xcf, 0xac, + 0xd3, 0xcc, 0xe2, 0xab, 0xba, 0xef, 0xd0, 0xc9, 0xb7, 0xa9, 0xe7, 0xf7, 0xc1, + 0xd5, 0xd7, 0xc1, 0xe7, 0xfa, 0xc5, 0xfd, 0xc5, 0xc3, 0xc7, 0xd9, 0xa1, 0xf5, + 0xe8, 0xa1, 0xe7, 0xf9, 0xe7, 0xfb, 0xc9, 0xfb, 0xcb, 0xd5, 0xbb, 0xad, 0xb7, + 0xac, 0xc1, 0xa1, 0xcd, 0xb4, 0xf0, 0xeb, 0xbe, 0xb7, 0xb6, 0xbb, 0xc6, 0xa6, + 0xa1, 0xf5, 0xb5, 0xc7, 0xb7, 0xa2, 0xcd, 0xee, 0xf0, 0xa9, 0xf1, 0xe5, 0xb5, + 0xc1, 0xc0, 0xa7, 0xb6, 0xcc, 0xcf, 0xf5, 0xd3, 0xb2, 0xd1, 0xe2, 0xc9, 0xd4, + 0xb8, 0xd1, 0xb3, 0xcc, 0xcb, 0xb0, 0xcf, 0xa1, 0xbe, 0xbd, 0xb4, 0xb0, 0xbd, + 0xd1, 0xcd, 0xaf, 0xbf, 0xa2, 0xb5, 0xc8, 0xb2, 0xdf, 0xb1, 0xca, 0xbf, 0xf0, + 0xcd, 0xb2, 0xb4, 0xf0, 0xcb, 0xf1, 0xbd, 0xee, 0xb7, 0xa4, 0xd6, 0xfe, 0xcb, + 0xda, 0xd6, 0xe0, 0xbd, 0xca, 0xbd, 0xe1, 0xc8, 0xde, 0xbe, 0xf8, 0xd7, 0xcf, + 0xd0, 0xf5, 0xcb, 0xbf, 0xc2, 0xe7, 0xb8, 0xf8, 0xd1, 0xa4, 0xa1, 0xf5, 0xe7, + 0xad, 0xc9, 0xc6, 0xcf, 0xe8, 0xf4, 0xe2, 0xf1, 0xf3, 0xf1, 0xf8, 0xcb, 0xe0, + 0xcd, 0xf3, 0xc7, 0xbb, 0xd2, 0xb8, 0xb8, 0xad, 0xc9, 0xf6, 0xd5, 0xcd, 0xcc, + 0xf3, 0xc6, 0xa2, 0xeb, 0xe7, 0xeb, 0xe8, 0xeb, 0xe9, 0xca, 0xe6, 0xcb, 0xb4, + 0xc6, 0xd0, 0xdd, 0xcd, 0xdd, 0xce, 0xc6, 0xbc, 0xb2, 0xa4, 0xdd, 0xd1, 0xdd, + 0xc2, 0xdd, 0xbc, 0xbb, 0xaa, 0xc1, 0xe2, 0xa1, 0xf5, 0xd6, 0xf8, 0xc0, 0xb3, + 0xdd, 0xd4, 0xc3, 0xc8, 0xbe, 0xfa, 0xdd, 0xc4, 0xb7, 0xc6, 0xbe, 0xd5, 0xdd, + 0xc7, 0xce, 0xae, 0xcc, 0xd1, 0xb2, 0xcb, 0xdc, 0xc9, 0xdd, 0xca, 0xdd, 0xcb, + 0xd0, 0xe9, 0xf2, 0xd4, 0xcd, 0xdc, 0xf2, 0xce, 0xbb, 0xd7, 0xd6, 0xeb, 0xb8, + 0xf2, 0xf2, 0xd0, 0xf2, 0xd2, 0xbd, 0xd6, 0xb2, 0xc3, 0xc1, 0xd1, 0xb8, 0xa4, + 0xf1, 0xfb, 0xca, 0xd3, 0xd7, 0xa2, 0xd3, 0xbd, 0xc6, 0xc0, 0xb4, 0xca, 0xd6, + 0xa4, 0xda, 0xac, 0xda, 0xb0, 0xd7, 0xe7, 0xd5, 0xa9, 0xda, 0xae, 0xcb, 0xdf, + 0xd5, 0xef, 0xda, 0xad, 0xa1, 0xf5, 0xcf, 0xf3, 0xf5, 0xf5, 0xd6, 0xfc, 0xcc, + 0xf9, 0xb7, 0xa1, 0xea, 0xdd, 0xea, 0xda, 0xb7, 0xd1, 0xba, 0xd8, 0xb9, 0xf3, + 0xc2, 0xf2, 0xb1, 0xe1, 0xc3, 0xb3, 0xb4, 0xfb, 0xd4, 0xbd, 0xb3, 0xac, 0xb3, + 0xc3, 0xf5, 0xc9, 0xbe, 0xe0, 0xb0, 0xcf, 0xf5, 0xc7, 0xc5, 0xdc, 0xb5, 0xf8, + 0xf5, 0xcb, 0xf5, 0xcc, 0xe9, 0xf0, 0xd6, 0xe1, 0xe9, 0xf3, 0xb9, 0xbc, 0xb4, + 0xfe, 0xe5, 0xd3, 0xd6, 0xdc, 0xd2, 0xdd, 0xbd, 0xf8, 0xe5, 0xd4, 0xb6, 0xf5, + 0xd3, 0xca, 0xcf, 0xe7, 0xdb, 0xb1, 0xba, 0xa8, 0xcb, 0xd6, 0xc1, 0xbf, 0xb3, + 0xae, 0xc5, 0xa5, 0xb8, 0xc6, 0xc4, 0xc6, 0xbe, 0xfb, 0xb6, 0xdb, 0xee, 0xd4, + 0xa1, 0xf5, 0xee, 0xd3, 0xe3, 0xc9, 0xc8, 0xf2, 0xbf, 0xaa, 0xcf, 0xd0, 0xbc, + 0xe4, 0xcf, 0xd0, 0xe3, 0xc8, 0xb6, 0xd3, 0xbd, 0xd7, 0xcb, 0xe5, 0xd1, 0xf4, + 0xd3, 0xe7, 0xc2, 0xa1, 0xda, 0xf2, 0xda, 0xef, 0xb5, 0xcc, 0xd1, 0xe3, 0xd1, + 0xc5, 0xd0, 0xdb, 0xbc, 0xaf, 0xb9, 0xcd, 0xf6, 0xa9, 0xd4, 0xc6, 0xc8, 0xcd, + 0xcf, 0xee, 0xcb, 0xb3, 0xd0, 0xeb, 0xe2, 0xb8, 0xe2, 0xbf, 0xb7, 0xb9, 0xe2, + 0xbd, 0xd2, 0xfb, 0xe2, 0xc1, 0xb7, 0xeb, 0xd4, 0xa6, 0xbb, 0xc6, 0xca, 0xf2, + 0xba, 0xda, 0xc2, 0xd2, 0xd3, 0xb6, 0xd5, 0xae, 0xb0, 0xc1, 0xb4, 0xab, 0xbd, + 0xf6, 0xc7, 0xe3, 0xb4, 0xdf, 0xc9, 0xcb, 0xc9, 0xb5, 0xd9, 0xcc, 0xa1, 0xf5, + 0xbd, 0xcb, 0xb2, 0xf9, 0xd8, 0xe2, 0xc4, 0xbc, 0xbd, 0xcb, 0xc7, 0xda, 0xca, + 0xc6, 0xbc, 0xa8, 0xbb, 0xe3, 0xe0, 0xb5, 0xe0, 0xcb, 0xc9, 0xa4, 0xe0, 0xc2, + 0xc2, 0xf0, 0xca, 0xc8, 0xd8, 0xc4, 0xe0, 0xbe, 0xcb, 0xc3, 0xe0, 0xcd, 0xe0, + 0xc5, 0xce, 0xd8, 0xce, 0xcb, 0xd0, 0xe1, 0xc7, 0xba, 0xe0, 0xc6, 0xe0, 0xbc, + 0xd4, 0xb0, 0xd4, 0xb2, 0xc8, 0xfb, 0xcb, 0xdc, 0xcc, 0xc1, 0xcd, 0xbf, 0xda, + 0xa3, 0xcb, 0xfe, 0xcc, 0xee, 0xcb, 0xfa, 0xce, 0xc1, 0xbf, 0xe9, 0xce, 0xeb, + 0xdb, 0xf5, 0xdc, 0xe3, 0xb0, 0xc2, 0xbc, 0xde, 0xbc, 0xb5, 0xcf, 0xd3, 0xe6, + 0xc5, 0xc2, 0xe8, 0xe6, 0xc1, 0xcf, 0xb1, 0xc9, 0xa9, 0xe6, 0xc7, 0xe1, 0xd4, + 0xe1, 0xcf, 0xbb, 0xcf, 0xb8, 0xc9, 0xc1, 0xae, 0xcf, 0xc3, 0xdf, 0xb1, 0xbb, + 0xe3, 0xc5, 0xd4, 0xce, 0xa2, 0xd3, 0xde, 0xd2, 0xe2, 0xb4, 0xc8, 0xb8, 0xd0, + 0xcf, 0xeb, 0xb0, 0xae, 0xc8, 0xc7, 0xb3, 0xee, 0xd3, 0xfa, 0xc9, 0xf7, 0xbb, + 0xc5, 0xc0, 0xf5, 0xe3, 0xb3, 0xe2, 0xe9, 0xe2, 0xeb, 0xc0, 0xa2, 0xed, 0xaa, + 0xed, 0xa9, 0xe2, 0xfd, 0xea, 0xac, 0xea, 0xab, 0xb4, 0xea, 0xd5, 0xa5, 0xb8, + 0xe3, 0xcc, 0xc2, 0xb4, 0xee, 0xb2, 0xeb, 0xb0, 0xe1, 0xb2, 0xab, 0xcb, 0xd1, + 0xc9, 0xa6, 0xcb, 0xf0, 0xc7, 0xc0, 0xd2, 0xa1, 0xb5, 0xb7, 0xb9, 0xb9, 0xbe, + 0xb4, 0xd5, 0xe5, 0xd0, 0xc2, 0xb0, 0xb5, 0xea, 0xcd, 0xcf, 0xbe, 0xd4, 0xce, + 0xc5, 0xaf, 0xea, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, 0xbb, 0xe1, 0xc0, 0xc6, 0xd2, + 0xb5, 0xb3, 0xfe, 0xbf, 0xac, 0xe9, 0xaa, 0xd0, 0xa8, 0xbc, 0xab, 0xd2, 0xac, + 0xb8, 0xc5, 0xd1, 0xee, 0xe8, 0xe5, 0xe9, 0xae, 0xc0, 0xe3, 0xb7, 0xe3, 0xe9, + 0xba, 0xd3, 0xdc, 0xe9, 0xac, 0xe9, 0xb9, 0xa1, 0xf5, 0xd0, 0xaa, 0xcb, 0xea, + 0xbb, 0xd9, 0xb5, 0xee, 0xd8, 0xb9, 0xeb, 0xa6, 0xd2, 0xe7, 0xcb, 0xdd, 0xd7, + 0xd2, 0xc8, 0xdc, 0xe4, 0xe8, 0xd4, 0xb4, 0xb9, 0xb5, 0xb5, 0xe1, 0xc3, 0xf0, + 0xe4, 0xdf, 0xe4, 0xdb, 0xca, 0xaa, 0xc4, 0xe7, 0xce, 0xc2, 0xbb, 0xac, 0xd7, + 0xbc, 0xc1, 0xef, 0xb2, 0xd7, 0xcc, 0xcf, 0xcf, 0xaa, 0xe4, 0xe0, 0xe4, 0xe5, + 0xbc, 0xe5, 0xd1, 0xcc, 0xb7, 0xb3, 0xc3, 0xba, 0xc1, 0xb6, 0xd5, 0xd5, 0xec, + 0xcf, 0xec, 0xbe, 0xec, 0xe3, 0xbb, 0xcd, 0xbb, 0xc0, 0xc9, 0xb7, 0xcf, 0xba, + 0xec, 0xd0, 0xa1, 0xf5, 0xd2, 0xaf, 0xeb, 0xba, 0xe9, 0xe0, 0xca, 0xa8, 0xd4, + 0xb3, 0xbb, 0xab, 0xc0, 0xc5, 0xba, 0xf7, 0xe8, 0xa6, 0xc9, 0xaa, 0xc8, 0xf0, + 0xe8, 0xa3, 0xe7, 0xf5, 0xe8, 0xa7, 0xe7, 0xf8, 0xe8, 0xa4, 0xb5, 0xb1, 0xbb, + 0xfb, 0xf0, 0xf6, 0xcc, 0xb5, 0xb4, 0xe1, 0xc2, 0xe9, 0xf0, 0xf2, 0xb1, 0xd4, + 0xf0, 0xf4, 0xb3, 0xd5, 0xc2, 0xe9, 0xd5, 0xb5, 0xc3, 0xcb, 0xbe, 0xa6, 0xbd, + 0xde, 0xc4, 0xc0, 0xed, 0xf9, 0xb6, 0xbd, 0xb6, 0xc3, 0xd8, 0xba, 0xb2, 0xc7, + 0xd5, 0xf6, 0xee, 0xa2, 0xed, 0xfe, 0xee, 0xa1, 0xb0, 0xab, 0xcb, 0xe9, 0xc5, + 0xf6, 0xcd, 0xeb, 0xb5, 0xe2, 0xc2, 0xb5, 0xb5, 0xef, 0xc5, 0xf0, 0xb1, 0xae, + 0xed, 0xd4, 0xa1, 0xf5, 0xec, 0xf7, 0xc2, 0xbb, 0xbd, 0xfb, 0xcd, 0xf2, 0xc7, + 0xdd, 0xc0, 0xe2, 0xd6, 0xc9, 0xb3, 0xed, 0xef, 0xfe, 0xd9, 0xf7, 0xef, 0xfd, + 0xbf, 0xdf, 0xf1, 0xbd, 0xbf, 0xea, 0xbd, 0xda, 0xf3, 0xde, 0xf3, 0xdf, 0xf3, + 0xc8, 0xc1, 0xbb, 0xbe, 0xac, 0xd4, 0xc1, 0xbe, 0xad, 0xbe, 0xee, 0xc0, 0xa7, + 0xb0, 0xf3, 0xcb, 0xe7, 0xcc, 0xd0, 0xd6, 0xc3, 0xd5, 0xd6, 0xd7, 0xef, 0xca, + 0xf0, 0xd2, 0xe5, 0xcf, 0xdb, 0xc8, 0xba, 0xca, 0xa5, 0xc6, 0xb8, 0xcb, 0xc1, + 0xd2, 0xde, 0xeb, 0xec, 0xd1, 0xfc, 0xb3, 0xa6, 0xd0, 0xc8, 0xc8, 0xf9, 0xbd, + 0xc5, 0xd6, 0xd7, 0xb8, 0xb9, 0xcf, 0xd9, 0xc4, 0xd4, 0xbe, 0xcb, 0xcd, 0xa7, + 0xb5, 0xd9, 0xbb, 0xe7, 0xc2, 0xe4, 0xdd, 0xe6, 0xbf, 0xfb, 0xce, 0xad, 0xba, + 0xf9, 0xd2, 0xb6, 0xd4, 0xe1, 0xb8, 0xf0, 0xdd, 0xe0, 0xdd, 0xab, 0xc6, 0xcf, + 0xb6, 0xad, 0xdd, 0xe2, 0xdd, 0xe7, 0xdd, 0xe1, 0xd3, 0xdd, 0xc2, 0xb2, 0xba, + 0xc5, 0xd3, 0xbc, 0xf2, 0xd1, 0xf2, 0xda, 0xf2, 0xd8, 0xca, 0xf1, 0xb6, 0xea, + 0xcd, 0xc9, 0xb7, 0xe4, 0xf2, 0xd7, 0xf2, 0xb9, 0xf2, 0xdb, 0xd1, 0xc3, 0xf4, + 0xc4, 0xd2, 0xe1, 0xc8, 0xb9, 0xb2, 0xb9, 0xf4, 0xc3, 0xd7, 0xb0, 0xc0, 0xef, + 0xf4, 0xc1, 0xd4, 0xa3, 0xd9, 0xf6, 0xa1, 0xf5, 0xbd, 0xe2, 0xb2, 0xef, 0xb8, + 0xc3, 0xcf, 0xea, 0xca, 0xd4, 0xca, 0xab, 0xda, 0xb5, 0xbf, 0xe4, 0xda, 0xb6, + 0xd2, 0xe8, 0xb3, 0xcf, 0xbb, 0xb0, 0xd6, 0xef, 0xb9, 0xee, 0xd1, 0xaf, 0xda, + 0xb9, 0xda, 0xb8, 0xd5, 0xb2, 0xa1, 0xf5, 0xf6, 0xa4, 0xa1, 0xf5, 0xbb, 0xbf, + 0xf5, 0xf6, 0xba, 0xd1, 0xd4, 0xf4, 0xd7, 0xca, 0xbc, 0xd6, 0xbb, 0xdf, 0xea, + 0xdf, 0xc1, 0xde, 0xc2, 0xb8, 0xea, 0xe0, 0xbc, 0xa3, 0xb8, 0xfa, 0xbf, 0xe7, + 0xc2, 0xb7, 0xcc, 0xf8, 0xb6, 0xe5, 0xb9, 0xf2, 0xf5, 0xd3, 0xa1, 0xf5, 0xb6, + 0xe3, 0xbd, 0xcf, 0xd4, 0xd8, 0xe9, 0xf8, 0xe9, 0xf9, 0xb1, 0xd9, 0xc5, 0xa9, + 0xd4, 0xcb, 0xd3, 0xce, 0xb5, 0xc0, 0xcb, 0xec, 0xb4, 0xef, 0xb1, 0xc6, 0xce, + 0xa5, 0xe5, 0xda, 0xd3, 0xf6, 0xb6, 0xf4, 0xb9, 0xfd, 0xb1, 0xe9, 0xe5, 0xd8, + 0xd3, 0xe2, 0xb6, 0xdd, 0xd7, 0xde, 0xa1, 0xf5, 0xb3, 0xea, 0xc0, 0xd2, 0xf5, + 0xa4, 0xd3, 0xd4, 0xee, 0xdc, 0xc7, 0xaf, 0xee, 0xe0, 0xee, 0xdf, 0xbc, 0xd8, + 0xd3, 0xcb, 0xc7, 0xa6, 0xc5, 0xd9, 0xb9, 0xb3, 0xb2, 0xac, 0xc1, 0xe5, 0xee, + 0xe7, 0xee, 0xe9, 0xee, 0xd2, 0xee, 0xeb, 0xee, 0xe4, 0xc3, 0xad, 0xd5, 0xa2, + 0xb0, 0xaf, 0xb8, 0xf4, 0xd4, 0xc9, 0xd3, 0xba, 0xf6, 0xc1, 0xef, 0xf4, 0xa1, + 0xf5, 0xc0, 0xd7, 0xb5, 0xe7, 0xb1, 0xa2, 0xc1, 0xe3, 0xbe, 0xb8, 0xd1, 0xa5, + 0xb0, 0xd0, 0xd4, 0xa4, 0xcd, 0xe7, 0xb6, 0xd9, 0xe7, 0xef, 0xb0, 0xe4, 0xcb, + 0xcc, 0xcb, 0xc7, 0xe2, 0xc2, 0xb1, 0xa5, 0xca, 0xce, 0xb3, 0xdb, 0xcd, 0xd4, + 0xd1, 0xb1, 0xf7, 0xd5, 0xf0, 0xaf, 0xf7, 0xe4, 0xb6, 0xa6, 0xb9, 0xc4, 0xca, + 0xf3, 0xc9, 0xae, 0xd9, 0xd7, 0xbd, 0xc4, 0xd9, 0xd2, 0xd9, 0xd4, 0xc1, 0xc5, + 0xc6, 0xcd, 0xcf, 0xf1, 0xc7, 0xc8, 0xb9, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xbe, + 0xa4, 0xb5, 0xca, 0xbb, 0xae, 0xd8, 0xe3, 0xd8, 0xd1, 0xd1, 0xe1, 0xe0, 0xd5, + 0xe0, 0xd6, 0xc2, 0xef, 0xb3, 0xa2, 0xcb, 0xd4, 0xc5, 0xbb, 0xcc, 0xbe, 0xbc, + 0xce, 0xe0, 0xb6, 0xb8, 0xc2, 0xe0, 0xbb, 0xdf, 0xf5, 0xe0, 0xbd, 0xe0, 0xd0, + 0xa1, 0xf5, 0xdf, 0xd9, 0xcd, 0xc5, 0xcd, 0xbc, 0xb3, 0xbe, 0xdb, 0xd3, 0xbe, + 0xb3, 0xc4, 0xb9, 0xb5, 0xe6, 0xc7, 0xb5, 0xca, 0xfb, 0xa1, 0xf5, 0xca, 0xd9, + 0xe2, 0xb7, 0xc3, 0xce, 0xe2, 0xb9, 0xb6, 0xe1, 0xde, 0xc6, 0xb5, 0xd5, 0xe6, + 0xcf, 0xc4, 0xdb, 0xe5, 0xfd, 0xe6, 0xce, 0xe6, 0xd0, 0xe6, 0xcc, 0xb7, 0xf5, + 0xc4, 0xaf, 0xc4, 0xfe, 0xb9, 0xd1, 0xc1, 0xc8, 0xca, 0xb5, 0xd5, 0xaf, 0xc7, + 0xde, 0xe5, 0xbb, 0xb2, 0xec, 0xb6, 0xd4, 0xc2, 0xc5, 0xd5, 0xb8, 0xe1, 0xab, + 0xe1, 0xa4, 0xb1, 0xd2, 0xc4, 0xbb, 0xe0, 0xfe, 0xe1, 0xa3, 0xc0, 0xaa, 0xc1, + 0xce, 0xb1, 0xd7, 0xb1, 0xf0, 0xd5, 0xc3, 0xb3, 0xb9, 0xd2, 0xf3, 0xd4, 0xb8, + 0xcc, 0xac, 0xbf, 0xb6, 0xc2, 0xfd, 0xb9, 0xdf, 0xe2, 0xfa, 0xb2, 0xd1, 0xb2, + 0xd2, 0xe3, 0xbc, 0xbd, 0xd8, 0xc6, 0xb2, 0xd5, 0xaa, 0xcb, 0xa4, 0xb3, 0xb7, + 0xc3, 0xfe, 0xc2, 0xa7, 0xdf, 0xa1, 0xde, 0xe2, 0xb4, 0xdd, 0xe5, 0xba, 0xde, + 0xfd, 0xb2, 0xf4, 0xc7, 0xc3, 0xce, 0xd3, 0xc6, 0xec, 0xec, 0xbd, 0xb3, 0xa9, + 0xf4, 0xdf, 0xea, 0xd4, 0xb0, 0xf1, 0xd5, 0xa5, 0xe9, 0xc5, 0xe9, 0xc2, 0xc8, + 0xd9, 0xb8, 0xdc, 0xb9, 0xb9, 0xe9, 0xbb, 0xc8, 0xb6, 0xe9, 0xbd, 0xe9, 0xbe, + 0xc1, 0xf1, 0xbb, 0xb1, 0xc7, 0xb9, 0xe9, 0xbf, 0xe9, 0xb3, 0xa1, 0xf5, 0xc5, + 0xcc, 0xa1, 0xf5, 0xc7, 0xb8, 0xb8, 0xe8, 0xeb, 0xb5, 0xd5, 0xc4, 0xd1, 0xdd, + 0xb9, 0xf6, 0xc0, 0xec, 0xb5, 0xce, 0xe4, 0xf6, 0xd1, 0xfa, 0xc4, 0xae, 0xd7, + 0xd5, 0xc2, 0xa9, 0xc6, 0xaf, 0xba, 0xba, 0xc2, 0xfa, 0xd6, 0xcd, 0xc6, 0xe1, + 0xca, 0xfe, 0xbd, 0xa5, 0xd5, 0xc7, 0xc1, 0xb0, 0xe4, 0xee, 0xc2, 0xfe, 0xe4, + 0xf0, 0xb3, 0xba, 0xe4, 0xf4, 0xbb, 0xa6, 0xd3, 0xe6, 0xc9, 0xf8, 0xb5, 0xd3, + 0xc2, 0xb1, 0xc8, 0xdb, 0xce, 0xf5, 0xc9, 0xbf, 0xd0, 0xdc, 0xcf, 0xa8, 0xd3, + 0xab, 0xb6, 0xfb, 0xea, 0xfb, 0xdc, 0xfd, 0xd3, 0xfc, 0xe2, 0xaf, 0xd1, 0xfe, + 0xcb, 0xf6, 0xc2, 0xea, 0xb9, 0xe5, 0xe8, 0xa9, 0xd5, 0xe7, 0xd2, 0xc9, 0xc5, + 0xb1, 0xd1, 0xf1, 0xb7, 0xe8, 0xd3, 0xfa, 0xbb, 0xbe, 0xbe, 0xa1, 0xbc, 0xe0, + 0xc3, 0xe9, 0xee, 0xa5, 0xee, 0xa3, 0xcb, 0xaf, 0xb4, 0xc5, 0xb5, 0xfa, 0xb1, + 0xcc, 0xcc, 0xbc, 0xcb, 0xb6, 0xed, 0xd9, 0xec, 0xf5, 0xb8, 0xa3, 0xbb, 0xf6, + 0xd6, 0xd6, 0xb3, 0xc6, 0xcd, 0xdd, 0xce, 0xd1, 0xbd, 0xdf, 0xb6, 0xcb, 0xb9, + 0xdc, 0xbb, 0xfe, 0xbc, 0xe3, 0xf3, 0xdb, 0xcb, 0xe3, 0xf3, 0xe9, 0xb2, 0xad, + 0xf3, 0xdd, 0xf3, 0xe7, 0xb8, 0xf6, 0xa1, 0xf5, 0xb4, 0xe2, 0xf4, 0xd5, 0xbe, + 0xab, 0xd5, 0xc0, 0xe7, 0xba, 0xd7, 0xdb, 0xb4, 0xc2, 0xe7, 0xb1, 0xc2, 0xcc, + 0xbd, 0xf4, 0xd7, 0xba, 0xcd, 0xf8, 0xb8, 0xd9, 0xe7, 0xb2, 0xb3, 0xf1, 0xc3, + 0xe0, 0xb2, 0xca, 0xc2, 0xda, 0xce, 0xac, 0xd0, 0xf7, 0xe7, 0xbb, 0xe7, 0xb7, + 0xb7, 0xa3, 0xb4, 0xe4, 0xf4, 0xe4, 0xb5, 0xd4, 0xce, 0xc5, 0xbe, 0xdb, 0xd5, + 0xd8, 0xb8, 0xaf, 0xb0, 0xf2, 0xb8, 0xe0, 0xeb, 0xf5, 0xb2, 0xb2, 0xcd, 0xc8, + 0xeb, 0xf6, 0xea, 0xb0, 0xcc, 0xa8, 0xd3, 0xeb, 0xcc, 0xf2, 0xce, 0xe8, 0xf4, + 0xbb, 0xc8, 0xd8, 0xdd, 0xef, 0xcf, 0xaf, 0xd0, 0xee, 0xc3, 0xc9, 0xdd, 0xb0, + 0xc6, 0xd1, 0xcb, 0xe2, 0xb8, 0xc7, 0xd5, 0xf4, 0xdd, 0xa5, 0xdd, 0xed, 0xa1, + 0xf5, 0xb2, 0xd4, 0xcb, 0xf2, 0xdd, 0xee, 0xf2, 0xea, 0xc3, 0xdb, 0xf2, 0xdf, + 0xf2, 0xec, 0xf2, 0xe1, 0xf2, 0xe6, 0xd6, 0xa9, 0xca, 0xb4, 0xf2, 0xe9, 0xf2, + 0xe8, 0xc9, 0xd1, 0xb9, 0xd3, 0xc5, 0xe1, 0xb9, 0xfc, 0xc2, 0xe3, 0xd6, 0xc6, + 0xf1, 0xd4, 0xf1, 0xd2, 0xa1, 0xf5, 0xcb, 0xd0, 0xd6, 0xbe, 0xd3, 0xef, 0xce, + 0xdc, 0xc8, 0xcf, 0xbd, 0xeb, 0xca, 0xc4, 0xce, 0xf3, 0xcb, 0xb5, 0xda, 0xbe, + 0xbb, 0xe5, 0xd3, 0xd5, 0xda, 0xbf, 0xda, 0xbd, 0xa1, 0xf5, 0xba, 0xc0, 0xc0, + 0xea, 0xc3, 0xb2, 0xb1, 0xf6, 0xea, 0xe2, 0xc9, 0xde, 0xba, 0xd5, 0xd5, 0xd4, + 0xb8, 0xcf, 0xbe, 0xd6, 0xb8, 0xa8, 0xe9, 0xfc, 0xc7, 0xe1, 0xcd, 0xec, 0xc0, + 0xb1, 0xd4, 0xb6, 0xe5, 0xdc, 0xd1, 0xb7, 0xc7, 0xb2, 0xd2, 0xa3, 0xb5, 0xdd, + 0xe5, 0xdd, 0xa1, 0xf5, 0xe5, 0xde, 0xb1, 0xc9, 0xa1, 0xf5, 0xdb, 0xb4, 0xbd, + 0xcd, 0xcb, 0xe1, 0xbf, 0xe1, 0xf5, 0xa9, 0xbd, 0xc2, 0xd2, 0xf8, 0xcd, 0xad, + 0xc3, 0xfa, 0xee, 0xf9, 0xb8, 0xf5, 0xee, 0xfd, 0xcf, 0xce, 0xef, 0xa7, 0xa1, + 0xf5, 0xcf, 0xb3, 0xba, 0xd2, 0xb9, 0xeb, 0xc3, 0xf6, 0xb8, 0xf3, 0xb7, 0xa7, + 0xb8, 0xf3, 0xcf, 0xb6, 0xd5, 0xcf, 0xbc, 0xca, 0xb4, 0xc6, 0xf6, 0xc3, 0xd0, + 0xe8, 0xf7, 0xb0, 0xf7, 0xb1, 0xc9, 0xd8, 0xc6, 0xc4, 0xc1, 0xec, 0xec, 0xaa, + 0xcc, 0xa8, 0xbd, 0xc8, 0xb1, 0xfd, 0xb6, 0xfc, 0xe2, 0xc3, 0xb2, 0xb5, 0xb0, + 0xb9, 0xf7, 0xbb, 0xf7, 0xd6, 0xbf, 0xfd, 0xbb, 0xea, 0xc3, 0xf9, 0xf0, 0xb0, + 0xb7, 0xef, 0xc3, 0xb4, 0xb1, 0xc7, 0xc6, 0xeb, 0xd2, 0xda, 0xd2, 0xc7, 0xc6, + 0xa7, 0xbd, 0xa9, 0xbc, 0xdb, 0xd9, 0xaf, 0xbf, 0xeb, 0xbc, 0xf3, 0xa1, 0xf5, + 0xc1, 0xdd, 0xbe, 0xe7, 0xc5, 0xfc, 0xc1, 0xf5, 0xbd, 0xa3, 0xb9, 0xf4, 0xdb, + 0xc4, 0xc0, 0xf7, 0xdf, 0xeb, 0xce, 0xfb, 0xe0, 0xda, 0xb3, 0xb0, 0xba, 0xd9, + 0xd7, 0xec, 0xbb, 0xa9, 0xd0, 0xea, 0xd2, 0xad, 0xe0, 0xdb, 0xc5, 0xe7, 0xcb, + 0xbb, 0xd0, 0xa5, 0xdf, 0xb4, 0xdc, 0xaf, 0xd0, 0xe6, 0xd4, 0xf6, 0xb7, 0xd8, + 0xd7, 0xb9, 0xb6, 0xe9, 0xb6, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xd2, 0xe6, + 0xb5, 0xe6, 0xbf, 0xe5, 0xfc, 0xbd, 0xbf, 0xe6, 0xac, 0xe5, 0xbc, 0xbf, 0xed, + 0xc9, 0xf3, 0xd0, 0xb4, 0xb2, 0xe3, 0xc2, 0xc4, 0xe1, 0xd8, 0xa1, 0xf5, 0xb4, + 0xb1, 0xd6, 0xc4, 0xe1, 0xa6, 0xb7, 0xcf, 0xb3, 0xf8, 0xc3, 0xed, 0xd8, 0xcb, + 0xb9, 0xe3, 0xb3, 0xa7, 0xb5, 0xaf, 0xd3, 0xb0, 0xb5, 0xc2, 0xe1, 0xe7, 0xc7, + 0xec, 0xbb, 0xdb, 0xc2, 0xc7, 0xed, 0xab, 0xc4, 0xbd, 0xd3, 0xc7, 0xc6, 0xdd, + 0xce, 0xbf, 0xcb, 0xcb, 0xd3, 0xfb, 0xe3, 0xbf, 0xc1, 0xaf, 0xc3, 0xf5, 0xd4, + 0xf7, 0xe3, 0xbd, 0xb5, 0xac, 0xb7, 0xdf, 0xe3, 0xbe, 0xe2, 0xe4, 0xc2, 0xbe, + 0xc4, 0xa6, 0xd6, 0xbf, 0xc4, 0xa1, 0xd7, 0xb2, 0xc6, 0xcb, 0xc0, 0xcc, 0xb3, + 0xc5, 0xd7, 0xab, 0xb2, 0xa6, 0xc4, 0xd3, 0xcb, 0xba, 0xc1, 0xc3, 0xc8, 0xf6, + 0xb4, 0xe9, 0xb2, 0xa5, 0xb8, 0xa7, 0xc4, 0xed, 0xc7, 0xcb, 0xdf, 0xa4, 0xb5, + 0xa7, 0xde, 0xec, 0xb5, 0xd0, 0xb7, 0xf3, 0xca, 0xfd, 0xc4, 0xba, 0xd4, 0xdd, + 0xb1, 0xa9, 0xea, 0xc7, 0xd1, 0xf9, 0xd5, 0xc1, 0xe9, 0xa4, 0xd7, 0xae, 0xca, + 0xe0, 0xb1, 0xea, 0xb2, 0xdb, 0xc4, 0xa3, 0xc2, 0xa5, 0xb7, 0xae, 0xbd, 0xb0, + 0xc0, 0xd6, 0xe8, 0xc8, 0xe9, 0xca, 0xc1, 0xba, 0xc5, 0xb7, 0xcc, 0xbe, 0xe9, + 0xe4, 0xd2, 0xe3, 0xc5, 0xb9, 0xbd, 0xac, 0xe4, 0xfc, 0xb3, 0xce, 0xc6, 0xc3, + 0xc1, 0xca, 0xbd, 0xe0, 0xbd, 0xbd, 0xcc, 0xb6, 0xc7, 0xb1, 0xe4, 0xfa, 0xb3, + 0xb1, 0xc5, 0xec, 0xe4, 0xfd, 0xc0, 0xa3, 0xc8, 0xf3, 0xbd, 0xa7, 0xc5, 0xcb, + 0xeb, 0xf8, 0xe4, 0xb1, 0xa1, 0xf5, 0xf4, 0xaa, 0xca, 0xec, 0xb0, 0xbe, 0xc8, + 0xc8, 0xec, 0xd9, 0xeb, 0xbb, 0xa1, 0xf5, 0xbd, 0xb1, 0xe2, 0xb1, 0xd3, 0xa8, + 0xe8, 0xb0, 0xc1, 0xa7, 0xe8, 0xaa, 0xe8, 0xad, 0xe7, 0xdc, 0xf1, 0xa4, 0xb4, + 0xf1, 0xce, 0xc1, 0xc1, 0xf6, 0xca, 0xdd, 0xb4, 0xaf, 0xf1, 0xa3, 0xb0, 0xa8, + 0xd6, 0xe5, 0xc5, 0xcc, 0xcf, 0xb9, 0xc3, 0xd0, 0xee, 0xa7, 0xee, 0xa8, 0xa1, + 0xf5, 0xb4, 0xe8, 0xb0, 0xf5, 0xc8, 0xb7, 0xc0, 0xda, 0xc4, 0xeb, 0xbf, 0xc4, + 0xc2, 0xeb, 0xc5, 0xcd, 0xb8, 0xe5, 0xbc, 0xda, 0xb9, 0xc8, 0xbb, 0xfc, 0xf0, + 0xa2, 0xb5, 0xbe, 0xd2, 0xa4, 0xc7, 0xee, 0xbc, 0xfd, 0xcf, 0xe4, 0xb7, 0xb6, + 0xf3, 0xf0, 0xd7, 0xad, 0xc6, 0xaa, 0xf3, 0xf2, 0xa1, 0xf5, 0xf3, 0xf3, 0xba, + 0xfd, 0xb5, 0xde, 0xc1, 0xb7, 0xce, 0xb3, 0xd6, 0xc2, 0xbc, 0xea, 0xc3, 0xe5, + 0xbc, 0xa9, 0xb1, 0xe0, 0xd4, 0xb5, 0xcf, 0xdf, 0xb6, 0xd0, 0xbb, 0xba, 0xe7, + 0xb6, 0xe7, 0xbc, 0xe7, 0xbf, 0xe7, 0xbe, 0xc2, 0xee, 0xb0, 0xd5, 0xf4, 0xc9, + 0xf4, 0xe6, 0xf1, 0xee, 0xcc, 0xc5, 0xc4, 0xa4, 0xcf, 0xa5, 0xbd, 0xba, 0xb7, + 0xf4, 0xb1, 0xec, 0xd5, 0xe1, 0xb1, 0xce, 0xce, 0xb5, 0xc1, 0xab, 0xca, 0xdf, + 0xd2, 0xf1, 0xc2, 0xfb, 0xc3, 0xef, 0xbd, 0xaf, 0xb2, 0xcc, 0xb2, 0xb7, 0xc5, + 0xee, 0xb4, 0xd0, 0xde, 0xa3, 0xa1, 0xf5, 0xf2, 0xeb, 0xba, 0xfb, 0xb5, 0xfb, + 0xf2, 0xf0, 0xcf, 0xba, 0xce, 0xcf, 0xca, 0xad, 0xf2, 0xf9, 0xbb, 0xc8, 0xf2, + 0xf2, 0xf2, 0xf5, 0xce, 0xc0, 0xb3, 0xe5, 0xba, 0xd6, 0xb8, 0xb4, 0xb0, 0xfd, + 0xf1, 0xd9, 0xa1, 0xf5, 0xf1, 0xdb, 0xd2, 0xea, 0xc1, 0xc2, 0xcc, 0xb8, 0xd7, + 0xbb, 0xb5, 0xae, 0xc7, 0xeb, 0xd6, 0xee, 0xbf, 0xce, 0xda, 0xc3, 0xda, 0xc6, + 0xb5, 0xf7, 0xcb, 0xad, 0xc2, 0xdb, 0xda, 0xba, 0xda, 0xc7, 0xb7, 0xcc, 0xda, + 0xc4, 0xcd, 0xe3, 0xca, 0xfa, 0xd6, 0xed, 0xc5, 0xe2, 0xc9, 0xcd, 0xb8, 0xb3, + 0xbc, 0xfa, 0xd5, 0xcb, 0xb6, 0xc4, 0xcf, 0xcd, 0xc2, 0xf4, 0xb4, 0xcd, 0xd6, + 0xca, 0xe2, 0xd9, 0xf4, 0xf7, 0xcc, 0xcb, 0xc8, 0xa4, 0xa1, 0xf5, 0xbc, 0xf9, + 0xf5, 0xd7, 0xcc, 0xdf, 0xcc, 0xa4, 0xb2, 0xc8, 0xf5, 0xd8, 0xa1, 0xf5, 0xbe, + 0xe1, 0xcc, 0xc9, 0xbb, 0xd4, 0xc1, 0xbe, 0xea, 0xa1, 0xb1, 0xb2, 0xe9, 0xfd, + 0xc2, 0xd6, 0xea, 0xa2, 0xe9, 0xfe, 0xb9, 0xf5, 0xca, 0xca, 0xd5, 0xda, 0xe5, + 0xdb, 0xd4, 0xe2, 0xc7, 0xa8, 0xc1, 0xda, 0xd6, 0xa3, 0xb5, 0xcb, 0xdb, 0xb6, + 0xb4, 0xbc, 0xd7, 0xed, 0xb4, 0xd7, 0xeb, 0xe7, 0xd0, 0xbf, 0xcc, 0xe0, 0xcf, + 0xfa, 0xc6, 0xcc, 0xee, 0xed, 0xb3, 0xfa, 0xc2, 0xc1, 0xc8, 0xf1, 0xef, 0xb1, + 0xb7, 0xe6, 0xb1, 0xb5, 0xef, 0xae, 0xba, 0xb8, 0xe3, 0xcc, 0xd4, 0xc4, 0xcf, + 0xf6, 0xf6, 0xaa, 0xd5, 0xf0, 0xc3, 0xb9, 0xbf, 0xbf, 0xb0, 0xb0, 0xd0, 0xac, + 0xb9, 0xae, 0xf2, 0xa1, 0xa1, 0xf5, 0xf2, 0xa2, 0xb9, 0xce, 0xd1, 0xf8, 0xb6, + 0xf6, 0xc4, 0xd9, 0xe2, 0xc5, 0xcd, 0xd5, 0xd7, 0xa4, 0xe6, 0xe1, 0xca, 0xbb, + 0xe6, 0xe5, 0xbc, 0xdd, 0xbe, 0xd4, 0xe6, 0xe2, 0xf7, 0xbc, 0xb7, 0xa2, 0xf7, + 0xd7, 0xc4, 0xd6, 0xf7, 0xc8, 0xc6, 0xc7, 0xf6, 0xcf, 0xc2, 0xb3, 0xf0, 0xb2, + 0xd1, 0xbb, 0xf5, 0xfb, 0xf4, 0xef, 0xf7, 0xe2, 0xc0, 0xe8, 0xc4, 0xab, 0xb3, + 0xdd, 0xc8, 0xe5, 0xbe, 0xa1, 0xd9, 0xb1, 0xd9, 0xcf, 0xd9, 0xad, 0xbc, 0xbd, + 0xc3, 0xdd, 0xc4, 0xfd, 0xbc, 0xc1, 0xd8, 0xe6, 0xd1, 0xab, 0xe0, 0xdf, 0xe0, + 0xe6, 0xb5, 0xb1, 0xd8, 0xac, 0xe0, 0xe4, 0xb6, 0xd6, 0xd4, 0xeb, 0xc6, 0xf7, + 0xdf, 0xe6, 0xe0, 0xe5, 0xe0, 0xc8, 0xca, 0xc9, 0xe0, 0xde, 0xb8, 0xc1, 0xb1, + 0xda, 0xbf, 0xd1, 0xcc, 0xb3, 0xdb, 0xd5, 0xb7, 0xdc, 0xa1, 0xf5, 0xd9, 0xf8, + 0xd1, 0xa7, 0xe5, 0xbe, 0xb5, 0xbc, 0xc7, 0xbf, 0xcf, 0xdc, 0xc6, 0xbe, 0xed, + 0xac, 0xb1, 0xb9, 0xe3, 0xc1, 0xd2, 0xe4, 0xba, 0xb6, 0xb0, 0xc3, 0xd0, 0xb8, + 0xd5, 0xbd, 0xc9, 0xc3, 0xd3, 0xb5, 0xb5, 0xb2, 0xcc, 0xa2, 0xba, 0xb3, 0xbe, + 0xdd, 0xc2, 0xb0, 0xd4, 0xf1, 0xc0, 0xde, 0xb2, 0xd9, 0xbc, 0xf1, 0xc7, 0xdc, + 0xb5, 0xa3, 0xce, 0xce, 0xd5, 0xfb, 0xc0, 0xfa, 0xcf, 0xfe, 0xe5, 0xdf, 0xea, + 0xca, 0xea, 0xbc, 0xa1, 0xf5, 0xe9, 0xd7, 0xc6, 0xd3, 0xe8, 0xeb, 0xb3, 0xc8, + 0xba, 0xe1, 0xe9, 0xd9, 0xca, 0xf7, 0xe9, 0xcf, 0xcd, 0xd6, 0xcf, 0xf0, 0xc7, + 0xc5, 0xc7, 0xc1, 0xe9, 0xd4, 0xbb, 0xfa, 0xe8, 0xe3, 0xec, 0xa8, 0xc0, 0xfa, + 0xeb, 0xa9, 0xe5, 0xa5, 0xb5, 0xed, 0xd4, 0xe8, 0xc5, 0xa8, 0xd4, 0xf3, 0xd7, + 0xc7, 0xe5, 0xa2, 0xb0, 0xc4, 0xbc, 0xa4, 0xe5, 0xa3, 0xe5, 0xa4, 0xa1, 0xf5, + 0xe4, 0xc5, 0xa1, 0xf5, 0xb3, 0xe3, 0xec, 0xc0, 0xc1, 0xd7, 0xc9, 0xd5, 0xb5, + 0xc6, 0xd1, 0xe0, 0xec, 0xe4, 0xc1, 0xc7, 0xcc, 0xcc, 0xec, 0xcb, 0xc8, 0xbc, + 0xd1, 0xe6, 0xb6, 0xc0, 0xe8, 0xab, 0xe7, 0xe1, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, + 0xb1, 0xc6, 0xb0, 0xea, 0xb1, 0xdd, 0xf9, 0xd5, 0xce, 0xc8, 0xb3, 0xa1, 0xf5, + 0xc2, 0xac, 0xee, 0xc2, 0xee, 0xaa, 0xc2, 0xf7, 0xee, 0xa9, 0xc6, 0xb3, 0xc4, + 0xa5, 0xd7, 0xa9, 0xed, 0xe0, 0xed, 0xd3, 0xd3, 0xf9, 0xbb, 0xfd, 0xd3, 0xb1, + 0xc4, 0xc2, 0xf6, 0xd5, 0xa1, 0xf5, 0xbf, 0xfa, 0xb8, 0xdd, 0xa1, 0xf5, 0xd6, + 0xfe, 0xf3, 0xc6, 0xa1, 0xf5, 0xb4, 0xdb, 0xc9, 0xb8, 0xf3, 0xf7, 0xb8, 0xe2, + 0xcc, 0xc7, 0xe7, 0xcb, 0xe7, 0xcc, 0xdd, 0xd3, 0xb8, 0xbf, 0xcf, 0xd8, 0xe7, + 0xc9, 0xe7, 0xc7, 0xe7, 0xc6, 0xe7, 0xa7, 0xee, 0xbe, 0xf4, 0xcb, 0xba, 0xb2, + 0xb0, 0xbf, 0xf4, 0xe7, 0xf1, 0xf1, 0xc9, 0xc5, 0xc4, 0xe5, 0xc5, 0xf2, 0xd5, + 0xe9, 0xd0, 0xcb, 0xcb, 0xd2, 0xb2, 0xd5, 0xc8, 0xef, 0xde, 0xa5, 0xde, 0xa6, + 0xde, 0xa7, 0xb5, 0xb4, 0xde, 0xac, 0xbd, 0xb6, 0xcf, 0xf4, 0xce, 0xdf, 0xde, + 0xa9, 0xf3, 0xa6, 0xc3, 0xf8, 0xc2, 0xec, 0xd3, 0xa9, 0xc8, 0xda, 0xba, 0xe2, + 0xcd, 0xca, 0xbf, 0xe3, 0xc8, 0xec, 0xf1, 0xdd, 0xf1, 0xd7, 0xc7, 0xd7, 0xea, + 0xec, 0xda, 0xd0, 0xd1, 0xe8, 0xda, 0xc9, 0xbb, 0xe4, 0xc4, 0xb1, 0xb5, 0xfd, + 0xd0, 0xb3, 0xda, 0xd1, 0xc5, 0xb5, 0xda, 0xcb, 0xce, 0xbd, 0xb7, 0xed, 0xda, + 0xcd, 0xda, 0xcf, 0xda, 0xc8, 0xda, 0xce, 0xd4, 0xa5, 0xa1, 0xf5, 0xc3, 0xa8, + 0xc0, 0xb5, 0xcc, 0xe3, 0xf5, 0xe2, 0xd3, 0xbb, 0xf5, 0xe5, 0xf5, 0xdf, 0xf5, + 0xe0, 0xb7, 0xf8, 0xbc, 0xad, 0xca, 0xe4, 0xea, 0xa3, 0xb1, 0xe6, 0xb0, 0xec, + 0xd7, 0xf1, 0xe5, 0xe0, 0xd1, 0xa1, 0xb3, 0xd9, 0xc1, 0xc9, 0xd2, 0xc5, 0xda, + 0xfe, 0xd0, 0xd1, 0xb6, 0xa7, 0xb1, 0xed, 0xbe, 0xe2, 0xc3, 0xcc, 0xb4, 0xed, + 0xc7, 0xae, 0xb8, 0xd6, 0xce, 0xfd, 0xc2, 0xbc, 0xef, 0xa3, 0xd7, 0xb6, 0xbd, + 0xf5, 0xa1, 0xf5, 0xef, 0xbf, 0xef, 0xc0, 0xef, 0xc5, 0xd1, 0xd6, 0xcb, 0xed, + 0xcb, 0xe6, 0xcf, 0xd5, 0xb5, 0xf1, 0xf6, 0xae, 0xd5, 0xb4, 0xc1, 0xd8, 0xbb, + 0xf4, 0xc4, 0xde, 0xf6, 0xad, 0xb5, 0xe5, 0xbe, 0xb2, 0xcc, 0xf3, 0xc7, 0xca, + 0xbc, 0xd5, 0xbe, 0xb1, 0xc6, 0xb5, 0xf2, 0xa5, 0xcd, 0xb7, 0xcd, 0xc7, 0xd2, + 0xc3, 0xb2, 0xcd, 0xb9, 0xdd, 0xbd, 0xa4, 0xe2, 0xc6, 0xcf, 0xda, 0xeb, 0xc8, + 0xba, 0xa7, 0xe6, 0xe9, 0xc2, 0xe6, 0xba, 0xa1, 0xf7, 0xc0, 0xf7, 0xd9, 0xf7, + 0xda, 0xba, 0xe5, 0xb1, 0xab, 0xcd, 0xd2, 0xf0, 0xb3, 0xd1, 0xec, 0xd1, 0xbc, + 0xc1, 0xee, 0xd4, 0xa7, 0xc4, 0xac, 0xc7, 0xad, 0xc1, 0xfa, 0xb9, 0xea, 0xd3, + 0xc5, 0xb3, 0xa5, 0xc0, 0xdc, 0xb4, 0xa2, 0xc0, 0xf8, 0xba, 0xbf, 0xdf, 0xcc, + 0xb3, 0xa2, 0xe0, 0xe9, 0xcf, 0xc5, 0xcc, 0xe7, 0xba, 0xbe, 0xd1, 0xb9, 0xdb, + 0xd6, 0xa1, 0xf5, 0xd3, 0xa4, 0xe6, 0xc9, 0xe6, 0xd6, 0xc8, 0xe6, 0xde, 0xcf, + 0xe5, 0xf0, 0xd3, 0xec, 0xc1, 0xeb, 0xd4, 0xc0, 0xe1, 0xc9, 0xb0, 0xef, 0xc3, + 0xd6, 0xbb, 0xd5, 0xd3, 0xa6, 0xb6, 0xae, 0xbf, 0xd2, 0xc5, 0xb3, 0xed, 0xae, + 0xcf, 0xb7, 0xb4, 0xf7, 0xc7, 0xe6, 0xbb, 0xf7, 0xeb, 0xa2, 0xbc, 0xb7, 0xc5, + 0xa1, 0xb2, 0xc1, 0xc4, 0xe2, 0xb8, 0xe9, 0xdf, 0xaa, 0xa1, 0xf5, 0xc1, 0xb2, + 0xb1, 0xd0, 0xca, 0xef, 0xea, 0xd3, 0xcc, 0xb4, 0xb5, 0xb5, 0xcf, 0xad, 0xbc, + 0xec, 0xe8, 0xed, 0xe8, 0xce, 0xe9, 0xc9, 0xc5, 0xf6, 0xe9, 0xde, 0xe9, 0xdc, + 0xe9, 0xd1, 0xa1, 0xf5, 0xe9, 0xe7, 0xa1, 0xf5, 0xd5, 0xb1, 0xc5, 0xa2, 0xb1, + 0xf5, 0xbc, 0xc3, 0xe5, 0xa9, 0xc3, 0xc9, 0xcc, 0xce, 0xc0, 0xc4, 0xe5, 0xaa, + 0xc9, 0xac, 0xbf, 0xa3, 0xe5, 0xa6, 0xa1, 0xf5, 0xca, 0xaa, 0xe5, 0xa7, 0xce, + 0xab, 0xec, 0xdd, 0xd3, 0xaa, 0xdb, 0xc6, 0xb2, 0xd3, 0xd4, 0xef, 0xd6, 0xf2, + 0xbb, 0xd9, 0xbb, 0xe2, 0xec, 0xdb, 0xbe, 0xf4, 0xc7, 0xbd, 0xc4, 0xfc, 0xbb, + 0xf1, 0xe8, 0xb3, 0xbb, 0xb7, 0xe8, 0xa8, 0xe8, 0xb2, 0xf0, 0xec, 0xc1, 0xc6, + 0xb0, 0xa9, 0xb5, 0xb4, 0xcd, 0xab, 0xb5, 0xc9, 0xee, 0xab, 0xcb, 0xb2, 0xc7, + 0xc6, 0xc1, 0xcb, 0xbd, 0xc3, 0xc1, 0xd7, 0xbb, 0xc7, 0xed, 0xe3, 0xed, 0xb6, + 0xbd, 0xb8, 0xec, 0xfb, 0xec, 0xf8, 0xcb, 0xeb, 0xc1, 0xfe, 0xb4, 0xd8, 0xc2, + 0xa8, 0xf3, 0xfa, 0xc5, 0xf1, 0xf3, 0xf9, 0xa1, 0xf5, 0xbf, 0xb7, 0xc3, 0xd3, + 0xb7, 0xe0, 0xc4, 0xa3, 0xd4, 0xe3, 0xb2, 0xda, 0xf4, 0xd6, 0xcb, 0xf5, 0xbc, + 0xa8, 0xe7, 0xd1, 0xc2, 0xc6, 0xe7, 0xd0, 0xb1, 0xc1, 0xb7, 0xec, 0xd7, 0xdc, + 0xd7, 0xdd, 0xe7, 0xd2, 0xb7, 0xb1, 0xcf, 0xcb, 0xe7, 0xce, 0xa1, 0xf5, 0xe7, + 0xcf, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xc0, 0xf4, 0xe8, 0xd2, 0xed, 0xf1, 0xfa, + 0xc9, 0xf9, 0xb4, 0xcf, 0xc1, 0xaa, 0xcb, 0xca, 0xd2, 0xdc, 0xd3, 0xb7, 0xe2, + 0xdf, 0xb1, 0xdb, 0xcd, 0xce, 0xc5, 0xa7, 0xb5, 0xa8, 0xc1, 0xb3, 0xeb, 0xda, + 0xc1, 0xd9, 0xbe, 0xd9, 0xbc, 0xe8, 0xd0, 0xbd, 0xb1, 0xa1, 0xc0, 0xd9, 0xde, + 0xb5, 0xbd, 0xaa, 0xc7, 0xbe, 0xca, 0xed, 0xd1, 0xa6, 0xde, 0xb1, 0xde, 0xb0, + 0xbc, 0xbb, 0xbf, 0xf7, 0xf3, 0xb0, 0xf3, 0xaf, 0xf3, 0xab, 0xf2, 0xfe, 0xf3, + 0xa1, 0xf3, 0xa7, 0xf2, 0xf7, 0xc2, 0xdd, 0xf2, 0xe5, 0xf3, 0xac, 0xd9, 0xf4, + 0xf1, 0xde, 0xcf, 0xe5, 0xf1, 0xda, 0xa1, 0xf5, 0xea, 0xe9, 0xc3, 0xd5, 0xb0, + 0xf9, 0xc7, 0xab, 0xbd, 0xb2, 0xbb, 0xd1, 0xd2, 0xa5, 0xd0, 0xbb, 0xcc, 0xdc, + 0xda, 0xd7, 0xbb, 0xed, 0xcf, 0xaa, 0xe1, 0xd9, 0xd7, 0xac, 0xc8, 0xfc, 0xb9, + 0xba, 0xa1, 0xf5, 0xea, 0xe7, 0xc7, 0xf7, 0xf5, 0xe3, 0xcc, 0xa3, 0xb5, 0xb8, + 0xf5, 0xe8, 0xcf, 0xbd, 0xd5, 0xb7, 0xec, 0xb1, 0xd4, 0xaf, 0xd3, 0xdf, 0xb1, + 0xdc, 0xe5, 0xe1, 0xbb, 0xb9, 0xc2, 0xf5, 0xe5, 0xe2, 0xd1, 0xfb, 0xdb, 0xb8, + 0xf5, 0xb1, 0xd4, 0xcd, 0xb3, 0xf3, 0xb6, 0xc6, 0xc3, 0xbe, 0xc3, 0xaa, 0xbc, + 0xfc, 0xc1, 0xb4, 0xef, 0xc6, 0xb9, 0xf8, 0xb4, 0xb8, 0xef, 0xf1, 0xc7, 0xc2, + 0xb6, 0xcd, 0xef, 0xcc, 0xa1, 0xf5, 0xef, 0xc9, 0xc0, 0xab, 0xe3, 0xd7, 0xc0, + 0xbb, 0xe3, 0xc7, 0xb0, 0xe5, 0xd2, 0xfe, 0xc1, 0xa5, 0xcb, 0xe4, 0xcb, 0xaa, + 0xcf, 0xbc, 0xbe, 0xcf, 0xba, 0xab, 0xbf, 0xc5, 0xec, 0xab, 0xce, 0xb9, 0xb3, + 0xd2, 0xbf, 0xa5, 0xcf, 0xca, 0xf6, 0xde, 0xf6, 0xdb, 0xf6, 0xd9, 0xba, 0xe8, + 0xb8, 0xeb, 0xf7, 0xe7, 0xf0, 0xa4, 0xb5, 0xe3, 0xf7, 0xed, 0xf7, 0xee, 0xf7, + 0xec, 0xf7, 0xfd, 0xd5, 0xab, 0xb4, 0xd4, 0xe0, 0xe0, 0xcf, 0xf2, 0xdb, 0xdb, + 0xc0, 0xdd, 0xc9, 0xf4, 0xd2, 0xcd, 0xed, 0xaf, 0xb4, 0xc1, 0xc0, 0xa9, 0xd6, + 0xc0, 0xc8, 0xc5, 0xc4, 0xec, 0xb0, 0xda, 0xcb, 0xd3, 0xdf, 0xa2, 0xb6, 0xcf, + 0xea, 0xd7, 0xeb, 0xfc, 0xe9, 0xc4, 0xc3, 0xca, 0xb9, 0xf1, 0xbc, 0xf7, 0xc4, + 0xfb, 0xe8, 0xfe, 0xa1, 0xf5, 0xcc, 0xa8, 0xec, 0xa3, 0xb9, 0xe9, 0xe9, 0xeb, + 0xd0, 0xba, 0xe4, 0xc9, 0xc2, 0xcb, 0xe4, 0xc2, 0xbd, 0xa6, 0xc6, 0xd9, 0xe4, + 0xaf, 0xd1, 0xac, 0xbd, 0xfd, 0xec, 0xe2, 0xa1, 0xf5, 0xe1, 0xee, 0xc1, 0xd4, + 0xe8, 0xb5, 0xa1, 0xf5, 0xce, 0xcd, 0xf1, 0xb1, 0xf0, 0xdd, 0xd3, 0xfa, 0xee, + 0xad, 0xf6, 0xc4, 0xd5, 0xb0, 0xed, 0xfa, 0xb4, 0xa1, 0xc0, 0xf1, 0xf0, 0xa3, + 0xbb, 0xe0, 0xa1, 0xf5, 0xb4, 0xdc, 0xc7, 0xcf, 0xf3, 0xef, 0xbb, 0xc9, 0xf4, + 0xa2, 0xf3, 0xec, 0xf3, 0xf1, 0xbc, 0xf2, 0xc1, 0xb8, 0xd6, 0xaf, 0xc9, 0xc9, + 0xc8, 0xc6, 0xe7, 0xd4, 0xd0, 0xe5, 0xe7, 0xd5, 0xa1, 0xf5, 0xcc, 0xb3, 0xc7, + 0xcc, 0xb7, 0xad, 0xd6, 0xb0, 0xc4, 0xf4, 0xc6, 0xea, 0xeb, 0xf7, 0xbe, 0xc9, + 0xb2, 0xd8, 0xc8, 0xf8, 0xc0, 0xb6, 0xc3, 0xea, 0xbd, 0xe5, 0xde, 0xb9, 0xdc, + 0xf9, 0xde, 0xb7, 0xbc, 0xf6, 0xf2, 0xcd, 0xb2, 0xf5, 0xb3, 0xe6, 0xf3, 0xb4, + 0xb8, 0xb2, 0xea, 0xee, 0xf5, 0xfc, 0xda, 0xd3, 0xbd, 0xf7, 0xc3, 0xfd, 0xda, + 0xd8, 0xb7, 0xe1, 0xd7, 0xb8, 0xf5, 0xbe, 0xf5, 0xe7, 0xb1, 0xc4, 0xd7, 0xd9, + 0xbc, 0xa3, 0xf5, 0xcf, 0xc7, 0xfb, 0xd7, 0xaa, 0xd5, 0xde, 0xe5, 0xc7, 0xe5, + 0xe4, 0xe5, 0xe3, 0xd2, 0xbd, 0xbd, 0xb4, 0xc0, 0xe5, 0xc8, 0xdb, 0xb0, 0xf7, + 0xcb, 0xf8, 0xce, 0xd9, 0xc4, 0xf8, 0xd5, 0xf2, 0xb8, 0xe4, 0xef, 0xd7, 0xef, + 0xd3, 0xb4, 0xb8, 0xc7, 0xb9, 0xe3, 0xd8, 0xb4, 0xb3, 0xe3, 0xd9, 0xe3, 0xda, + 0xc0, 0xeb, 0xd4, 0xd3, 0xcb, 0xab, 0xb3, 0xfb, 0xbc, 0xa6, 0xa1, 0xf5, 0xf7, + 0xb7, 0xc7, 0xef, 0xb1, 0xde, 0xa1, 0xf5, 0xb6, 0xee, 0xd1, 0xd5, 0xcc, 0xe2, + 0xf2, 0xa6, 0xf2, 0xa7, 0xa1, 0xf5, 0xc1, 0xf3, 0xe2, 0xc8, 0xc0, 0xa1, 0xf7, + 0xd1, 0xf0, 0xa5, 0xc6, 0xef, 0xf7, 0xc1, 0xd7, 0xd7, 0xcb, 0xc9, 0xce, 0xba, + 0xf7, 0xcb, 0xf7, 0xcd, 0xf6, 0xe8, 0xc0, 0xf0, 0xf6, 0xea, 0xa1, 0xf5, 0xf6, + 0xe7, 0xbe, 0xe9, 0xb6, 0xec, 0xf0, 0xc0, 0xf7, 0xef, 0xa1, 0xf5, 0xf7, 0xf8, + 0xb2, 0xf6, 0xd1, 0xca, 0xbb, 0xb5, 0xc2, 0xa2, 0xdb, 0xde, 0xb3, 0xe8, 0xc5, + 0xd3, 0xc2, 0xae, 0xb3, 0xcd, 0xbb, 0xb3, 0xc0, 0xc1, 0xe3, 0xc2, 0xc5, 0xca, + 0xc2, 0xa3, 0xbf, 0xf5, 0xc6, 0xd8, 0xb3, 0xf7, 0xe8, 0xfc, 0xe9, 0xb5, 0xe9, + 0xd6, 0xe5, 0xad, 0xe4, 0xec, 0xe4, 0xfe, 0xe5, 0xab, 0xc1, 0xa4, 0xb1, 0xf4, + 0xe3, 0xf2, 0xb1, 0xac, 0xcb, 0xb8, 0xeb, 0xb9, 0xb6, 0xbf, 0xca, 0xde, 0xcc, + 0xa1, 0xe7, 0xf4, 0xc7, 0xed, 0xb0, 0xea, 0xb3, 0xeb, 0xbd, 0xae, 0xb1, 0xf1, + 0xb3, 0xd5, 0xc3, 0xc9, 0xb0, 0xad, 0xb5, 0xbb, 0xbb, 0xf1, 0xce, 0xc8, 0xc1, + 0xb1, 0xb2, 0xbe, 0xf4, 0xa4, 0xc7, 0xa9, 0xe9, 0xdc, 0xf4, 0xa6, 0xcf, 0xb5, + 0xbc, 0xeb, 0xd2, 0xef, 0xc9, 0xfe, 0xbb, 0xe6, 0xc2, 0xde, 0xbd, 0xc9, 0xeb, + 0xfe, 0xb8, 0xfe, 0xd9, 0xfa, 0xc0, 0xb0, 0xb7, 0xaa, 0xd2, 0xd5, 0xde, 0xb4, + 0xc5, 0xba, 0xcc, 0xd9, 0xd2, 0xa9, 0xa1, 0xf5, 0xd2, 0xcf, 0xd3, 0xac, 0xd0, + 0xab, 0xd0, 0xb7, 0xf3, 0xb8, 0xf1, 0xc9, 0xbd, 0xf3, 0xb0, 0xc0, 0xf4, 0xc5, + 0xbb, 0xa9, 0xc6, 0xd7, 0xca, 0xb6, 0xd6, 0xa4, 0xcc, 0xb7, 0xda, 0xdc, 0xbc, + 0xa5, 0xa1, 0xf5, 0xda, 0xdb, 0xd4, 0xf9, 0xd4, 0xde, 0xf5, 0xeb, 0xb6, 0xd7, + 0xb3, 0xf9, 0xf5, 0xea, 0xb5, 0xc5, 0xf5, 0xce, 0xf5, 0xed, 0xea, 0xa5, 0xbd, + 0xce, 0xb4, 0xc7, 0xb1, 0xdf, 0xe5, 0xe5, 0xc6, 0xc9, 0xf5, 0xb4, 0xbe, 0xb5, + 0xef, 0xe1, 0xb2, 0xf9, 0xef, 0xdf, 0xc1, 0xb4, 0xef, 0xdb, 0xef, 0xdc, 0xf7, + 0xe9, 0xef, 0xda, 0xef, 0xdd, 0xef, 0xcf, 0xef, 0xce, 0xef, 0xac, 0xf6, 0xc9, + 0xb9, 0xd8, 0xc2, 0xa4, 0xc4, 0xd1, 0xf6, 0xaf, 0xce, 0xed, 0xc3, 0xd2, 0xe8, + 0xba, 0xd4, 0xcf, 0xc0, 0xe0, 0xd4, 0xb8, 0xb5, 0xdf, 0xec, 0xac, 0xc2, 0xf8, + 0xe2, 0xcb, 0xe6, 0xf0, 0xc6, 0xad, 0xba, 0xfa, 0xbe, 0xa8, 0xf6, 0xf0, 0xf6, + 0xeb, 0xf6, 0xf4, 0xf0, 0xc8, 0xf0, 0xc4, 0xc8, 0xb5, 0xf0, 0xc6, 0xc5, 0xf4, + 0xf7, 0xe8, 0xc0, 0xf6, 0xc2, 0xb4, 0xf4, 0xf0, 0xc8, 0xb0, 0xc1, 0xfc, 0xc8, + 0xc2, 0xe0, 0xd3, 0xd1, 0xcf, 0xbd, 0xc0, 0xc8, 0xc0, 0xe6, 0xd7, 0xc4, 0xef, + 0xc4, 0xf5, 0xb1, 0xa6, 0xa1, 0xf5, 0xd0, 0xfc, 0xe2, 0xe3, 0xc8, 0xc1, 0xc0, + 0xb9, 0xb2, 0xf3, 0xea, 0xd8, 0xeb, 0xca, 0xe9, 0xb4, 0xc0, 0xbd, 0xc3, 0xd6, + 0xe4, 0xf2, 0xc2, 0xaf, 0xcf, 0xd7, 0xe7, 0xe7, 0xd1, 0xf7, 0xd5, 0xf7, 0xbf, + 0xf3, 0xed, 0xc2, 0xb7, 0xaf, 0xc0, 0xf9, 0xf1, 0xbc, 0xbe, 0xba, 0xb3, 0xef, + 0xc0, 0xba, 0xbc, 0xae, 0xc5, 0xb4, 0xcd, 0xc5, 0xb1, 0xe8, 0xe7, 0xcd, 0xbc, + 0xcc, 0xd7, 0xeb, 0xf3, 0xbf, 0xd2, 0xab, 0xeb, 0xcd, 0xbd, 0xa2, 0xd4, 0xe5, + 0xb0, 0xaa, 0xc4, 0xa2, 0xdd, 0xfe, 0xc2, 0xab, 0xc6, 0xbb, 0xcb, 0xd5, 0xd4, + 0xcc, 0xf2, 0xba, 0xc8, 0xe4, 0xf1, 0xdc, 0xbe, 0xf5, 0xb4, 0xa5, 0xd2, 0xe9, + 0xc6, 0xa9, 0xbe, 0xaf, 0xd2, 0xeb, 0xd4, 0xeb, 0xda, 0xde, 0xd3, 0xae, 0xc9, + 0xc4, 0xf5, 0xbb, 0xd4, 0xea, 0xf5, 0xee, 0xcc, 0xa4, 0xf5, 0xb7, 0xca, 0xcd, + 0xd6, 0xd3, 0xee, 0xf3, 0xd0, 0xe2, 0xb2, 0xfb, 0xf6, 0xb1, 0xc6, 0xae, 0xc8, + 0xc4, 0xbc, 0xa2, 0xdc, 0xb0, 0xe5, 0xb9, 0xcc, 0xda, 0xc9, 0xa7, 0xa1, 0xf5, + 0xc8, 0xfa, 0xf6, 0xfa, 0xcf, 0xcc, 0xc3, 0xe6, 0xb5, 0xb3, 0xf7, 0xf9, 0xf6, + 0xb4, 0xb3, 0xf6, 0xc1, 0xe4, 0xd9, 0xb3, 0xa1, 0xf5, 0xe0, 0xbf, 0xdf, 0xf9, + 0xcf, 0xf9, 0xd9, 0xe7, 0xca, 0xf4, 0xce, 0xa1, 0xbe, 0xe5, 0xc9, 0xe5, 0xc9, + 0xe3, 0xd0, 0xaf, 0xec, 0xb5, 0xea, 0xd9, 0xd3, 0xa3, 0xc0, 0xb8, 0xe8, 0xf9, + 0xbc, 0xdf, 0xb9, 0xe0, 0xc0, 0xc3, 0xce, 0xfe, 0xa1, 0xf5, 0xe8, 0xac, 0xf1, + 0xae, 0xeb, 0xca, 0xcc, 0xd9, 0xb2, 0xf8, 0xd0, 0xf8, 0xe5, 0xf1, 0xde, 0xc1, + 0xc0, 0xbc, 0xde, 0xba, 0xf2, 0xc3, 0xb4, 0xc0, 0xf3, 0xbb, 0xc0, 0xaf, 0xcd, + 0xe0, 0xa1, 0xf5, 0xc0, 0xc0, 0xc7, 0xb4, 0xbb, 0xa4, 0xd3, 0xfe, 0xd4, 0xdf, + 0xb3, 0xec, 0xd4, 0xbe, 0xf5, 0xd2, 0xba, 0xe4, 0xb1, 0xe7, 0xf5, 0xb8, 0xc1, + 0xad, 0xc0, 0xd8, 0xcc, 0xfa, 0xee, 0xf5, 0xee, 0xec, 0xef, 0xed, 0xef, 0xd4, + 0xb1, 0xd9, 0xb0, 0xd4, 0xc5, 0xf9, 0xc2, 0xb6, 0xcf, 0xec, 0xb9, 0xcb, 0xf2, + 0xab, 0xf7, 0xcf, 0xc7, 0xfd, 0xe6, 0xf4, 0xdd, 0xeb, 0xc2, 0xe2, 0xf7, 0xc3, + 0xc4, 0xa7, 0xf7, 0xce, 0xf7, 0xa2, 0xf7, 0xa4, 0xdd, 0xba, 0xba, 0xd7, 0xf0, + 0xce, 0xc8, 0xf5, 0xf7, 0xea, 0xf7, 0xf6, 0xdc, 0xb1, 0xf6, 0xb7, 0xf6, 0xb8, + 0xc4, 0xf6, 0xd9, 0xb2, 0xd9, 0xce, 0xdf, 0xbd, 0xc4, 0xd2, 0xc2, 0xde, 0xc2, + 0xcf, 0xe1, 0xdb, 0xc2, 0xcd, 0xcd, 0xe4, 0xdc, 0xb2, 0xcc, 0xaf, 0xc8, 0xa8, + 0xbb, 0xb6, 0xc8, 0xf7, 0xcc, 0xb2, 0xe2, 0xa4, 0xc8, 0xbf, 0xb5, 0xfe, 0xf1, + 0xab, 0xd1, 0xa2, 0xec, 0xfc, 0xc1, 0xfd, 0xf4, 0xa5, 0xc1, 0xfb, 0xcc, 0xfd, + 0xd4, 0xe0, 0xcf, 0xae, 0xb3, 0xc4, 0xa1, 0xf5, 0xb6, 0xc1, 0xca, 0xea, 0xd8, + 0xcd, 0xf5, 0xdc, 0xf5, 0xd9, 0xe0, 0xce, 0xdb, 0xaa, 0xd6, 0xfd, 0xbc, 0xf8, + 0xbc, 0xf8, 0xf6, 0xab, 0xf6, 0xb2, 0xf7, 0xb2, 0xe7, 0xd6, 0xb2, 0xfc, 0xf7, + 0xd2, 0xbd, 0xbe, 0xe6, 0xe7, 0xd4, 0xe0, 0xd0, 0xeb, 0xb1, 0xee, 0xf6, 0xe3, + 0xf7, 0xa7, 0xf7, 0xa9, 0xf0, 0xd1, 0xc5, 0xb8, 0xf7, 0xfa, 0xf6, 0xb9, 0xf6, + 0xba, 0xb9, 0xa8, 0xcb, 0xd5, 0xd1, 0xd2, 0xc1, 0xb5, 0xc2, 0xce, 0xbe, 0xf0, + 0xbd, 0xc1, 0xc9, 0xb9, 0xa1, 0xf5, 0xe8, 0xb6, 0xc7, 0xd4, 0xc7, 0xa9, 0xa1, + 0xf5, 0xd9, 0xdf, 0xd3, 0xa7, 0xcf, 0xcb, 0xa1, 0xf5, 0xa1, 0xf5, 0xd5, 0xba, + 0xc2, 0xdc, 0xb9, 0xc6, 0xb1, 0xe4, 0xe5, 0xce, 0xc2, 0xdf, 0xef, 0xf0, 0xee, + 0xe5, 0xa1, 0xf5, 0xd8, 0xcc, 0xcf, 0xd4, 0xf7, 0xd0, 0xbe, 0xaa, 0xe6, 0xe4, + 0xd1, 0xe9, 0xcb, 0xe8, 0xcc, 0xe5, 0xf7, 0xc7, 0xf7, 0xad, 0xc1, 0xdb, 0xf7, + 0xac, 0xf0, 0xb8, 0xf7, 0xeb, 0xc3, 0xb9, 0xd6, 0xf6, 0xb0, 0xd3, 0xc0, 0xbf, + 0xe5, 0xb1, 0xcc, 0xb1, 0xf1, 0xb2, 0xb4, 0xa3, 0xb9, 0xde, 0xee, 0xbf, 0xb2, + 0xcf, 0xf3, 0xbc, 0xe1, 0xe9, 0xc8, 0xc3, 0xb2, 0xf7, 0xda, 0xdf, 0xd1, 0xde, + 0xb8, 0xd3, 0xc4, 0xf0, 0xa1, 0xf5, 0xf6, 0xa8, 0xc1, 0xe9, 0xf6, 0xb0, 0xc7, + 0xa7, 0xf2, 0xad, 0xd6, 0xe8, 0xf7, 0xde, 0xf7, 0xca, 0xf6, 0xd7, 0xd3, 0xa5, + 0xf0, 0xd8, 0xbc, 0xee, 0xd1, 0xce, 0xf2, 0xfc, 0xf6, 0xbb, 0xc8, 0xa3, 0xcc, + 0xfc, 0xe9, 0xad, 0xcd, 0xe5, 0xc0, 0xe9, 0xc2, 0xe1, 0xc2, 0xf9, 0xb9, 0xdb, + 0xf5, 0xe6, 0xd0, 0xc6, 0xcf, 0xe2, 0xd4, 0xbf, 0xc2, 0xad, 0xb2, 0xf6, 0xf7, + 0xc5, 0xf7, 0xe0, 0xd9, 0xe4, 0xc2, 0xd0, 0xd6, 0xf5, 0xd4, 0xde, 0xc4, 0xf7, + 0xf7, 0xb5, 0xc2, 0xbf, 0xe6, 0xf7, 0xc0, 0xc2, 0xda, 0xd4, 0xf5, 0xef, 0xf5, + 0xa6, 0xd7, 0xea, 0xf6, 0xc7, 0xc2, 0xe0, 0xf6, 0xf9, 0xf6, 0xd4, 0xf7, 0xf2, + 0xd1, 0xde, 0xd4, 0xe4, 0xf0, 0xd0, 0xec, 0xe0, 0xe6, 0xea, 0xd3, 0xf4, 0xf0, + 0xd9, 0xf0, 0xbd, 0xd3, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, 0xbf, 0xdb, 0xc9, 0xd8, 0xce, 0xb3, 0xa7, 0xcd, + 0xf2, 0xd8, 0xa2, 0xd8, 0xb1, 0xd8, 0xa1, 0xe0, 0xed, 0xd8, 0xa3, 0xe5, 0xf8, + 0xe1, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xd3, 0xeb, 0xa1, 0xf5, 0xd8, 0xc1, 0xd8, + 0xec, 0xd8, 0xeb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb0, 0xba, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, + 0xaf, 0xa1, 0xf5, 0xc6, 0xf8, 0xe3, 0xdd, 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, 0xed, + 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, 0xee, 0xd9, 0xda, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xca, 0xa5, 0xa1, 0xf5, 0xba, 0xbb, 0xc4, 0xfe, + 0xe5, 0xb3, 0xa1, 0xf5, 0xe5, 0xea, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, + 0xcf, 0xa1, 0xf5, 0xe2, 0xe1, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xad, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xec, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbc, 0xbf, 0xd3, 0xc5, 0xa1, 0xf5, 0xd8, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbc, 0xdb, 0xd0, 0xc4, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xd8, 0xf3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xd9, 0xfc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xcd, 0xf2, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, 0xef, 0xd8, 0xb6, 0xdb, 0xdc, + 0xdb, 0xd9, 0xa1, 0xf5, 0xde, 0xc5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xd8, 0xde, 0xcd, + 0xa1, 0xf5, 0xe1, 0xa8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbf, 0xaa, 0xd7, + 0xaf, 0xd2, 0xec, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xe3, + 0xa1, 0xf5, 0xba, 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xc7, 0xa4, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xb9, 0xea, 0xb8, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbb, 0xfa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xeb, 0xae, 0xd9, 0xdb, 0xa1, 0xf5, 0xe3, 0xe1, 0xa1, 0xf5, 0xe3, 0xe2, + 0xe3, 0xe0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xed, 0xa1, + 0xf5, 0xe7, 0xe0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xcd, 0xf8, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, 0xb4, 0xdc, 0xb5, 0xf2, 0xae, 0xa1, 0xf5, 0xda, + 0xf8, 0xda, 0xf5, 0xa1, 0xf5, 0xda, 0xf6, 0xa1, 0xf5, 0xda, 0xe3, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xcc, + 0xe5, 0xd8, 0xf4, 0xa1, 0xf5, 0xd8, 0xfb, 0xa1, 0xf5, 0xd9, 0xa1, 0xa1, 0xf5, + 0xd9, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xbf, 0xa1, 0xf5, 0xa1, 0xf5, + 0xd8, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdf, 0xbe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb6, 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xd0, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe6, 0xa1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xa9, 0xa1, + 0xf5, 0xe1, 0xac, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xd1, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdf, 0xaf, 0xec, 0xfd, 0xec, 0xfe, 0xe2, 0xed, 0xa1, 0xf5, 0xe2, + 0xe5, 0xa1, 0xf5, 0xe2, 0xe7, 0xe2, 0xe8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xd0, 0xda, 0xd0, 0xc3, 0xbb, 0xb3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbc, 0xab, 0xa1, 0xf5, + 0xa1, 0xf5, 0xc8, 0xc5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xbf, 0xbc, 0xea, 0xba, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xbb, 0xe8, + 0xbe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xaf, + 0xeb, 0xb0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc6, + 0xe3, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xf0, + 0xa1, 0xf5, 0xe1, 0xf1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xae, 0xa1, 0xf5, 0xf0, 0xdb, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xeb, 0xc0, 0xa1, 0xf5, 0xdc, 0xb6, 0xa1, 0xf5, 0xdc, 0xba, 0xdc, 0xbb, + 0xa1, 0xf5, 0xdc, 0xb7, 0xa1, 0xf5, 0xdc, 0xb9, 0xf5, 0xf4, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xda, 0xfa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, + 0xae, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xa5, 0xd9, 0xa6, + 0xd9, 0xa8, 0xd6, 0xb6, 0xa1, 0xf5, 0xa1, 0xf5, 0xb6, 0xb1, 0xa1, 0xf5, 0xe1, + 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xb0, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xd9, 0xfe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, 0xda, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xcc, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, 0xc6, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, + 0xcf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdf, 0xca, 0xa1, 0xf5, 0xe0, 0xf2, 0xc5, 0xf7, 0xa1, 0xf5, 0xdb, + 0xe8, 0xdb, 0xe3, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xe9, 0xa1, 0xf5, 0xc7, 0xf0, + 0xdb, 0xe6, 0xdb, 0xea, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xe7, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc4, 0xa9, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xa7, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xdf, + 0xe6, 0xdb, 0xe5, 0xb5, 0xe5, 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe1, 0xb2, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xb5, 0xa1, 0xf5, + 0xe1, 0xb8, 0xc1, 0xeb, 0xe1, 0xb3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, 0xfa, 0xe0, 0xf9, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xde, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xf1, 0xe2, 0xef, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xf7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xf4, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc1, 0xaf, 0xea, 0xa7, 0xec, + 0xe6, 0xa1, 0xf5, 0xa1, 0xf5, 0xc7, 0xaf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xde, 0xd4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xd3, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xbe, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xc3, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, + 0xc4, 0xa1, 0xf5, 0xb9, 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbc, 0xab, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xed, 0xb3, 0xa1, 0xf5, 0xe3, 0xf9, 0xe3, 0xfa, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe3, 0xef, 0xe3, 0xf0, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xee, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc5, 0xa2, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xc8, 0xb2, 0xa1, 0xf5, 0xea, 0xc1, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xc0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xf4, + 0xa1, 0xf5, 0xb5, 0xa9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe7, 0xe3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xaf, 0xe7, 0xde, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xed, 0xec, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xb7, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xcb, 0xfb, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf1, 0xb6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xf4, + 0xa1, 0xf5, 0xb0, 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xc7, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, 0xbe, 0xa1, 0xf5, 0xdc, 0xc5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, 0xc7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, + 0xcc, 0xdc, 0xb8, 0xdc, 0xcd, 0xdc, 0xcb, 0xa1, 0xf5, 0xdc, 0xd2, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xb0, 0xa1, 0xf5, 0xf2, 0xb1, 0xd8, + 0xa1, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, 0xc2, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, 0xc3, + 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xfb, 0xba, 0xaa, 0xda, 0xfc, 0xdb, 0xa2, 0xa1, + 0xf5, 0xda, 0xe7, 0xda, 0xe8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xb4, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xb6, 0xa1, 0xf5, 0xd9, + 0xb7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, 0xd9, 0xef, 0xb1, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, 0xc7, + 0xc0, 0xe5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, 0xd2, 0xa1, 0xf5, 0xdf, 0xe7, 0xa1, + 0xf5, 0xa1, 0xf5, 0xdf, 0xfb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xb6, 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, 0xc3, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, + 0xda, 0xdf, 0xe8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xec, + 0xdb, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xb6, 0xe2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb8, 0xb4, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, + 0xad, 0xcf, 0xb3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xbe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xbf, 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xe1, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xb4, 0xc3, 0xa1, 0xf5, 0xe2, 0xd3, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, + 0xe8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe2, 0xfe, 0xd0, 0xda, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xe7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xbf, 0xe6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb8, 0xf1, + 0xa1, 0xf5, 0xde, 0xd9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xea, 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xc7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xc3, 0xea, 0xc4, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xd4, 0xe8, 0xde, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xb9, 0xf1, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xcf, 0xa1, 0xf5, 0xbc, 0xcf, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xd5, 0xa1, 0xf5, 0xe8, + 0xd7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xc0, 0xad, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe8, 0xda, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xe3, 0xe9, + 0xe5, 0xa1, 0xf5, 0xb1, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xb1, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xcd, 0xdd, 0xa1, 0xf5, 0xc8, + 0xf7, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xb2, 0xe4, 0xa7, 0xe4, 0xa8, 0xa1, 0xf5, + 0xe4, 0xae, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbd, 0xe0, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xa6, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xc4, 0xa1, + 0xf5, 0xa1, 0xf5, 0xec, 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xea, 0xf0, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xe6, 0xe7, + 0xec, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xce, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xb2, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xf1, 0xa1, 0xf5, 0xed, 0xed, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xf2, 0xa1, 0xf5, + 0xa1, 0xf5, 0xed, 0xbc, 0xc5, 0xf8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xed, 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xf5, 0xd6, 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf1, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, + 0xfd, 0xa1, 0xf5, 0xee, 0xb7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xe8, 0xde, 0xc7, 0xa1, 0xf5, 0xdb, 0xcf, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xcf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xeb, 0xd1, 0xca, 0xa4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, + 0xd3, 0xa1, 0xf5, 0xeb, 0xd2, 0xa1, 0xf5, 0xf4, 0xad, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xc6, 0xbb, 0xdc, 0xd8, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, 0xe6, 0xdc, + 0xfb, 0xc9, 0xbb, 0xa1, 0xf5, 0xdc, 0xda, 0xa1, 0xf5, 0xdc, 0xd3, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdc, 0xdd, 0xdc, 0xde, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, + 0xd6, 0xdc, 0xe5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf2, 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, + 0xc3, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xea, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe5, 0xc5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, + 0xa4, 0xdb, 0xa5, 0xdb, 0xa8, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xc6, 0xee, 0xc5, + 0xda, 0xeb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xb1, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xbe, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xd9, 0xc3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xb5, 0xb3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc6, + 0xe0, 0xb9, 0xcc, 0xbe, 0xbb, 0xa1, 0xf5, 0xd8, 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, + 0xd8, 0xde, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc7, 0xe6, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, 0xea, 0xdf, 0xee, + 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xc1, 0xdf, 0xc2, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, + 0xf2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xdb, 0xf4, 0xdb, 0xf8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdb, 0xf9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xd8, 0xab, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe5, 0xf2, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xa2, 0xed, 0xa3, 0xed, + 0xa4, 0xed, 0xa5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xa8, 0xa1, 0xf5, + 0xe3, 0xa6, 0xe3, 0xa7, 0xa1, 0xf5, 0xe3, 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xcd, 0xb1, 0xa1, 0xf5, 0xde, 0xdc, 0xa1, 0xf5, 0xde, + 0xda, 0xde, 0xdb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xec, 0xb7, 0xec, 0xb9, 0xec, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, + 0xc9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe8, 0xf1, 0xe8, 0xe0, 0xe8, 0xe1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc6, + 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe8, 0xe4, 0xe8, 0xe6, 0xa1, 0xf5, 0xe8, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xbd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xb4, + 0xe4, 0xb3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xb7, 0xa1, + 0xf5, 0xe4, 0xbb, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xbc, 0xa1, 0xf5, 0xcd, 0xbf, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xfe, 0xe1, 0xf9, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xfc, 0xe2, 0xa1, 0xe1, 0xfb, 0xa1, 0xf5, 0xe7, + 0xee, 0xe7, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xf2, 0xa1, 0xf5, 0xe7, 0xf1, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xac, 0xa1, 0xf5, 0xea, 0xb2, 0xa1, 0xf5, + 0xa1, 0xf5, 0xee, 0xb3, 0xa1, 0xf5, 0xf0, 0xe6, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, + 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xed, 0xf4, 0xed, 0xf2, 0xed, 0xf3, 0xa1, 0xf5, 0xed, 0xc8, + 0xed, 0xc7, 0xa1, 0xf5, 0xb2, 0xa7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xed, 0xc9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xec, 0xee, 0xa1, 0xf5, 0xec, 0xef, 0xec, 0xf0, 0xa1, 0xf5, 0xa1, 0xf5, 0xef, + 0xf8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xf6, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xc7, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf3, 0xcb, 0xf3, 0xc5, 0xf3, 0xc9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf4, 0xce, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe7, 0xa3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xee, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, + 0xb0, 0xb7, 0xeb, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf4, 0xa8, 0xf4, 0xb1, 0xa1, 0xf5, 0xdc, 0xfc, 0xdc, 0xfa, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdc, 0xe8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdc, 0xe7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xa2, 0xa1, 0xf5, + 0xdc, 0xeb, 0xdc, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdc, 0xf2, 0xa1, 0xf5, 0xdc, 0xf4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xb2, 0xe7, 0xa1, 0xf5, 0xbc, 0xeb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf2, 0xb6, 0xa1, 0xf5, 0xf2, 0xb7, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xbb, 0xb2, 0xcf, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf2, 0xba, 0xa1, 0xf5, 0xa1, 0xf5, 0xb1, 0xad, 0xf4, 0xac, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf1, 0xc4, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xc6, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf4, 0xc0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xf8, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb8, 0xcf, 0xa1, 0xf5, 0xf5, 0xc0, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xca, + 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, 0xcc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xa3, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdb, 0xae, 0xdb, 0xad, 0xdb, 0xac, 0xa1, 0xf5, 0xf4, 0xfb, 0xf4, 0xfc, + 0xf4, 0xfd, 0xee, 0xc9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xec, 0xf6, + 0xc0, 0xa1, 0xf5, 0xf7, 0xd4, 0xdb, 0xcb, 0xa1, 0xf5, 0xa1, 0xf5, 0xb1, 0xc6, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xd9, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb9, 0xd0, 0xdb, 0xc3, 0xa1, + 0xf5, 0xd8, 0xd0, 0xa1, 0xf5, 0xe0, 0xa3, 0xe0, 0xa4, 0xdf, 0xfe, 0xa1, 0xf5, + 0xdf, 0xfd, 0xa1, 0xf5, 0xdf, 0xf4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe0, 0xa7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc9, 0xb6, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe0, 0xf5, 0xe0, 0xf0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdb, 0xfa, 0xdc, 0xa5, 0xdc, 0xa4, 0xdc, 0xa3, 0xa1, 0xf5, 0xdb, + 0xfc, 0xdc, 0xa1, 0xa1, 0xf5, 0xdb, 0xef, 0xdd, 0xc0, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xeb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xdc, 0xa2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xbc, 0xe6, + 0xba, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xab, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe5, 0xed, 0xe1, 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xc1, 0xe1, 0xc3, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xc4, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xd5, 0xa1, 0xf5, 0xe2, 0xd8, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xae, 0xa1, 0xf5, 0xe3, 0xad, 0xa1, 0xf5, 0xa1, + 0xf5, 0xbe, 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xfd, + 0xa1, 0xf5, 0xde, 0xe5, 0xb5, 0xe0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, + 0xdd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xe1, 0xa1, 0xf5, 0xb6, 0xde, + 0xc6, 0xfe, 0xbe, 0xdd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xe3, 0xde, + 0xe7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xea, 0xce, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xb2, 0xce, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe8, 0xf5, 0xa1, 0xf5, 0xe8, 0xf4, 0xe8, 0xf6, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe8, 0xf8, 0xd8, 0xc3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xb1, 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xec, 0xa4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xe8, 0xa1, + 0xf5, 0xa1, 0xf5, 0xeb, 0xb4, 0xb5, 0xed, 0xe4, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, + 0xba, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xb5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xc4, 0xa1, 0xf5, 0xc4, 0xd7, 0xa1, 0xf5, + 0xe4, 0xcb, 0xa1, 0xf5, 0xe4, 0xc7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xcd, 0xe9, 0xbe, 0xd6, + 0xcc, 0xfe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xc9, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, + 0xf6, 0xe2, 0xa7, 0xe2, 0xa2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xa5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xa6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd1, 0xf7, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xc3, 0xd0, 0xed, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xed, 0xf6, 0xa1, 0xf5, 0xed, 0xf7, 0xa1, 0xf5, 0xce, 0xf8, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xd1, 0xed, 0xce, 0xb9, 0xe8, 0xed, 0xcf, + 0xa1, 0xf5, 0xec, 0xf6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xc0, 0xeb, 0xa1, 0xf5, 0xbd, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xcc, 0xa1, 0xf5, 0xf3, 0xd3, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf3, 0xd4, 0xf3, 0xd5, 0xa1, 0xf5, 0xf3, 0xce, 0xa1, 0xf5, + 0xf3, 0xd1, 0xf3, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xcd, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd5, 0xb3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xa4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xc6, 0xa1, 0xf5, 0xf1, + 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xf5, 0xa1, + 0xf5, 0xeb, 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, + 0xeb, 0xe3, 0xeb, 0xe2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf4, 0xb4, 0xf4, 0xb6, 0xa1, 0xf5, 0xf4, 0xb7, 0xa1, 0xf5, + 0xe5, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xb6, + 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xb3, 0xdd, 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdc, 0xf0, 0xdd, 0xad, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xa8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xc5, 0xf2, 0xc4, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xc5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf1, 0xc8, 0xec, 0xee, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xf3, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xfb, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf5, 0xc2, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xc1, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe5, 0xcd, 0xe5, 0xcf, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, 0xd2, 0xdb, + 0xb0, 0xa1, 0xf5, 0xa1, 0xf5, 0xb3, 0xbb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xdb, 0xaf, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xb2, 0xa1, 0xf5, 0xb7, 0xd3, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xee, 0xcc, 0xee, 0xcf, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xca, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe3, 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, + 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb4, 0xf6, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, 0xb3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, + 0xa5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, 0xae, 0xdf, 0xf6, 0xdf, 0xf7, + 0xe0, 0xaf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdc, 0xa7, 0xdc, 0xa6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe6, 0xa3, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xc4, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe1, 0xd1, 0xa1, 0xf5, 0xe1, 0xd2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xce, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xcc, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xa2, 0xa1, 0xf5, 0xe5, + 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xa2, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xfe, 0xde, 0xef, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xde, 0xeb, 0xde, 0xde, 0xa1, 0xf5, 0xde, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xde, 0xf2, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xed, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb1, 0xf3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xec, 0xbc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xc4, 0xf6, 0xa1, 0xf5, 0xa1, 0xf5, 0xc0, 0xe2, 0xe8, + 0xe2, 0xe8, 0xc7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe9, 0xa7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xb1, 0xb0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xfb, 0xa1, 0xf5, 0xe9, 0xa3, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xec, 0xa5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xc8, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xa5, 0xc7, + 0xe8, 0xed, 0xb5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xed, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xcd, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xa5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xd0, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xd4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xcc, 0xa1, + 0xf5, 0xa1, 0xf5, 0xec, 0xcd, 0xa1, 0xf5, 0xcd, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xf8, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe2, 0xa9, 0xe2, 0xae, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xfd, 0xe7, 0xfe, + 0xe7, 0xfc, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xa2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe5, 0xb8, 0xa1, 0xf5, 0xee, 0xb4, 0xf0, 0xf0, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf0, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xee, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xfb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xf3, + 0xa1, 0xf5, 0xed, 0xcc, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xcb, 0xa1, 0xf5, 0xed, + 0xd2, 0xc8, 0xb7, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xba, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xfc, 0xa1, 0xf5, 0xef, + 0xfb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xb5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, + 0xd8, 0xf3, 0xda, 0xf4, 0xd2, 0xf4, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xac, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xcf, 0xdb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc0, 0xb0, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xba, 0xca, 0xdd, 0xcf, 0xa1, 0xf5, 0xdd, 0xd2, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xc0, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xbd, + 0xdd, 0xc3, 0xdd, 0xbe, 0xdd, 0xbf, 0xa1, 0xf5, 0xdd, 0xd5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdd, 0xc5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xcc, 0xa1, 0xf5, + 0xdd, 0xc8, 0xdd, 0xc9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb9, + 0xbd, 0xa1, 0xf5, 0xdd, 0xd0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf2, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xcb, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf2, 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, + 0xcb, 0xf1, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xcc, 0xa1, 0xf5, + 0xea, 0xe8, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xfd, 0xa1, 0xf5, 0xda, 0xaa, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xaf, 0xa1, 0xf5, + 0xa1, 0xf5, 0xda, 0xb1, 0xee, 0xba, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xdc, 0xa1, 0xf5, 0xea, 0xdb, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xf2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xc5, 0xa1, 0xf5, 0xf5, 0xca, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, + 0xf7, 0xe9, 0xf2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xf4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe5, 0xd5, 0xa1, 0xf5, 0xe5, 0xd6, 0xdb, 0xa9, 0xa1, 0xf5, 0xdb, 0xb2, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xa2, 0xf4, 0xfe, 0xa1, 0xf5, + 0xf5, 0xa1, 0xa1, 0xf5, 0xee, 0xd5, 0xa1, 0xf5, 0xee, 0xd8, 0xa1, 0xf5, 0xa1, + 0xf5, 0xee, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xd9, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xd7, 0xee, 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe3, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xf1, 0xda, 0xed, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xfc, 0xa1, 0xf5, 0xe2, 0xc0, 0xa1, + 0xf5, 0xed, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xcf, 0xc9, 0xd8, 0xf1, 0xa1, 0xf5, 0xd9, + 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xdd, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, 0xc9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe0, 0xc3, 0xa1, 0xf5, 0xe0, 0xc1, 0xe0, 0xc4, 0xdf, 0xef, 0xa1, 0xf5, 0xe0, + 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, 0xb2, 0xa1, 0xf5, + 0xe0, 0xc7, 0xe0, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdb, 0xf7, 0xdb, 0xee, 0xeb, 0xf3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xba, 0xf8, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xc1, 0xa1, 0xf5, + 0xe6, 0xca, 0xa1, 0xf5, 0xeb, 0xf4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xd3, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe1, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xcf, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xb0, 0xa1, 0xf5, 0xe1, 0xe6, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe3, 0xbb, 0xe3, 0xba, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xad, 0xea, 0xae, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xb4, 0xa4, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xf7, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xf8, 0xde, 0xf9, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, + 0xf4, 0xa1, 0xf5, 0xcc, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xce, 0xe6, 0xb4, 0xb7, + 0xa1, 0xf5, 0xde, 0xf5, 0xa1, 0xf5, 0xde, 0xf6, 0xa1, 0xf5, 0xde, 0xfa, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xd2, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe9, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xa8, + 0xb4, 0xbb, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xa9, 0xe9, 0xab, 0xe9, 0xa5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xb4, 0xaa, 0xa1, 0xf5, 0xe9, 0xa2, 0xe9, 0xb1, 0xe9, 0xb2, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xd8, 0xd2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xa7, + 0xa1, 0xf5, 0xec, 0xa6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xea, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xa8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xe7, 0xa1, 0xf5, 0xe4, 0xe9, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe4, 0xda, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xe1, + 0xb3, 0xfc, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xe3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe4, 0xe6, 0xe4, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xbf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdc, 0xe4, 0xec, 0xd2, 0xec, 0xd4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xf9, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xf8, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd5, 0xe8, 0xe7, 0xe2, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xa5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xb3, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xb5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf0, 0xf1, 0xa1, 0xf5, 0xf0, 0xe2, 0xf0, 0xf3, 0xb1, 0xd4, + 0xa1, 0xf5, 0xf0, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf0, 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xfd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xd6, 0xed, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xd8, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc2, 0xe3, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb0, + 0xde, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb2, + 0xdf, 0xa1, 0xf5, 0xf3, 0xe2, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xe3, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xd3, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe7, 0xb0, 0xe7, 0xae, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xaf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xee, 0xbb, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xc7, 0xf4, 0xc8, 0xa1, 0xf5, 0xa1, + 0xf5, 0xd6, 0xfa, 0xa1, 0xf5, 0xeb, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xee, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, + 0xf2, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xe1, 0xa1, 0xf5, 0xf4, 0xba, 0xf4, 0xb9, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, + 0xe3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xd7, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xd8, 0xdd, + 0xd9, 0xa1, 0xf5, 0xdd, 0xda, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xdd, 0xa1, 0xf5, 0xdd, 0xdf, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xb1, 0xe2, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xa6, 0xd2, + 0xa9, 0xa1, 0xf5, 0xdd, 0xe5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xcc, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xd9, 0xa1, 0xf5, 0xf2, 0xdd, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf2, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf1, 0xce, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xa1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf5, 0xfe, 0xb4, 0xa5, 0xa1, 0xf5, 0xda, 0xb2, 0xda, 0xb4, 0xda, + 0xbc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xb3, 0xda, 0xb7, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb5, 0xc7, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xf7, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xf4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf4, 0xf3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf5, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xd0, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xbc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xfb, 0xe9, 0xfa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe5, 0xd9, 0xa1, 0xf5, 0xe5, 0xd7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd4, 0xc7, 0xda, 0xf9, 0xa1, 0xf5, 0xa1, + 0xf5, 0xcd, 0xaa, 0xf5, 0xa5, 0xee, 0xe8, 0xa1, 0xf5, 0xee, 0xe6, 0xee, 0xda, + 0xee, 0xdb, 0xee, 0xdd, 0xa1, 0xf5, 0xee, 0xe1, 0xef, 0xa5, 0xee, 0xea, 0xa1, + 0xf5, 0xa1, 0xf5, 0xee, 0xe3, 0xee, 0xe2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xda, 0xf3, 0xf6, 0xc2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xbd, 0xf9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xfe, 0xa1, + 0xf5, 0xf1, 0xfd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xd9, 0xec, 0xa1, 0xf5, 0xf6, 0xbc, 0xd9, 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, + 0xd9, 0xc7, 0xc0, 0xfc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xd9, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xd8, 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, + 0xd7, 0xa1, 0xf5, 0xe0, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, 0xc5, 0xdf, 0xe9, + 0xe0, 0xd2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xdc, 0xad, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xdc, 0xac, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc9, + 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe6, 0xcb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, 0xef, 0xe1, 0xd6, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xd0, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe0, 0xfd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xdb, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xda, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xa8, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xa5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe2, 0xe6, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xaf, 0xea, 0xa8, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, + 0xd2, 0xa1, 0xf5, 0xbf, 0xd9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xc1, 0xcc, 0xde, 0xfb, 0xde, 0xe8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xa1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xc1, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe9, 0xb6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xbc, 0xe9, 0xc7, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe8, 0xe7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xc0, 0xa1, + 0xf5, 0xe9, 0xc3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xbf, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xf8, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xe6, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, 0xfe, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xb0, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe4, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc5, 0xbd, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xf1, 0xa1, 0xf5, + 0xe4, 0xef, 0xa1, 0xf5, 0xe4, 0xdd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, + 0xd3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd1, 0xac, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xec, 0xc1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xb4, 0xf4, 0xe2, 0xb0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xf8, 0xf0, + 0xfd, 0xa1, 0xf5, 0xf0, 0xfa, 0xa1, 0xf5, 0xf1, 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, + 0xb3, 0xf2, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xa6, 0xa1, 0xf5, 0xd8, 0xba, 0xa1, + 0xf5, 0xed, 0xda, 0xa1, 0xf5, 0xb2, 0xea, 0xed, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xec, 0xf9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb1, 0xe2, 0xa1, 0xf5, 0xf1, 0xbf, 0xa1, 0xf5, + 0xf1, 0xbe, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, + 0xe4, 0xa1, 0xf5, 0xb9, 0xbf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xeb, + 0xa1, 0xf5, 0xd4, 0xfd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf4, 0xd4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xb9, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, + 0xb5, 0xa1, 0xf5, 0xe7, 0xb3, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xb8, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xeb, 0xf4, 0xec, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xe3, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, 0xbc, 0xeb, 0xf0, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xf5, 0xa1, 0xf5, 0xdd, 0xf2, + 0xa1, 0xf5, 0xdd, 0xf0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdd, 0xf3, 0xdd, 0xf4, 0xdd, 0xe8, 0xdd, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdd, 0xea, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, + 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, 0xe1, 0xa1, 0xf5, + 0xb1, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf2, 0xde, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xe2, 0xf2, 0xe0, 0xc0, + 0xaf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xe4, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd1, + 0xd1, 0xa1, 0xf5, 0xf2, 0xe7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xe3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf1, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xd5, 0xa1, 0xf5, 0xf1, 0xd3, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, + 0xea, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xa2, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xc0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xea, 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xd4, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xd5, 0xd3, 0xbb, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf5, 0xbd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xb5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, + 0xb3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf5, 0xa8, 0xf5, 0xaa, 0xa1, 0xf5, 0xd2, 0xbf, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xee, 0xef, 0xee, 0xee, 0xa1, 0xf5, 0xee, 0xf0, 0xa1, 0xf5, + 0xee, 0xf7, 0xef, 0xa2, 0xef, 0xa4, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xfe, 0xef, + 0xa8, 0xee, 0xf1, 0xf6, 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xfb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xa9, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xba, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xd9, 0xd3, 0xd9, 0xd8, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xd9, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd8, 0xdb, 0xdb, 0xbd, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, 0xe1, 0xdf, 0xd8, 0xb6, 0xf1, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, 0xd9, 0xd1, 0xb0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe0, 0xdc, 0xa1, 0xf5, 0xdf, 0xbc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xd7, 0xe1, 0xc0, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe1, 0xbd, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xdc, 0xa1, 0xf5, 0xe2, 0xd0, 0xa1, 0xf5, 0xa1, + 0xf5, 0xb1, 0xef, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, + 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xfe, 0xa1, 0xf5, 0xbe, 0xef, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb5, 0xa7, 0xde, 0xd8, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xcb, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc1, 0xac, 0xa1, 0xf5, 0xe9, 0xc8, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, + 0xce, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xfd, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe9, 0xcc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xa7, 0xa1, 0xf5, 0xf2, 0xa3, 0xa1, 0xf5, + 0xa1, 0xf5, 0xc0, 0xd4, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xf8, 0xe4, 0xf7, 0xe4, + 0xf9, 0xe4, 0xea, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xb3, 0xce, 0xa1, 0xf5, 0xe4, 0xfb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, + 0xb6, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xda, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, + 0xd8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xd7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, + 0xe1, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xb2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xaf, 0xe7, 0xf6, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe8, 0xae, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xfb, 0xf0, 0xf9, 0xf0, 0xfe, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xa1, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xa4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xed, 0xdd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xdf, 0xec, 0xfa, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xa1, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xc1, 0xa1, 0xf5, 0xf3, 0xe6, 0xa1, 0xf5, 0xf3, + 0xe8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xdb, + 0xf4, 0xda, 0xf4, 0xd8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe7, 0xbd, 0xe7, 0xc5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xc1, 0xe7, 0xc2, + 0xe7, 0xc3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, + 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xe5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xf9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc6, 0xcc, 0xf4, 0xbc, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xa2, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xfd, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc4, 0xe8, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdd, 0xf8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xa4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, 0xea, + 0xdd, 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, 0xe0, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, + 0xfb, 0xdc, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xbd, 0xa1, 0xf5, 0xf2, 0xf6, 0xf2, 0xf8, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xd0, 0xab, 0xce, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf2, 0xf3, 0xa1, 0xf5, 0xf2, 0xfa, 0xa1, 0xf5, 0xf2, 0xef, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xd8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xc1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, + 0xc2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xc5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd6, 0xdc, 0xa1, 0xf5, + 0xea, 0xe3, 0xa1, 0xf5, 0xea, 0xe6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf5, 0xdb, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xda, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, + 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xdb, 0xb7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb5, 0xa6, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf5, 0xac, 0xd5, 0xb5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xb6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xee, 0xf2, 0xef, 0xab, 0xef, 0xb7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xef, 0xb2, 0xee, 0xfa, 0xef, 0xaf, 0xa1, 0xf5, 0xef, 0xb0, 0xa1, 0xf5, 0xf6, + 0xc8, 0xa1, 0xf5, 0xef, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xcf, 0xe3, 0xcd, 0xa1, 0xf5, 0xd1, 0xd6, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xac, 0xa1, 0xf5, 0xf6, + 0xa6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf2, 0xa4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xc4, 0xb2, 0xb8, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, + 0xe0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xe6, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xd8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf7, 0xc9, 0xd0, 0xd0, 0xf6, 0xd0, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xe0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xb1, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xd8, 0xbe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, 0xd5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xdf, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, 0xe0, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe0, 0xf7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xd4, 0xa1, 0xf5, 0xe6, 0xd3, 0xe6, 0xcd, + 0xa1, 0xf5, 0xe6, 0xc8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xd4, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe1, 0xbb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xde, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xdd, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe1, 0xe8, 0xed, 0xad, 0xba, 0xa9, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xf8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xdf, 0xa8, 0xa1, 0xf5, 0xdf, 0xa7, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xd5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe9, 0xd0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xd3, 0xa1, + 0xf5, 0xe9, 0xd8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe9, 0xd2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xec, 0xe9, + 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xab, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc2, + 0xba, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe4, 0xab, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, 0xa1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xec, 0xc7, 0xa1, 0xf5, 0xec, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xb3, + 0xa1, 0xf5, 0xe1, 0xfd, 0xe1, 0xf6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf1, 0xa6, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xac, 0xf1, 0xa2, 0xf1, 0xa9, 0xa1, + 0xf5, 0xf1, 0xa7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xab, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xd7, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xc0, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xf4, 0xa1, + 0xf5, 0xf3, 0xf6, 0xf3, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xf8, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf4, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe7, 0xc8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xc4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc5, 0xd5, 0xf1, 0xf0, 0xa1, 0xf5, 0xa1, 0xf5, + 0xec, 0xa2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc1, 0xcb, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xa1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, + 0xbf, 0xa1, 0xf5, 0xdc, 0xe9, 0xa1, 0xf5, 0xdd, 0xdb, 0xde, 0xa8, 0xdd, 0xa1, + 0xdd, 0xde, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xdc, 0xf1, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xb5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdc, 0xbc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xa5, + 0xf2, 0xfb, 0xa1, 0xf5, 0xf3, 0xa2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xa3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf2, 0xcf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe5, 0xbd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd0, + 0xfa, 0xda, 0xbb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xca, + 0xda, 0xcc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xd2, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xde, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xe1, 0xf5, 0xe4, 0xd3, 0xe2, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xa6, 0xa1, 0xf5, 0xf5, 0xad, 0xf5, 0xaf, + 0xf5, 0xae, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xc3, 0xef, 0xc4, 0xef, + 0xba, 0xa1, 0xf5, 0xd5, 0xe0, 0xef, 0xaa, 0xa1, 0xf5, 0xef, 0xbc, 0xa1, 0xf5, + 0xef, 0xb9, 0xef, 0xbe, 0xee, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xd5, 0xa1, 0xf5, 0xe3, 0xd0, 0xd1, + 0xcb, 0xa1, 0xf5, 0xe3, 0xd1, 0xe3, 0xd3, 0xa1, 0xf5, 0xe3, 0xd4, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, + 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb2, 0xb5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, + 0xdb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xd6, 0xf6, 0xd8, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xb6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf0, 0xb7, 0xf7, 0xe6, 0xa1, 0xf5, 0xf7, 0xe5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xfc, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe0, 0xea, 0xdf, 0xe2, 0xa1, 0xf5, 0xe0, 0xe3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe1, 0xda, 0xe0, 0xfc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xfb, + 0xa1, 0xf5, 0xb1, 0xf7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, 0xa9, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe9, 0xdd, 0xa1, 0xf5, 0xe8, 0xdf, 0xbc, 0xd6, 0xa1, 0xf5, 0xa1, + 0xf5, 0xbd, 0xe2, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xdb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbd, 0xa9, 0xa1, 0xf5, 0xa1, 0xf5, + 0xed, 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe5, 0xa8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe1, 0xfd, 0xe2, 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe8, 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xea, 0xb5, 0xa1, 0xf5, 0xea, 0xb4, 0xa1, 0xf5, 0xf1, 0xaa, 0xa1, 0xf5, + 0xf0, 0xf7, 0xf0, 0xef, 0xf0, 0xab, 0xa1, 0xf5, 0xee, 0xac, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xed, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xe1, 0xed, + 0xe2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xfc, 0xa1, 0xf5, 0xf3, 0xe5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xfe, 0xf3, 0xd9, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xc0, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xdd, 0xe7, 0xca, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf4, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xe3, 0xf4, 0xea, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf3, 0xc1, 0xa1, 0xf5, 0xee, 0xc0, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf1, 0xef, 0xeb, 0xfe, 0xa1, 0xf5, 0xeb, 0xfb, 0xeb, 0xfd, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc2, 0xa6, 0xf4, 0xbd, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xb2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xde, 0xae, 0xde, 0xaf, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xf7, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xcc, 0xea, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, 0xf6, 0xde, 0xb6, 0xde, 0xb3, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xdd, 0xb2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xa4, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xa9, 0xa1, 0xf5, 0xf3, 0xaa, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xfc, + 0xd5, 0xdd, 0xf3, 0xb1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, + 0xae, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf1, 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xed, 0xa1, + 0xf5, 0xa1, 0xf5, 0xec, 0xb2, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xd5, 0xa1, 0xf5, + 0xd6, 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, + 0xc0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xd6, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, + 0xf9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf5, 0xc4, 0xe5, 0xbf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xc3, 0xd1, 0xf5, 0xb0, 0xc8, 0xa9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xca, 0xa1, + 0xf5, 0xef, 0xc7, 0xd5, 0xeb, 0xd5, 0xa1, 0xa1, 0xf5, 0xef, 0xc8, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xcc, 0xa1, 0xf5, 0xf6, + 0xca, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xd6, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xf4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xba, 0xfd, 0xa1, 0xf5, 0xe2, 0xbc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xd9, 0xe5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xcc, 0xf6, 0xda, 0xa1, 0xf5, 0xf6, 0xdc, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf0, 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xbb, 0xa1, 0xf5, 0xf0, 0xbc, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xed, 0xea, 0xf6, 0xbd, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xf7, 0xf6, 0xb3, 0xd9, + 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xc4, 0xf6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xa1, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xde, 0xf3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xdf, 0xa3, 0xa1, 0xf5, 0xe1, 0xa6, 0xa1, 0xf5, 0xea, 0xd6, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xec, 0xf2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xde, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe4, 0xf3, 0xe3, 0xf8, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xde, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xb6, 0xf1, 0xb0, 0xf0, 0xdc, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xe4, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xa1, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xa3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xbb, 0xdd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xc0, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xf9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf4, 0xbe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdd, 0xa3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xb2, 0xa1, 0xf5, 0xf3, 0xb3, 0xf3, 0xa8, 0xa1, + 0xf5, 0xf6, 0xe0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xad, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf2, 0xb1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xc7, 0xfe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xd0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xda, 0xa9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xc3, 0xa1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xa5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf5, 0xf8, 0xa1, 0xf5, 0xd8, 0xd3, 0xea, 0xde, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xc5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xd4, 0xe3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, + 0xbf, 0xa1, 0xf5, 0xea, 0xa4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xda, 0xf7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, + 0xb5, 0xf5, 0xb2, 0xef, 0xd8, 0xc1, 0xad, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xf8, 0xa1, 0xf5, 0xef, 0xcb, 0xa1, 0xf5, 0xef, + 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xf6, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xc4, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xb6, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xbe, + 0xa1, 0xf5, 0xe6, 0xeb, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xec, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe6, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xc2, 0xa1, 0xf5, + 0xf7, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xd2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf6, 0xe9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xe1, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf0, 0xc3, 0xf0, 0xbe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xc1, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xf0, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xd8, 0xc9, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, 0xbf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdb, 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xdf, 0xab, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe8, 0xdd, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xcd, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe9, 0xda, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xaa, 0xa1, 0xf5, 0xe3, + 0xf1, 0xe4, 0xeb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, 0xac, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xed, 0xe7, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xe6, 0xec, 0xf2, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xd8, 0xa1, + 0xf5, 0xe7, 0xd9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xbc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf4, 0xaf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xde, 0xbc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd9, 0xf9, 0xf2, 0xc9, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xb2, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, + 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xcf, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xef, 0xa1, + 0xf5, 0xf6, 0xa3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xda, 0xda, 0xd7, 0xab, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb2, + 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xec, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xb3, 0xef, 0xde, 0xef, 0xe0, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xa5, 0xef, 0xea, 0xa1, 0xf5, 0xef, 0xd2, 0xa1, + 0xf5, 0xef, 0xa1, 0xa1, 0xf5, 0xf6, 0xcb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, + 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xf2, 0xaa, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xca, 0xa1, 0xf5, 0xe2, 0xc9, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf7, 0xc4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf6, 0xec, 0xf6, 0xed, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xef, 0xa1, + 0xf5, 0xf6, 0xf2, 0xf6, 0xf3, 0xf6, 0xf6, 0xf6, 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xee, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xb5, 0xf1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf0, 0xc7, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xed, 0xeb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, + 0xb7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xfc, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xd0, 0xa1, 0xf5, + 0xe8, 0xc0, 0xe8, 0xd3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xe5, 0xaf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, 0xae, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xa8, + 0xe8, 0xb7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xdb, 0xc7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xed, 0xe5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xe7, 0xd7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf1, 0xf7, 0xa1, 0xf5, 0xa1, 0xf5, 0xd0, 0xc6, 0xf4, 0xbf, 0xa1, 0xf5, + 0xdc, 0xd7, 0xde, 0xbd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdc, + 0xc2, 0xde, 0xad, 0xa1, 0xf5, 0xde, 0xbf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf2, 0xd3, 0xf2, 0xee, 0xa1, 0xf5, 0xf3, 0xb7, 0xf3, 0xb6, 0xa1, 0xf5, 0xf1, + 0xe0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbb, 0xd9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xdb, 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xb6, 0xa1, + 0xf5, 0xa1, 0xf5, 0xef, 0xa6, 0xef, 0xe6, 0xa1, 0xf5, 0xef, 0xe8, 0xa1, 0xf5, + 0xef, 0xe2, 0xa1, 0xf5, 0xa1, 0xf5, 0xc1, 0xcd, 0xef, 0xd0, 0xef, 0xeb, 0xa1, + 0xf5, 0xee, 0xfc, 0xa1, 0xf5, 0xef, 0xe4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xef, 0xa9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xdb, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf2, 0xa9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xcd, 0xc0, 0xa1, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xe3, 0xa1, 0xf5, + 0xe6, 0xf2, 0xe6, 0xf3, 0xe6, 0xef, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xf8, 0xca, 0xc7, 0xa1, 0xf5, + 0xf6, 0xfb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf6, 0xfc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf0, 0xc9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xca, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xf4, 0xa1, 0xf5, 0xf7, 0xf3, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xb6, 0xa1, 0xf5, 0xa1, + 0xf5, 0xf6, 0xb5, 0xa1, 0xf5, 0xd9, 0xd0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbf, 0xf9, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xdf, 0xa5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe9, 0xb7, 0xa1, 0xf5, 0xe3, 0xe3, 0xe4, 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, 0xdf, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xb5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xc3, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf4, 0xcf, 0xe6, 0xfe, 0xa1, 0xf5, 0xe7, 0xd3, 0xa1, 0xf5, + 0xa1, 0xf5, 0xc0, 0xdb, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xde, 0xbe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xc0, 0xdd, 0xfc, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xba, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xc3, 0xef, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xea, 0xe1, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdb, 0xba, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xee, 0xa1, 0xf5, + 0xbb, 0xb7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xcb, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xec, 0xad, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xe6, 0xf5, 0xe6, 0xee, 0xe6, 0xf1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xe5, 0xf7, 0xa3, 0xf7, + 0xa5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xcf, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, + 0xbd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xbc, 0xb9, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, + 0xba, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xd9, 0xe6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xae, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd4, + 0xdc, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xeb, 0xac, 0xc0, 0xec, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf1, 0xa8, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf0, 0xa6, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xea, 0xa1, 0xf5, 0xa1, + 0xf5, 0xc2, 0xab, 0xd9, 0xe1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf4, 0xb5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xea, 0xeb, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xd9, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf5, 0xe9, 0xf5, 0xf0, + 0xf5, 0xd1, 0xf5, 0xc8, 0xf5, 0xf1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, + 0xf6, 0xa1, 0xf5, 0xef, 0xd9, 0xa1, 0xf5, 0xef, 0xec, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xd3, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe6, 0xf6, 0xa1, 0xf5, 0xe6, 0xe8, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe5, 0xf7, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xa8, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, + 0xe4, 0xf7, 0xa6, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xe6, 0xa1, 0xf5, 0xf7, 0xa1, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xd2, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xba, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xed, 0xe8, + 0xba, 0xcd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xdf, 0xac, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe8, 0xef, 0xe9, + 0xa1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xd3, 0xb8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xdd, 0xf1, 0xa1, 0xf5, 0xa1, 0xf5, 0xde, 0xc2, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xee, 0xc3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd1, 0xe7, 0xf6, 0xc5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe9, 0xf1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc0, 0xb0, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xdf, 0xa1, 0xf5, 0xf7, + 0xae, 0xf6, 0xe0, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xd1, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xd3, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf0, 0xd6, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xf0, 0xd4, 0xf0, 0xd5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xc2, 0xf0, + 0xc2, 0xa1, 0xf5, 0xb7, 0xb2, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xfb, 0xa1, 0xf5, 0xa1, 0xf5, 0xec, + 0xb4, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xc4, 0xf6, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xe5, 0xb0, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xfd, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xbd, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xc0, 0xbe, 0xf5, 0xf3, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xce, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, + 0xc6, 0xa1, 0xf5, 0xa1, 0xf5, 0xf7, 0xaf, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xd3, 0xae, 0xa1, 0xf5, 0xa1, 0xf5, 0xdd, 0xba, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe0, + 0xec, 0xdf, 0xad, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, + 0xd6, 0xa1, 0xf5, 0xf4, 0xd0, 0xa1, 0xf5, 0xe7, 0xda, 0xf4, 0xee, 0xa1, 0xf5, + 0xd9, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf1, 0xe1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xb4, 0xda, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xef, 0xe7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe2, 0xc3, 0xa1, 0xf5, 0xa1, 0xf5, 0xf6, 0xdd, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf6, 0xbe, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf3, 0xbd, 0xf4, 0xf5, 0xf5, + 0xf2, 0xf5, 0xa7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xda, 0xdd, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xf2, 0xa8, 0xc8, 0xa7, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xe6, 0xf8, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xf0, 0xb5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xed, 0xb0, 0xe8, 0xf9, 0xa1, 0xf5, 0xb1, 0xee, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xe3, 0xce, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xf6, 0xe2, 0xf0, 0xbf, 0xe4, 0xd9, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xd0, 0xe2, 0xc0, 0xef, 0xa1, 0xf5, + 0xba, 0xe3, 0xd7, 0xb1, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, + 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, + 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, 0xa1, 0xf5, +}; + +} // namespace FQTerm diff --git a/src/utilities/fqterm_convert.h b/src/utilities/fqterm_convert.h new file mode 100644 index 0000000..d7b226c --- /dev/null +++ b/src/utilities/fqterm_convert.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_CONVERT_H +#define FQTERM_CONVERT_H + +namespace FQTerm { + +class FQTermConvert { + public: + FQTermConvert(); + ~FQTermConvert(); + + char *G2B(const char *string, int length); + char *B2G(const char *string, int length); + + private: + void g2b(unsigned char c1, unsigned char c2, char *s); + void b2g(unsigned char c1, unsigned char c2, char *s); + + static unsigned char GtoB[]; + static unsigned char BtoG[]; +}; + +} // namespace FQTerm + +#endif // FQTERM_CONVERT_H diff --git a/src/utilities/fqterm_http.cpp b/src/utilities/fqterm_http.cpp new file mode 100644 index 0000000..57cde46 --- /dev/null +++ b/src/utilities/fqterm_http.cpp @@ -0,0 +1,264 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm.h" +#include "fqterm_path.h" +#include "fqterm_http.h" +#include "fqterm_config.h" +#include "fqterm_filedialog.h" + +namespace FQTerm { + +QMap FQTermHttp::downloadMap_; +QMutex FQTermHttp::mutex_; + +FQTermHttp::FQTermHttp(FQTermConfig *config, QWidget *p, const QString &poolDir, int serverEncodingID) + : nam_(new QNetworkAccessManager), poolDir_(poolDir) { + // m_pDialog = NULL; + config_ = config; + + serverEncodingID_ = serverEncodingID; + + } + +FQTermHttp::~FQTermHttp() { +} + +void FQTermHttp::cancel() { + if(netreply_){ + netreply_->abort(); + } + if (QFile::exists(cacheFileName_)) { + QFile::remove(cacheFileName_); + } + + emit done(this); +} + + + +void FQTermHttp::getLink(const QString &url, bool preview) { + QUrl u(url); + getLink(u,preview); +} + +void FQTermHttp::getLink(const QUrl& url, bool preview) { + QUrl u=url; + isExisting_ = false; + isPreview_ = preview; + previewEmitted = false; + lastPercent_ = 0; + if (u.isRelative() || u.scheme() == "file") { + emit previewImage(cacheFileName_, false, true); + emit done(this); + return ; + } + + if (QFile::exists(getPath(USER_CONFIG) + "hosts.cfg")) { + config_ = new FQTermConfig(getPath(USER_CONFIG) + "hosts.cfg"); + QString strTmp = config_->getItemValue("hosts", u.host().toLocal8Bit()); + if (!strTmp.isEmpty()) { + QString strUrl = u.toString(); + strUrl.replace(QRegExp(u.host(), Qt::CaseInsensitive), strTmp); + u = strUrl; + } + } + if (!(netreply_ && netreply_->hasRawHeader("Location"))) { + cacheFileName_ = QFileInfo(u.path()).fileName(); + } + if(netreply_){ + netreply_->blockSignals(true); + netreply_.take()->deleteLater(); + } + + netreply_.reset(nam_->get(QNetworkRequest(u))); + FQ_VERIFY(connect(netreply_.data(), SIGNAL(finished()), this, SLOT(httpDone()))); + FQ_VERIFY(connect(netreply_.data(), SIGNAL(downloadProgress(qint64, qint64)),this, SLOT(httpRead(qint64, qint64)))); + FQ_VERIFY(connect(netreply_.data(), SIGNAL(error( QNetworkReply::NetworkError)), this, SLOT(httpError(QNetworkReply::NetworkError)))); + FQ_VERIFY(connect(netreply_.data(), SIGNAL(metaDataChanged()), this, SLOT(httpResponse()))); +} + +void FQTermHttp::httpResponse() { + if (netreply_->hasRawHeader("Location")) { + //FIXME: according to RC, this code still could not work + //if the server send the relative location. + QString realLocation = netreply_->header(QNetworkRequest::LocationHeader).toString(); + QUrl u = realLocation; + if (u.isRelative() ) { + u=netreply_->url().resolved(u); + } + cacheFileName_ = QFileInfo(u.path()).fileName(); // update filename + getLink(u,isPreview_); + return; + } + + QString ValueString; + QString filename; + + ValueString = netreply_->header(QNetworkRequest::ContentLengthHeader).toString(); + int FileLength = ValueString.toInt(); + + ValueString = netreply_->rawHeader("Content-Disposition"); + // ValueString = ValueString.mid(ValueString.find(';') + 1).stripWhiteSpace(); + // if(ValueString.lower().find("filename") == 0) + // m_strHttpFile = ValueString.mid(ValueString.find('=') + 1).stripWhiteSpace(); + if (ValueString.right(1) != ";") { + ValueString += ";"; + } + QRegExp re("filename=.*;", Qt::CaseInsensitive); + re.setMinimal(true); + //Dont FIXME:this will also split filenames with ';' inside, does anyone really do this? + int pos = re.indexIn(ValueString); + if (pos != -1) { + cacheFileName_ = ValueString.mid(pos + 9, re.matchedLength() - 10); + } + //cacheFileName_ = encoding2unicode(cacheFileName_.toLatin1(), serverEncodingID_); + filename = cacheFileName_; + + if (isPreview_) { + cacheFileName_ = poolDir_ + cacheFileName_; + + QFileInfo fi(cacheFileName_); + + int i = 1; + QFileInfo fi2 = fi; + + mutex_.lock(); + if (downloadMap_.find(cacheFileName_) == downloadMap_.end() && !fi2.exists()) { + downloadMap_[cacheFileName_] = FileLength; + } + while (fi2.exists()) { + + QMap::iterator ii; + if ((ii = downloadMap_.find(cacheFileName_)) != downloadMap_.end()) { + if (ii.value() == FileLength) { + mutex_.unlock(); + netreply_->abort(); + isExisting_ = true; + emit headerReceived(this, filename); + emit done(this); + return; + } + } + + if (fi2.size() == FileLength) { + mutex_.unlock(); + isExisting_ = true; + emit headerReceived(this, filename); + netreply_->abort(); + return; + } else { + cacheFileName_ = QString("%1/%2(%3).%4").arg(fi.path()) + .arg(fi.completeBaseName()).arg(i).arg(fi.suffix()); + fi2.setFile(cacheFileName_); + if (!fi2.exists()) { + downloadMap_[cacheFileName_] = FileLength; + break; + } + + i++; + } + } + mutex_.unlock(); + + fi.setFile(cacheFileName_); + + QString strExt = fi.suffix().toLower(); + if (strExt == "jpg" || strExt == "jpeg" || strExt == "gif" || strExt == "mng" + || strExt == "png" || strExt == "bmp") { + isPreview_ = true; + } else { + isPreview_ = false; + } + } else { + //getSaveFileName(cacheFileName_, NULL, strSave); + mutex_.lock(); + + FQTermFileDialog fileDialog(config_); + QString strSave = fileDialog.getSaveName(cacheFileName_, "*"); + mutex_.unlock(); + // no filename specified which means the user canceled this download + if (strSave.isEmpty()) { + netreply_->abort(); + emit done(this); + return ; + } + cacheFileName_ = strSave; + } + + emit headerReceived(this, filename); +} + + +void FQTermHttp::httpRead(qint64 done, qint64 total) { + QByteArray ba = netreply_->readAll(); + QFile file(cacheFileName_); + if (file.open(QIODevice::ReadWrite | QIODevice::Append)) { + QDataStream ds(&file); + ds.writeRawData(ba, ba.size()); + file.close(); + } + if (total != 0) { + //m_pDialog->setProgress(done,total); + int p = done *100 / total; + if (p - lastPercent_ >= 10 && isPreview_ && QFileInfo(cacheFileName_).suffix().toLower() == "jpg") { + if (!previewEmitted) { + emit previewImage(cacheFileName_,true, false); + previewEmitted = true; + } else { + emit previewImage(cacheFileName_,false, false); + } + lastPercent_ = p; + } + emit percent(p); + } +} + +void FQTermHttp::httpDone() { + mutex_.lock(); + downloadMap_.remove(cacheFileName_); + mutex_.unlock(); + if (isPreview_) { + emit previewImage(cacheFileName_, true, true); + } else { + emit message("Download one file successfully"); + } + emit done(this); +} + +void FQTermHttp::httpError(QNetworkReply::NetworkError code) { + switch(code) + { + case QNetworkReply::OperationCanceledError: + break; + default: + QMessageBox::critical(NULL, tr("Download Error"), tr("Failed to download file\n code=%1").arg(code)); + //deleteLater(); /*Not needed. http done will be called and this will cause a double free. + //return; + break; + } +} + +void FQTermHttp::setProxy(const QNetworkProxy & proxy) { + nam_->setProxy(proxy); +} +} // namespace FQTerm + +#include "fqterm_http.moc" diff --git a/src/utilities/fqterm_http.h b/src/utilities/fqterm_http.h new file mode 100644 index 0000000..4c029d9 --- /dev/null +++ b/src/utilities/fqterm_http.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_HTTP_H +#define FQTERM_HTTP_H + +#include +#include +#include +#include +#include + +class QNetworkProxy; +class QNetworkAccessManager; + +namespace FQTerm { + +class FQTermConfig; +class FQTermFileDialog; + +class FQTermHttp: public QObject { + Q_OBJECT; + public: + FQTermHttp(FQTermConfig *, QWidget*, const QString &poolDir, int serverEncodingID); + ~FQTermHttp(); + + void getLink(const QString &, bool); + void getLink(const QUrl &, bool); + void setProxy (const QNetworkProxy & proxy); + signals: + void done(QObject*); + void message(const QString &); + void percent(int); + void headerReceived(FQTermHttp *, const QString &filename); + void previewImage(const QString &filename, bool raiseViewer, bool done); + + public slots: + void cancel(); + + protected slots: + void httpDone(); + void httpRead(qint64, qint64); + void httpError(QNetworkReply::NetworkError); + void httpResponse(); + + protected: + QScopedPointer nam_; + QScopedPointer netreply_; + QString cacheFileName_; + bool previewEmitted; + bool isPreview_; + bool isExisting_; + int lastPercent_; + int serverEncodingID_; + + QString poolDir_; + + static QMap downloadMap_; + static QMutex mutex_; + + FQTermConfig *config_; +}; + +} // namespace FQTerm + +#endif // FQTERM_HTTP_H diff --git a/src/utilities/fqterm_ip_location.cpp b/src/utilities/fqterm_ip_location.cpp new file mode 100644 index 0000000..ea5946d --- /dev/null +++ b/src/utilities/fqterm_ip_location.cpp @@ -0,0 +1,265 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN32 +#include +#else +#include +#include +#endif + +#include "fqterm_trace.h" +#include "fqterm_ip_location.h" +#include "fqterm_path.h" +#include "fqterm.h" + +namespace FQTerm { + +FQTermIPLocation* FQTermIPLocation::instance_ = NULL; + +FQTermIPLocation::FQTermIPLocation(const QString &pathLib) { + ipDatabase_ = new IPDatabase; + ipDatabase_->ipfp = NULL; + + isFileExiting_ = true; + + //case-insensitive match + QDir dir(pathLib); + QStringList files = dir.entryList(QStringList( + "[Qq][Qq][Ww][Rr][Yy].[Dd][Aa][Tt]"), QDir::Files); + if (!files.isEmpty()) { + if ((ipDatabase_->ipfp = fopen((pathLib + (files.at(0))).toLocal8Bit(), "rb")) == NULL) { + FQ_TRACE("iplocation", 0) << "Can't open ip database file!"; + isFileExiting_ = false; + } + } else { + isFileExiting_ = false; + } + +} + +FQTermIPLocation::~FQTermIPLocation() { + if (ipDatabase_->ipfp != NULL) { + fclose(ipDatabase_->ipfp); + } + delete ipDatabase_; +} + +uint32 FQTermIPLocation::byteArrayToInt(char *ip, int count) { + uint32 tmp, ret = 0L; + if (count < 1 || count > 4) { + FQ_TRACE("iplocation", 0) << "byteArrayToInt() error!"; + return 0; + } + for (int i = 0; i < count; i++) { + tmp = ((uint32)ip[i]) &0x000000FF; + ret |= (tmp << (8 *i)); + } + return ret; +} + +void FQTermIPLocation::readFrom(FILE *fp, uint32 offset, char *buf, int len) { + if (fseek(fp, (long)offset, SEEK_SET) == -1) { + FQ_TRACE("iplocation", 0) << "readFrom() error 1"; + memset(buf, 0, len); + return ; + } + if (fread(buf, sizeof(char), len, fp) == 0) { + FQ_TRACE("iplocation", 0) << "readFrom() error 2"; + memset(buf, 0, len); + return ; + } + return ; +} + +int FQTermIPLocation::readLineFrom(FILE *fp, uint32 offset, QByteArray &ret_str) { + char str[512]; + if (fseek(fp, (long)offset, SEEK_SET) == -1) { + FQ_TRACE("iplocation", 0) << "readLineFrom error 1"; + ret_str = QByteArray(); + return -1; + } + if (fgets((char*)str, 512, fp) == NULL) { + FQ_TRACE("iplocation", 0) << "readLineFrom error 2"; + ret_str = QByteArray(); + return -1; + } + ret_str = QByteArray(str); + return (ret_str.length()); +} + +uint32 FQTermIPLocation::getString(FILE *fp, uint32 offset, uint32 lastoffset, + QByteArray &ret, unsigned int flag, int maxRecursiveDepth) { + if (maxRecursiveDepth <= 0) + return 0; + unsigned int fg; + if (fp == NULL) { + return 0; + } + char buf[3] = {0}; + readFrom(fp, offset, buf, 1); + if (buf[0] == 0x01 || buf[0] == 0x02) { + fg = buf[0]; + readFrom(fp, offset + 1, buf, 3); + return getString(fp, byteArrayToInt(buf, 3), offset, ret, fg, maxRecursiveDepth - 1); + } else { + readLineFrom(fp, offset, ret); + } + switch (flag) { + case 0x01: + return 0; + case 0x02: + return lastoffset + 4; + default: + return offset + ret.length() + 1; + } +} + + +void FQTermIPLocation::getCountryCity(FILE *fp, uint32 offset, QByteArray &country, + QByteArray &city) { + uint32 next_offset; + if (fp == NULL) { + return ; + } + next_offset = getString(fp, offset, 0L, country, 0); + if (next_offset == 0) { + city = ""; + } else { + getString(fp, next_offset, 0L, city, 0); + } + return ; +} + +void FQTermIPLocation::setIpRange(int rec_no, IPDatabase *f) { + uint32 offset; + if (f == NULL) { + return ; + } + char buf[7] = {0}; + offset = f->offset_first_start_ip + rec_no * 7; + readFrom(f->ipfp, offset, buf, 7); + f->cur_start_ip = byteArrayToInt(buf, 4); + f->offset_cur_end_ip = byteArrayToInt(buf + 4, 3); + + readFrom(f->ipfp, f->offset_cur_end_ip, buf, 4); + f->cur_end_ip = byteArrayToInt(buf, 4); + +} + +bool FQTermIPLocation::getLocation(QString &url, QString &country, QString &city) +{ + QByteArray gbCountry, gbCity; + bool result = getLocation(url, gbCountry, gbCity); + country = encoding2unicode(gbCountry, FQTERM_ENCODING_GBK); + city = encoding2unicode(gbCity, FQTERM_ENCODING_GBK); + return result; +} + +bool FQTermIPLocation::getLocation(QString &url, QByteArray &country, + QByteArray &city) { + int rec, record_count, B, E; + uint32 ip; +#ifdef Q_OS_WIN32 + uint32 ipValue = inet_addr((const char*)url.toLatin1()); +#else + in_addr_t ipValue = inet_addr((const char*)url.toLatin1()); +#endif + if ((int)ipValue == -1) { + return false; + } else { + ip = ntohl(ipValue); + } + + char buf[4] = {0}; + readFrom(ipDatabase_->ipfp, 0L, (char*)buf, 4); + ipDatabase_->offset_first_start_ip = byteArrayToInt((char*)buf, 4); + readFrom(ipDatabase_->ipfp, 4L, (char*)buf, 4); + ipDatabase_->offset_last_start_ip = byteArrayToInt((char*)buf, 4); + + record_count = (ipDatabase_->offset_last_start_ip - ipDatabase_->offset_first_start_ip) / 7; + if (record_count <= 1) { + return FALSE; + } + + // search for right range + B = 0; + E = record_count; + while (B < E-1) { + rec = (B + E) / 2; + setIpRange(rec, ipDatabase_); + if (ip == ipDatabase_->cur_start_ip) { + B = rec; + break; + } + if (ip > ipDatabase_->cur_start_ip) { + B = rec; + } else { + E = rec; + } + } + setIpRange(B, ipDatabase_); + + if (ipDatabase_->cur_start_ip <= ip && ip <= ipDatabase_->cur_end_ip) { + getCountryCity(ipDatabase_->ipfp, ipDatabase_->offset_cur_end_ip + 4, country, city); + //country.replace( country.find( "CZ88.NET", 0, FALSE ), 8, "" ); + if ((rec = country.toUpper().indexOf("CZ88.NET", 0)) >= 0) { + country.replace(rec, 8, "********"); + } + if ((rec = city.toUpper().indexOf("CZ88.NET", 0)) >= 0) { + city.replace(rec, 8, "********"); + } + + } else { + // not in this range... miss + country = "unkown"; + city = ""; + } + // if ip_start<=ip<=ip_end + return TRUE; +} + +FQTermIPLocation* FQTermIPLocation::getInstance() { + if (instance_ == NULL) { + instance_ = new FQTermIPLocation(getPath(USER_CONFIG)); + if (instance_->isFileExiting_ == NULL) { + delete instance_; + instance_ = new FQTermIPLocation(getPath(RESOURCE)); + if (instance_->isFileExiting_ == NULL) { + delete instance_; + instance_ = NULL; + } + } + } + return instance_; +} + +void FQTermIPLocation::Destroy() { + delete instance_; + instance_ = NULL; +} + +} // namespace FQTerm diff --git a/src/utilities/fqterm_ip_location.h b/src/utilities/fqterm_ip_location.h new file mode 100644 index 0000000..55de36b --- /dev/null +++ b/src/utilities/fqterm_ip_location.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_IPLOCATION_H +#define FQTERM_IPLOCATION_H + +#include +#include + +class QString; + +namespace FQTerm { + +#define MAX_RECURSIVE_IP_DATA_DEPTH 100 + +typedef unsigned long uint32; + + +class FQTermIPLocation { +public: + static FQTermIPLocation* getInstance(); + static void Destroy(); + + bool getLocation(QString &url, QString &country, QString &city); + bool getLocation(QString &url, QByteArray &country, QByteArray &city); + +private: + struct IPDatabase { + uint32 offset_first_start_ip; // first abs offset of start ip + uint32 offset_last_start_ip; // last abs offset of start ip + uint32 cur_start_ip; // start ip of current search range + uint32 cur_end_ip; // end ip of current search range + uint32 offset_cur_end_ip; // where is the current end ip saved + FILE *ipfp; // IO Channel to read file + }; + + FQTermIPLocation(const QString &pathLib); + ~FQTermIPLocation(); + uint32 byteArrayToInt(char *ip, int count); + void readFrom(FILE *fp, uint32 offset, char *buf, int len); + int readLineFrom(FILE *fp, uint32 offset, QByteArray &ret_str); + uint32 getString(FILE *fp, uint32 offset, uint32 lastoffset, QByteArray &str, + unsigned int flag, int maxRecursiveDepth = MAX_RECURSIVE_IP_DATA_DEPTH); + void getCountryCity(FILE *fp, uint32 offset, QByteArray &country, QByteArray &city); + void setIpRange(int rec_no, IPDatabase *f); + + + IPDatabase *ipDatabase_; + bool isFileExiting_; + + static FQTermIPLocation* instance_; +}; + +} // namespace FQTerm + +#endif // FQTERM_IPLOCATION_H diff --git a/src/utilities/fqwcwidth.cpp b/src/utilities/fqwcwidth.cpp new file mode 100644 index 0000000..fc980e5 --- /dev/null +++ b/src/utilities/fqwcwidth.cpp @@ -0,0 +1,468 @@ +/* + * This is an implementation of wcwidth() and wcswidth() (defined in + * IEEE Std 1002.1-2001) for Unicode. + * + * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html + * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html + * + * In fixed-width output devices, Latin characters all occupy a single + * "cell" position of equal width, whereas ideographic CJK characters + * occupy two such cells. Interoperability between terminal-line + * applications and (teletype-style) character terminals using the + * UTF-8 encoding requires agreement on which character should advance + * the cursor by how many cell positions. No established formal + * standards exist at present on which Unicode character shall occupy + * how many cell positions on character terminals. These routines are + * a first attempt of defining such behavior based on simple rules + * applied to data provided by the Unicode Consortium. + * + * For some graphical characters, the Unicode standard explicitly + * defines a character-cell width via the definition of the East Asian + * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. + * In all these cases, there is no ambiguity about which width a + * terminal shall use. For characters in the East Asian Ambiguous (A) + * class, the width choice depends purely on a preference of backward + * compatibility with either historic CJK or Western practice. + * Choosing single-width for these characters is easy to justify as + * the appropriate long-term solution, as the CJK practice of + * displaying these characters as double-width comes from historic + * implementation simplicity (8-bit encoded characters were displayed + * single-width and 16-bit ones double-width, even for Greek, + * Cyrillic, etc.) and not any typographic considerations. + * + * Much less clear is the choice of width for the Not East Asian + * (Neutral) class. Existing practice does not dictate a width for any + * of these characters. It would nevertheless make sense + * typographically to allocate two character cells to characters such + * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be + * represented adequately with a single-width glyph. The following + * routines at present merely assign a single-cell width to all + * neutral characters, in the interest of simplicity. This is not + * entirely satisfactory and should be reconsidered before + * establishing a formal standard in this area. At the moment, the + * decision which Not East Asian (Neutral) characters should be + * represented by double-width glyphs cannot yet be answered by + * applying a simple rule from the Unicode database content. Setting + * up a proper standard for the behavior of UTF-8 character terminals + * will require a careful analysis not only of each Unicode character, + * but also of each presentation form, something the author of these + * routines has avoided to do so far. + * + * http://www.unicode.org/unicode/reports/tr11/ + * + * Markus Kuhn -- 2007-05-26 (Unicode 5.0) + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted. The author + * disclaims all warranties with regard to this software. + * + * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + */ + +/* + * For wchar_t may be of 16 bits on some platforms, use uint32_t instead. + * + */ + +#include "fqwcwidth.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +struct interval { + uint32_t first; + uint32_t last; +}; + +/* auxiliary function for binary search in interval table */ +static int bisearch(uint32_t ucs, const struct interval *table, int max) { + int min = 0; + int mid; + + if (ucs < table[0].first || ucs > table[max].last) + return 0; + while (max >= min) { + mid = (min + max) / 2; + if (ucs > table[mid].last) + min = mid + 1; + else if (ucs < table[mid].first) + max = mid - 1; + else + return 1; + } + + return 0; +} + + +/* The following two functions define the column width of an ISO 10646 + * character as follows: + * + * - The null character (U+0000) has a column width of 0. + * + * - Other C0/C1 control characters and DEL will lead to a return + * value of -1. + * + * - Non-spacing and enclosing combining characters (general + * category code Mn or Me in the Unicode database) have a + * column width of 0. + * + * - SOFT HYPHEN (U+00AD) has a column width of 1. + * + * - Other format characters (general category code Cf in the Unicode + * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. + * + * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) + * have a column width of 0. + * + * - Spacing characters in the East Asian Wide (W) or East Asian + * Full-width (F) category as defined in Unicode Technical + * Report #11 have a column width of 2. + * + * - All remaining characters (including all printable + * ISO 8859-1 and WGL4 characters, Unicode control characters, + * etc.) have a column width of 1. + * + * This implementation assumes that uint32_t characters are encoded + * in ISO 10646. + */ + +int mk_wcwidth(uint32_t ucs) +{ + /* sorted list of non-overlapping intervals of non-spacing characters */ + /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ + static const struct interval combining[] = { + { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, + { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, + { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, + { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, + { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, + { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, + { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, + { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, + { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, + { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, + { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, + { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, + { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, + { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, + { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, + { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, + { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, + { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, + { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, + { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, + { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, + { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, + { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, + { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, + { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, + { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, + { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, + { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, + { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, + { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, + { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, + { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, + { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, + { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, + { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, + { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, + { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, + { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, + { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, + { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, + { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, + { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, + { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, + { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, + { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, + { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, + { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, + { 0xE0100, 0xE01EF } + }; + + /* test for 8-bit control characters */ + if (ucs == 0) + return 0; + if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) + return -1; + + /* binary search in table of non-spacing characters */ + if (bisearch(ucs, combining, + sizeof(combining) / sizeof(struct interval) - 1)) + return 0; + + /* if we arrive here, ucs is not a combining or C0/C1 control character */ + + return 1 + + (ucs >= 0x1100 && + (ucs <= 0x115f || /* Hangul Jamo init. consonants */ + ucs == 0x2329 || ucs == 0x232a || + (ucs >= 0x2e80 && ucs <= 0xa4cf && + ucs != 0x303f) || /* CJK ... Yi */ + (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ + (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ + (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ + (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ + (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ + (ucs >= 0xffe0 && ucs <= 0xffe6) || + (ucs >= 0x20000 && ucs <= 0x2fffd) || + (ucs >= 0x30000 && ucs <= 0x3fffd))); +} + + +int mk_wcswidth(const uint32_t *pwcs, size_t n) +{ + int w, width = 0; + + for (;*pwcs && n-- > 0; pwcs++) + if ((w = mk_wcwidth(*pwcs)) < 0) + return -1; + else + width += w; + + return width; +} + + +int mk_wcswidth(const UTF16 *utf16_str, size_t n) +{ + int w, width = 0; + + // FIXME: only BMP is supported here. + for (;*utf16_str && n-- > 0; utf16_str++) + if ((w = mk_wcwidth(*utf16_str)) < 0) + return -1; + else + width += w; + + return width; +} + +int mk_wcswidth(const UTF16 *utf16_str, size_t n, int max_width, int &element_consumed) { + const UTF16 *org = utf16_str; + int w, width = 0; + + // FIXME: only BMP is supported here. + for (;*utf16_str && n-- > 0 && width < max_width; utf16_str++) + if ((w = mk_wcwidth(*utf16_str)) < 0) + return -1; + else + width += w; + + FQ_VERIFY(width <= max_width); + + element_consumed = utf16_str - org; + + return width; +} + +int mk_advance_one_code_point(const UTF16 **p, const UTF16 *end) { + FQ_ASSERT(*p < end); + + // TODO_UTF16: FIXME: only support BMP here. + *p = *p + 1; + return get_str_width(**p); +} + +int mk_advace_at_least_one_cell(const UTF16 **p, const UTF16 *end) { + FQ_ASSERT(*p < end); + + // TODO_UTF16: FIXME: only support BMP here. + int w = 0; + int width = 0; + do { + w = get_str_width(**p); + width += w; + *p = *p + 1; + } while (w == 0 && *p < end); + + if (w < 0) { + return -1; + } + + while (*p < end && get_str_width(**p) == 0) { + *p = *p + 1; + } + + return width; +} + +/* + * The following functions are the same as mk_wcwidth() and + * mk_wcswidth(), except that spacing characters in the East Asian + * Ambiguous (A) category as defined in Unicode Technical Report #11 + * have a column width of 2. This variant might be useful for users of + * CJK legacy encodings who want to migrate to UCS without changing + * the traditional terminal character-width behaviour. It is not + * otherwise recommended for general use. + */ +int mk_wcwidth_cjk(uint32_t ucs) +{ + /* sorted list of non-overlapping intervals of East Asian Ambiguous + * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ + static const struct interval ambiguous[] = { + { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, + { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, + { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, + { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, + { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, + { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, + { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, + { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, + { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, + { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, + { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, + { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, + { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, + { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, + { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, + { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, + { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, + { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, + { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, + { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, + { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, + { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, + { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, + { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, + { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, + { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, + { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, + { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, + { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, + { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, + { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, + { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, + { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, + { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, + { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, + { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, + { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, + { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, + { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, + { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, + { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, + { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, + { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, + { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, + { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, + { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, + { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, + { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, + { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, + { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, + { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, + { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } + }; + + /* binary search in table of non-spacing characters */ + if (bisearch(ucs, ambiguous, + sizeof(ambiguous) / sizeof(struct interval) - 1)) + return 2; + + return mk_wcwidth(ucs); +} + + +int mk_wcswidth_cjk(const uint32_t *pwcs, size_t n) +{ + int w, width = 0; + + for (;*pwcs && n-- > 0; pwcs++) + if ((w = mk_wcwidth_cjk(*pwcs)) < 0) + return -1; + else + width += w; + + return width; +} + +int mk_wcswidth_cjk(const UTF16 *utf16_str, size_t n) +{ + int w, width = 0; + + // FIXME: only BMP is supported here. + for (;*utf16_str && n-- > 0; utf16_str++) { + if ((w = mk_wcwidth_cjk(*utf16_str)) < 0) + return -1; + else + width += w; + } + + return width; +} + +int mk_wcswidth_cjk(const UTF16 *utf16_str, size_t n, int max_width, int &element_consumed) { + const UTF16 *org = utf16_str; + int w, width = 0; + + // FIXME: only BMP is supported here. + for (;*utf16_str && n-- > 0 && width < max_width; utf16_str++) { + const UTF16 *bak_str = utf16_str; + int bak_width = width; + + if ((w = mk_wcwidth_cjk(*utf16_str)) < 0) { + return -1; + } else { + width += w; + } + + if (width > max_width) { + utf16_str = bak_str; + width = bak_width; + if (utf16_str == org) { + return -1; + } else { + break; + } + } + } + + element_consumed = utf16_str - org; + return width; +} + + +#define USE_CJK_WIDTH + + +// TODO_UTF16: if we don't use CJK width, we will get wrong text layout. +#ifdef USE_CJK_WIDTH + +int get_str_width(uint32_t ucs) { + return mk_wcwidth_cjk(ucs); +} + +int get_str_width(const uint32_t *pwcs, size_t n) { + return mk_wcswidth_cjk(pwcs, n); +} + +int get_str_width(const UTF16 *utf16_str, size_t n) { + return mk_wcswidth_cjk(utf16_str, n); +} + +int get_str_width(const UTF16 *utf16_str, size_t n, int max_width, int &element_consumed) { + return mk_wcswidth_cjk(utf16_str, n, max_width, element_consumed); +} + +#else + +int get_str_width(uint32_t ucs) { + return mk_wcwidth(ucs); +} +int get_str_width(const uint32_t *pwcs, size_t n) { + return mk_wcswidth(pwcs, n); +} +int get_str_width(const UTF16 *utf16_str, size_t n) { + return mk_wcswidth(utf16_str, n); +} + +int get_str_width(const UTF16 *utf16_str, size_t n, int max_width, int &element_consumed) { + return mk_wcswidth(utf16_str, n, max_width, element_consumed); +} + +#endif + +} // namespace FQTerm diff --git a/src/utilities/fqwcwidth.h b/src/utilities/fqwcwidth.h new file mode 100644 index 0000000..b2007bc --- /dev/null +++ b/src/utilities/fqwcwidth.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_FQWCWIDTH_H +#define FQTERM_FQWCWIDTH_H + +#ifdef WIN32 +#define uint32_t unsigned __int32 +#define uint16_t unsigned __int16 +typedef wchar_t UTF16; +#else // WIN32 +#include +#include +typedef uint16_t UTF16; +#endif // WIN32 + +typedef char Verify_UTF16_Is_Two_Bytes[ + (sizeof(UTF16) == 2)? 1 : -1]; + +namespace FQTerm { + +//const uint16_t URC = 0xfffd; // the Unicode Replacement Character +// TODO_UTF16: 0xfffd is of width 2, which is not desired. +const uint16_t URC = '?'; // use '?' instead of the Unicode Replacement Character + +const int MAX_CELLS_PER_CHAR = 2; + +int get_str_width(uint32_t ucs); +int get_str_width(const uint32_t *pwcs, size_t n); +int get_str_width(const UTF16 *utf16_str, size_t n); +int get_str_width(const UTF16 *utf16_str, size_t n, int max_width, int &element_consumed); + +// Move p to next code point in max_n UTF16 characters. +// Return the width of the current code point. +int mk_advance_one_code_point(const UTF16 **p, const UTF16 *end); + +// Move p to next code point in max_n UTF16 characters. +// Return the width. +int mk_advace_at_least_one_cell(const UTF16 **p, const UTF16 *end); + +} // namespace FQTerm + +#endif // FQTERM_FQWCWIDTH_H -- cgit v1.2.3
" + + tr("Model") + " : " + QString::fromStdString((*exifExtractor_)["Model"]) + "" + + QString::fromStdString((*exifExtractor_)["DateTime"]) + "" + + QString::fromStdString((*exifExtractor_)["Flash"]) + "
" + + tr("ExposureTime") + " : " + QString::fromStdString((*exifExtractor_)["ExposureTime"]) + "" + + tr("FNumber") + " : " + QString::fromStdString((*exifExtractor_)["FNumber"]) + "" + + tr("ISO") + " : " + QString::fromStdString((*exifExtractor_)["ISOSpeedRatings"]) + "
" + + tr("FocalLength") + " : " + QString::fromStdString((*exifExtractor_)["FocalLength"]) + "" + + tr("MeteringMode") + " : " + QString::fromStdString((*exifExtractor_)["MeteringMode"]) + "" + + tr("ExposureBias") + " : " + QString::fromStdString((*exifExtractor_)["ExposureBiasValue"]) + "