pax_global_header00006660000000000000000000000064151733460100014512gustar00rootroot0000000000000052 comment=855447b13e4705d74d45332852d9a76cd4e2f7a8 foldynl-QLog-3252ff9/000077500000000000000000000000001517334601000143635ustar00rootroot00000000000000foldynl-QLog-3252ff9/.github/000077500000000000000000000000001517334601000157235ustar00rootroot00000000000000foldynl-QLog-3252ff9/.github/ISSUE_TEMPLATE/000077500000000000000000000000001517334601000201065ustar00rootroot00000000000000foldynl-QLog-3252ff9/.github/ISSUE_TEMPLATE/01-Bug Report.yml000066400000000000000000000040221517334601000230160ustar00rootroot00000000000000name: Bug Report description: File a bug report labels: ["bug", "triage"] body: - type: markdown attributes: value: | > [!IMPORTANT] > **Disclaimer Regarding Forks and Clones** > > Support is provided for the original, unmodified version of QLog. > If you are using a fork, clone, or any modified version of this project, please direct your issue to the maintainer of that specific repository. > This includes issues related to **core features**, as changes introduced in forks may directly or indirectly affect their behavior. Please reserve the issue tracker for reporting presumed bugs in QLog. If you have a question about usage or installation, please use the [QLog Discussions](https://github.com/foldynl/QLog/discussions) - type: textarea id: what-happened attributes: label: What happened? How can it be reproduced? Provide as much information as possible. description: Also, what did you expect to happen? validations: required: true - type: input id: specific-version attributes: label: QLog Version description: "Version reported in **Main Menu → Help → About**" value: "0.0.0" validations: required: true - type: dropdown id: ostype attributes: label: Which OS are you using? options: - Linux - macOS - Windows validations: required: true - type: dropdown id: osinstallation attributes: label: 'QLog Installation Method' description: 'Select the installation method' options: - DEB/RPM - Flatpak - EXE - DMG - Self-Compiled - I don't know validations: required: true - type: textarea id: system-information attributes: label: Installation Details description: | If you're not familiar with the QLog Installation Method mentioned above, please attach a screenshot of Main Menu → Help → About or provide more details about your OS. foldynl-QLog-3252ff9/.github/ISSUE_TEMPLATE/02-Feature Request.yml000066400000000000000000000012271517334601000240560ustar00rootroot00000000000000name: Feature Request description: Request a new feature or enhancement for QLog labels: ["enhancement"] body: - type: markdown attributes: value: | Please describe the feature you would like to see and why it would be beneficial. Before submitting a request, check if a similar feature has already been suggested in the [existing issues](https://github.com/foldynl/QLog/issues). - type: textarea id: feature-description attributes: label: Feature Description description: Describe the feature or enhancement in detail. How should it work? Why is this feature useful? validations: required: true foldynl-QLog-3252ff9/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000005131517334601000220750ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: "📖 Find documentation" url: https://github.com/foldynl/QLog/wiki about: "Most documentation is on the QLog wiki" - name: "📨 Ask a question — Discussions" url: https://github.com/foldynl/QLog/discussions about: "Please use GitHub Discussions for general questions" foldynl-QLog-3252ff9/.github/workflows/000077500000000000000000000000001517334601000177605ustar00rootroot00000000000000foldynl-QLog-3252ff9/.github/workflows/c-cpp.yml000066400000000000000000000127611517334601000215140ustar00rootroot00000000000000name: CI Linux/macOS on: push: branches: - 'testing_*' pull_request: branches: - 'testing_*' - master workflow_dispatch: jobs: ubuntu-build-qt5: name: Ubuntu CI QT5 strategy: matrix: os: [ubuntu-22.04, ubuntu-24.04] runs-on: ${{ matrix.os }} steps: - name: Install dependencies run: | sudo apt-get update sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libsqlite3-dev libhamlib++-dev libqt5charts5-dev qttools5-dev-tools libqt5keychain1 qt5keychain-dev qtwebengine5-dev build-essential libqt5serialport5-dev pkg-config libqt5websockets5-dev - name: Checkout code uses: actions/checkout@v5 - name: configure run: qmake QLog.pro - name: make run: make -j2 ubuntu-build-qt6: name: Ubuntu CI QT6 strategy: matrix: os: [ubuntu-22.04, ubuntu-24.04] runs-on: ${{ matrix.os }} steps: - name: Install dependencies run: | sudo apt-get update sudo apt-get -y install libhamlib-dev build-essential pkg-config qt6-base-dev qtkeychain-qt6-dev qt6-webengine-dev libqt6charts6-dev libqt6serialport6-dev libqt6webenginecore6-bin libqt6svg6-dev libgl-dev libqt6websockets6-dev - name: Checkout code uses: actions/checkout@v5 - name: configure run: qmake6 QLog.pro - name: make run: make -j2 macos-build: name: MacOS CI if: vars.ENABLE_MACOS == 'true' strategy: matrix: os: [macos-15] runs-on: ${{ matrix.os }} steps: - name: Install dependencies run: | unset HOMEBREW_NO_INSTALL_FROM_API brew update brew upgrade || true brew install qt6 brew link qt6 --force brew install hamlib brew link hamlib --force brew install qtkeychain brew install dbus-glib brew install brotli brew install icu4c brew install pkg-config - name: Checkout code uses: actions/checkout@v5 with: fetch-depth: 0 - name: Get version from tag run : | TAGVERSION=$(git describe --tags) echo "TAGVERSION=${TAGVERSION:1}" >> $GITHUB_ENV - name: Configure and compile run: | cd build qmake6 -config release .. make -j4 deb-package: name: DEB Package Build if: github.event_name != 'pull_request' runs-on: ubuntu-24.04 steps: - name: Checkout code uses: actions/checkout@v5 - name: Install tools and build dependencies run: | sudo apt-get update sudo apt-get -y install devscripts equivs dpkg-dev fakeroot lintian libconfig-model-dpkg-perl licensecheck sudo mk-build-deps --install --remove debian/control --tool "apt-get -y --no-install-recommends" - name: Check debian/copyright run: cme check dpkg-copyright - name: Build DEB package run: dpkg-buildpackage -b -us -uc -j4 - name: Verify DEB was created run: ls -la ../qlog_*.deb - name: Run lintian run: lintian --no-tag-display-limit --fail-on error ../qlog_*.changes - name: Upload DEB artifact uses: actions/upload-artifact@v5 with: name: deb-package path: /home/runner/work/QLog/qlog_*.deb retention-days: 1 deb-smoke-test: name: DEB Smoke Test needs: deb-package runs-on: ubuntu-24.04 steps: - name: Download DEB artifact uses: actions/download-artifact@v5 with: name: deb-package - name: Install and smoke test run: | sudo apt-get update sudo apt-get install -y ./qlog_*.deb QT_QPA_PLATFORM=offscreen qlog --help 2>&1 | grep -q "QLog Help" rpm-package: name: RPM Package Build if: github.event_name != 'pull_request' runs-on: ubuntu-latest container: image: fedora:43 steps: - name: Install base tools run: dnf install -y git rpm-build rpmdevtools rpmlint dnf-plugins-core - name: Checkout code uses: actions/checkout@v5 with: fetch-depth: 0 - name: Get version from tag run: | git config --global --add safe.directory "$GITHUB_WORKSPACE" VERSION=$(git describe --tags --abbrev=0 | sed 's/^v//') echo "REPO_VERSION=${VERSION}" >> $GITHUB_ENV - name: Install build dependencies from spec run: dnf builddep -y rpm_spec/qlog.spec - name: Prepare RPM build tree run: | rpmdev-setuptree TAR_DIR="QLog-${REPO_VERSION}" mkdir -p "/tmp/${TAR_DIR}" cp -a . "/tmp/${TAR_DIR}/" tar czf ~/rpmbuild/SOURCES/qlog-${REPO_VERSION}.tar.gz --exclude='.git' -C /tmp "${TAR_DIR}" - name: Build RPM package run: rpmbuild -bb rpm_spec/qlog.spec - name: Verify RPM was created run: ls -la ~/rpmbuild/RPMS/*/QLog-*.rpm - name: Run rpmlint run: rpmlint ~/rpmbuild/RPMS/*/*.rpm || true - name: Upload RPM artifact uses: actions/upload-artifact@v5 with: name: rpm-package path: ~/rpmbuild/RPMS/*/QLog-*.rpm retention-days: 1 rpm-smoke-test: name: RPM Smoke Test needs: rpm-package runs-on: ubuntu-latest container: image: fedora:43 steps: - name: Download RPM artifact uses: actions/download-artifact@v5 with: name: rpm-package - name: Install and smoke test run: | dnf install -y $(find . -name 'QLog-*.rpm') QT_QPA_PLATFORM=offscreen qlog --help 2>&1 | grep -q "QLog Help" foldynl-QLog-3252ff9/.github/workflows/macOSBuild.yml000066400000000000000000000052121517334601000224650ustar00rootroot00000000000000name: macOS deployment #on: [push, pull_request] on: workflow_dispatch: push: branches: - master jobs: macos-build: name: MacOS Build strategy: matrix: os: [macos-12, macos-13] runs-on: ${{ matrix.os }} steps: - name: Install Dependencies run: | unset HOMEBREW_NO_INSTALL_FROM_API brew update brew upgrade || true brew install qt6 brew install qt6-webengine brew link qt6 --force brew link qt6-webengine --force brew install hamlib brew link hamlib --force brew install qtkeychain brew install dbus-glib brew install brotli brew install icu4c brew install pkg-config - name: Checkout Code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Get version from tag run : | TAGVERSION=$(git describe --tags) echo "TAGVERSION=${TAGVERSION:1}" >> $GITHUB_ENV - name: Configure and compile run: | mkdir build cd build qmake -config release .. make -j4 - name: Build dmg run: | cd build macdeployqt qlog.app -executable=./qlog.app/Contents/MacOS/qlog cp `brew --prefix`/lib/libhamlib.dylib qlog.app/Contents/Frameworks/libhamlib.dylib cp `brew --prefix`/lib/libqt6keychain.dylib qlog.app/Contents/Frameworks/libqt6keychain.dylib cp `brew --prefix`/lib/libdbus-1.dylib qlog.app/Contents/Frameworks/libdbus-1.dylib cp `brew --prefix brotli`/lib/libbrotlicommon.1.dylib qlog.app/Contents/Frameworks/libbrotlicommon.1.dylib cp `brew --prefix`/opt/icu4c/lib/libicui18n.74.dylib qlog.app/Contents/Frameworks/libicui18n.74.dylib install_name_tool -change `brew --prefix`/lib/libhamlib.dylib @executable_path/../Frameworks/libhamlib.dylib qlog.app/Contents/MacOS/qlog install_name_tool -change `brew --prefix`/lib/libqt6keychain.dylib @executable_path/../Frameworks/libqt6keychain.dylib qlog.app/Contents/MacOS/qlog install_name_tool -change @loader_path/libbrotlicommon.1.dylib @executable_path/../Frameworks/libbrotlicommon.1.dylib qlog.app/Contents/MacOS/qlog install_name_tool -change /usr/local/opt/icu4c/lib/libicui18n.74.dylib @executable_path/../Frameworks/libicui18n.74.dylib qlog.app/Contents/MacOS/qlog otool -L qlog.app/Contents/MacOS/qlog macdeployqt qlog.app -dmg - name: Copy artifact uses: actions/upload-artifact@v4 with: name: QLog-${{ env.TAGVERSION }}-${{ matrix.os }} path: /Users/runner/work/QLog/QLog/build/qlog.dmg foldynl-QLog-3252ff9/.gitignore000066400000000000000000000011371517334601000163550ustar00rootroot00000000000000# C++ objects and libs *.slo *.lo *.o *.a *.la *.lai *.so *.dll *.dylib *.patch # Qt-es object_script.*.Release object_script.*.Debug *_plugin_import.cpp /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.qbs.user *.qbs.user.* *.moc moc_*.cpp moc_*.h qrc_*.cpp ui_*.h *.qmlc *.jsc Makefile* # Qt unit tests target_wrapper.* # QtCreator *.autosave # QtCreator Qml *.qmlproject.user *.qmlproject.user.* # QtCreator CMake CMakeLists.txt.user* # QtCreator 4.8< compilation database compile_commands.json # QtCreator local machine specific files for imported projects *creator.user* .DS_Store /build foldynl-QLog-3252ff9/.gitmodules000066400000000000000000000000001517334601000165260ustar00rootroot00000000000000foldynl-QLog-3252ff9/AUTHORS000066400000000000000000000006111517334601000154310ustar00rootroot00000000000000MAINTAINERS: Ladislav Foldyna OK1MLG PAST MAINTAINERS: Thomas Gatzweiler DL2IC CONTRIBUTORS: Wolfgang DL2KI Fabian Kurz DJ5CW gerbert Florian Thienel AsciiWolf Maciej Krüger BG7JAF Juan Carlos EA5WA Diego LU1IDC Alfredo IK1VQY Michael AA5SH Emilio EA7QL Kyle Boyle VE9KZ Stéphane Fillod F8CFE foldynl-QLog-3252ff9/CONTRIBUTING.md000066400000000000000000000111531517334601000166150ustar00rootroot00000000000000## How Can I Contribute? ### Reporting Bugs *Please* contact me via the repository's Discussion page or email (you can find it [QRZ](https://www.qrz.com/db/OK1MLG) or [HamQTH](https://www.hamqth.com/ok1mlg) ) If you run into an issue, please search [Issue tracking](https://github.com/foldynl/QLog/issues) *first* to ensure the issue hasn't been reported before. Open a new issue only if you haven't found anything similar to your issue. #### When opening a new issue, please include the following information at the top of the issue: * What version you are using. * Describe the issue you are experiencing. * Describe how to reproduce the issue. * Including any warning/errors/backtraces - see debug details in QLog [Wiki](https://github.com/foldynl/QLog/wiki/Debug-Log-Level). In general, the more detail you share about a problem the quicker a developer can resolve it. For example, providing a simple test case is always exceptionally helpful. Be prepared to work with the developers investigating your issue. Your assistance is crucial in providing a quick solution. They may ask for information like: * Your non-sensitive information - ADIF export, log file etc. * Your hardware configuration * Your OS, distribution etc. * Your version of libraries (especial Qt, Hamlib) ### Pull Requests #### General * All pull requests must be based on the current `master` branch and should apply without conflicts. * Please attempt to limit pull requests to a single commit which resolves one specific issue. * Make sure your commit messages are in the correct format. See the [Commit Message Formats](#commit-message-formats) section for more information. * When updating a pull request squash multiple commits by performing a [rebase](https://git-scm.com/docs/git-rebase) (squash). * For large pull requests consider structuring your changes as a stack of logically independent patches which build on each other. This makes large changes easier to review and approve which speeds up the merging process. * Try to keep pull requests simple. Simple code with comments is much easier to review and approve. * If you have an idea you'd like to discuss or which requires additional testing, consider opening it as a draft pull request. Once everything is in good shape and the details have been worked out you can remove its draft status. Any required reviews can then be finalized and the pull request merged. ### Testing If you're in a position to run the latest code consider helping us by reporting any functional problems, performance regressions or other suspected issues. By running the latest code to a wide range of realistic workloads, configurations and architectures we're better able quickly identify and resolve potential issues. ## Style Guides ### Repository Structure **Branch Names:** - Latest Public Release branch: `master` - Upcoming release branch: `testing_$VERSION` ### Coding Conventions * Conditional ``` if ( cond ) { command; } ```` * Use spaces around operators * `count + 1` instead of `count+1` * Use spaces after commas (unless separated by newlines) * Keep in mind that QLog can run under Linux, Windows and MacOS - do not use platform-depend code #### Modules If possible, one class one file. Each mode (except models) has to include `debug.h` and define ``` MODULE_IDENTIFICATION("qlog.ui.mainwindow"); ``` Each function (except models) has to contain ``` FCT_IDENTIFICATION; ``` ### Commit Message Formats #### New Changes Commit messages for new changes must meet the following guidelines: * In 72 characters or less, provide a summary of the change as the first line in the commit message. * A body which provides a description of the change. If necessary, please summarize important information such as why the proposed approach was chosen or a brief description of the bug you are resolving. Each line of the body must be 72 characters or less. * Provides a subject line in the format of `Module_Name: Change description` where `Module_name` defines a part of source code where the change was made or new feature name (short name). ``` Module_Name: This line is a brief summary of your change Please provide at least a couple sentences describing the change. If necessary, please summarize decisions such as why the proposed approach was chosen or what bug you are attempting to solve. ``` #### Bug Fixes If you are submitting a fix the commit message should meet the following guidelines: * Provides a subject line in the format of `Fixed #ddd: Fix name...` where `ddd` represents each [Issue](https://github.com/foldynl/QLog/issues) . Bugfixes not listed in the Github Issue are introduced by the same way as Improvements (Module Name etc). foldynl-QLog-3252ff9/Changelog000066400000000000000000001312341517334601000162010ustar00rootroot000000000000002026/04/26 - 0.50.0 - [NEW] - Added Split detection - [NEW] - Added Developer and Support tools (PR #991 @aa5sh @foldynl) - [NEW] - Added a simple QSL label printing dialog (issue #562) - [NEW] - Added Cabrillo contest export - [NEW] - Added direct labeling of QSL Requested and QSL Received to the QSO context menu (PR #982 @aa5sh) - [NEW] - DXCC Submission Report (PR #967 @aa5sh) - [NEW] - DXC - Search pre-fills the callsign from New Contact if callsign is present - [NEW] - Settings - Added Danger Zone tab with Delete all passwords and QSOs - [CHANGED] - Mutex-free Omnirig1 and Omnirig2 - [CHANGED] - POTA/SOTA/WWFF/SAT list are download from QLog LOV-repo - [CHANGED] - Used an external lib for CSV parsing for LOV Download - [CHANGED] - Import - ADIF import updates DXCC only if it is missing in the QSO (issue #983) - [REMOVED] - Import - ADIF import does not include the option to update DXCC during the import - no longer needed - Fixed Callsign disappears when calling a DX in a split via VFO-B (issue #799) - Fixing Rendering issue (issue #989) - Updated debian packaging (PR @979 thx @dawkagaming) - Hamlib rigctld switching between VFO A/B doesnt change the band mode - added workaround (issue #999) - Awards internal redesign - Removed AN from the WAC award (issue #1010) 2026/03/19 - 0.49.1 - Fixed Online Map OSM Access Blocked banner (issue #956) - Fixed Package build process issue - openssl-dev is missing (issue #957) - Fixed Missing dependence for QTKeychain (issue #964) - Added French Translation (PR #969 thx @fillods) 2026/03/13 - 0.49.0 - [NEW] - Added Pack and Unpack Data and Setting - Computer to Computer Migration (issue #535) - [NEW] - Added Rig Sharing via Rigctld (PR #736 issue #159 @aa5sh @foldynl) - [NEW] - Added QSL Gallery - [NEW] - QSO Filter - Added REGEXP operator - [NEW] - Settings - TQSL - Added Path auto-detect and validation - [NEW] - Upload QSO - Added LoTW Station Location Combo (PR #929 @TrgoSk @foldynl) - [NEW] - QSO Export - Added Station Profile Filter - [NEW] - BandMap shows emergency frequencies (issue #462) - [NEW] - Added Speed Up Down Macros - WinKey and CWDaemon (issue #491) - [NEW] - Settings Winkey v2 - Added PaddleOnly Sidetone (issue #739) - [NEW] - Settings Winkey v2 and CWDaemon - Added Sidetone Freq - [NEW] - All County fields contain Completer for Ukraine, US, Japan, NZ, Spanish, Russia (PR #785 @aa5sh @foldynl) - [NEW] - Added County Awards for Ukraine, US, Japan, NZ, Spanish, Russia (PR #785 @aa5sh @foldynl) - [NEW] - ADIF 3.1.7 - Added new modes FT2, FREEDATA, RIBBIT_PIX, RIBBIT_SMS (issue #934) - [CHANGED] - Generic FTx for FT8/FT4 (FT2) in Alert and DXC filter (issue #937) - [CHANGED] - LoTW QSL matching algorithm uses Mode and Mode Group matching (issue #942) - [CHANGED] - Reduced download period for DXCC Entities from 21 to 7 days - LogbookWidget: Delete Performance Optimization - Fixed Awards POTA Activator Filter - Fixed man page - Fixing SATmode Activity is blank (issue #948) 2026/01/30 - 0.48.0 - [NEW] - Rig Widget - tuning rig with mouse (issue #855) - [NEW] - Awards - Added User Filter Combo (issue #870) - [NEW] - Statistics - Added User Filter; new Dialog layout (issue #870) - [NEW] - Alerts - Added detailed Log Status settings (issue #817) - [NEW] - Settings - Enable/Disable sending color-coded status indicators back to WSJT-X (issue #885 @aa5sh @foldynl) - [CHANGED] - Omnirig Drivers: Removed QT AXContainers - pure Windows API code - [CHANGED] - Enabled Chekbox in Alerts Table (issue #867) - [CHANGED] - Serial Port Completer contains Horizontal ScrollBar - [CHANGED] - TCI - Settings - Default PWR defines the maximum output power - Fixed Omnirig drivers keep sending frequency change (issue #872) - Fixed ADIF import does not accept a default operator name (issue #884) - Fixed HamQTH URL from http to https (PR #886 @aa5sh) - Fixed Missing Band value when QSO from FLDigi (issue #892) 2025/12/19 - 0.47.1 - [CHANGED] - DXC - VE7CC-type Cluster is correctly detected (PR #851 @kyleboyle) - [CHANGED] - Chat - Changed ON4KST URL (issue #857) - Fixed missing clear button for Search Callsign (issue #753) - Fixed Updated QSOs are not sent to wavelog (issue #847) - Fixed Fixed Omnirig(v2) getFreq, getVFO, setFreq (issue #853) - Fixed ADI Header does not follow ADIF Spec (issue #859) - Fixed OmniRig settings are not saved (issue #862) 2025/12/06 - 0.47.0 - [NEW] - Adds theme options - native, light, dark (PR #718 @kyleboyle) - [NEW] - Implemented ADIF 3.1.6 - [NEW] - ADIF 3.1.6 - Added new modes FSK and MTONE - [NEW] - ADIF 3.1.6 - Added new contest IDs - [NEW] - ADIF 3.1.6 - Added new column EQSL_AG (Import/Export only) - [NEW] - Statistics, QSODetail contain deleted DXCC Entities (PR #728 @aa5sh @foldynl) - [NEW] - Settings Hamlib - Added support to define CIV Addr for Icom and Ten-Tec (issue #747) - [NEW] - Settings Hamlib - Added RTS and DTR control (PR #809 @aa5sh) - [NEW] - Settings GUI - Added options to switch distance unit - [NEW] - Added Linux manpage (PR #791 @dawkagaming) - [NEW] - Added a link to the GitHub release notes under Help-Whats New - [NEW] - Added workaround for WriteLog - always call callbook lookups (PR #833 @sjwoodr) - [NEW] - Awards - Added Not-Confirmed filter (PR #836 @aa5sh) - [NEW] - Rotator Widget - Added buttons to change button profiles - [CHANGED] - Settings - Added network loop detection for WSJTX Forward (issue #815 @aa5sh @foldynl) - [CHANGED] - Rotator - Rotator timeout is set to 5s (PR #823 @aa5sh) - [CHANGED] - Double Spin Boxes - the decimal separator is forced to be a period - [DELETED] - WSJTX Widget - Removed Freq and Mode - Fixed QSODetail - Anti-meridian bug on map (issue #786) - Fixed Statistics: Center maps on QTH longitude (issue #824) - Fixed OmniRig disconnecting when its status changed unexpectedly (issue #832) 2025/10/31 - 0.46.2 - Fixed Spaces after QRZ.com name (issue #767) - Fixed SPID Rot1Prog Rotator more 360 deg (issue #775) - Fixed build instructions on Debian (PR #777 @leventelist) - Fixed Bandmap truncated output despite having space (issue #779) - Fixed Statistics - Anti-meridian bug on map (issue #786) - Fixed Binary file in the tarballs (issue #794) - Fixed LOTW and eQSL upload status updated even when nothing is uploaded (issue #807) - Fixed Imported QSOs contain incorrect My DXCC info (issue #812) - Fixed Statistics Dialog does not show confirmed grids 2025/09/26 - 0.46.1 - Fixed QSO filter incorrectly displays inserted date (issue #752) - Fixed Logbook Search Icon is not centered (issue #753) - Fixed Using CQRLog API Key for Clublog (issue #759) - Fixed Online Service Password leaking via debug files (issue #760) - Fixed Tabs are not showed properly (PR #762 @aa5sh) - Fixed inability to edit Power in QSO Detail (issue #763) 2025/09/12 - 0.46.0 - [NEW] - NewContact: POTA/SOTA/WWFF/IOTA info is taken from the nearest spot (@aa5sh @foldynl) - [NEW] - DXSpots are sent to Flex Radio (PR #694 @aa5sh) - [NEW] - CWConsole - Added support for automatic periodic sending of CW Macros (issue #708) - [NEW] - Added mapping of Winkey hardware buttons to CW macro keys F1–F4 (issue #711) - [NEW] - Added Search Types to the Logbook Search Editbox (issue #733) - [NEW] - Rig - Periodic Rig status reporting independent of its changes (PR #730 @aa5sh) - [NEW] - Settings - Serial Port Completer for MacOS and Linux (PR #737 @aa5sh) - [NEW] - Hamlib - Attempt to send Power On when connecting the Rig - [NEW] - POTA Spots Info is received from the API at api.pota.app to improve POTA detection - [CHANGED] - Logbook Search Filter Widget - Added Search Widget - [CHANGED] - QSO Detail Country boxes use the new Search Filter Widget - [CHANGED] - NewContact - RST field uses the Overwrite Mode - [CHANGED] - NewContact - Default cursor position in RST is at the first character - [CHANGED] - Setting Dialog - Modes - Default Report can define cursor position - [CHANGED] - HamlibRot - Changed Poll Interval from 500 to 2000ms - Fixed DUPE is not detected for the first Contest QSO (issue #699) - Fixed FREQ_RX/BAND_RX is present only when RX and TX freqs are different (issue #714) - Fixed Repeated log recording (issue #722) - Fixed QSO Filter contains untranslated QSO items (issue #732) 2025/07/11 - 0.45.0 - [NEW] - Single Dialog for Upload/Download Online Services (issue #448) - [NEW] - Added option to swap paddles to Winkey settings (issue #676) - [NEW] - Added native support for the FLRig interface (issue #679) - [NEW] - Added New Version Notification - only for MacOS and Windows (PR #669 @aa5sh) - [NEW] - QRZ Upload - Added support for multiple API Keys - [NEW] - Logbook - Added highlighting to the filter button when a filter is active - [NEW] - WSJTX - Filtered label is shown when filter is enabled - [NEW] - DXC - Filtered label is shown when filter is enabled - [NEW] - Added support to Upload Cloudlog/Wavelog - [NEW] - Add JS8 to legacy_modes.json (issue #677) - [CHANGED] - Unification Settings storage - [CHANGED] - Calculate distances according to IARU rules - Fixed missing Wsjtx Spot values in the AlertWindow 2025/05/11 - 0.44.1 - Fixed Rotator Widget Seg Fault for new users (issue #666) 2025/05/09 - 0.44.0 - [NEW] - Activity Manager - Added SKCC, UKSMG and FISTS as Dynamic Fields - [NEW] - QSO - FISTS, SKCC, and UKSMG are auto-filled from MembershipQE (issue #628) - [NEW] - Rotator - Added QSO destination needle (issue #644) - [NEW] - QSO Detail - Adds grayline and short path (PR #653 @kyleboyle) - [CHANGED] - Rotator - Needle colors correspond to the online map (issue #644) - Fixed TCI cw_macros must contain RigID (issue #663) - Fixed TCI setKeySpeed sets keyer and macros speed (issue #663) - Fixed Data mode missing in rig control window - rigctld (issue #660 @aa5sh) - Improved DXC Mode detection - Updated Simplified Chinese translation 2025/04/19 - 0.43.1 - Fixed Click on PHONE DX Spots sets wrong mode (issue #453) - Fixed No freq via Omnirig for IC7400 (issue #639) 2025/04/04 - 0.43.0 - [NEW] - Added support to receive QSOs from CSN SAT Device (PR #610 @aa5sh) - [NEW] - Bandmap - Multiple independent bandmap windows (PR #593 @kyleboyle @foldynl) - [NEW] - Winkey Keyer driver currently supports v1 and v2 hardware - [NEW] - QSO Detail - QSLs QSLr Msg is editable - [NEW] - Activity Manager - Added new dynamic field - QSL Message Send - [CHANGED] - HamlibDrv - Enabled Power, RIT, XIT, Morse for RIG Netctl - [CHANGED] - QSO Detail - QSLMSG replaced by QSLMSG_RCVD (issue #633) - [CHANGED] - eQSL Upload - Added an option to choose a QSLMsg field - [CHANGED] - eQSL Download - eQSL QSLMSG is stored to QLog QSLMSG_RCVD - [CHANGED] - eQSL Download - Added QSLMSG_RCVD merging - eQSL message is appended - Fixed Speed pot doesn't seem to work with a WinKeyer; double chars (issue #618) - Fixed BandMap Spots colour change after a QSO (issue #632) - Fixed Incorrect Field Mapping for Received eQSL Messages (issue #633) 2025/03/07 - 0.42.2 - Fixed Logbook country translations (issue #608) - Fixed Unexpected dialog when QSO after contest (issue #614) - Fixed Statistics Widget does not display NULL continents (@aa5sh) - Fixed Statistics Widget does not display NULL Band, Mode - Fixed Statistics Widget TOP10 does not display removed DXCCs - Fixed Statistics Widget TOP10 does not display translated country names - Fixed Awards Widget does not display removed DXCCs 2025/02/22 - 0.42.1 - Fixed Unexpected timezone info (issue #600) - Fixed DXCC Statistics picks more entities (issue #601) - Fixed a crash when no internet connection 2025/02/14 - 0.42.0 - [NEW] - Awards - Added Slots - total over each band (issue #538) - [NEW] - Awards - Added Grid Award - 2/4/6 Chars grid (issue #564) - [NEW] - Settings - Added options to switch 12/24 time and date format (issue #573) - [NEW] - Activity Manager - Added new dynamic fields - Rig (issue #575) - [NEW] - LoTW Import - Fill missing information also for confirmed QSOs (@aa5sh) - [NEW] - Added CW macro QTH - [NEW] - DXC - Added 15min Trend - [CHANGED] - Changed IOTA LOV Source, the official web is used - [CHANGED] - CSV Export: Time and Date formats use ISO8601 format (issue #562) - [CHANGED] - Settings - Renamed Shortcuts to GUI tab - [CHANGED] - LOV - Improved LOV download performance (PR #582 @aa5sh) - Partial fix Windows State/Size does not save in case of fullscreen (issue #418) - Fixing TCI error when you change Rig (issue #526) - Fixed DXCC Award total worked confirmed counts included deleted entities (PR #588 @aa5sh) - Fixed Raspberry PI Flatpak - Import Select file dialog crashes (issue #589) - Suppressed the ability to edit Contest fields after the start (issue #590) 2025/01/21 - 0.41.1 - Fixed compilation issue under Debian 12 (issue #571) - Fixed Incorrect GPL version in rpm/deb packages (issue #572) - Fixed MacOS floating utility window bug (PR #576 @kyleboyle) - Updated IT translation 2025/01/11 - 0.41.0 - [NEW] - Logbook - Added a new context menu item - Update QSO from Callbook (issue #450 @aa5sh) - [NEW] - DIGI mode is used in case of DXC Digi Spots (issue #480) - [NEW] - DXC - Retrieve information about SOTA, POTA, IOTA and WWFF from comment (issue #482) - [NEW] - Alert - Added SOTA, POTA, IOTA and WWFF filter - [NEW] - Added the COM Port Completer for Windows platform (issue #490) - [NEW] - Settings - Added DXCC Confirmed By options (issue #508) - [NEW] - Added POTA Export Formatter (activator/hunter) (PR #514 @kyleboyle) - [NEW] - CW Console - CW Halt with the user-defined shortcut (issue #518) - [NEW] - Added an input parameter to save debug message to file - [NEW] - Logbook - Added sorting function to logbook table columns (PR #540 @kyleboyle) - [NEW] - Network Notification - Added Rig Status Notification - [NEW] - Implemented ADIF 3.1.5 - [NEW] - ADIF 3.1.5 - Added new submodes FSKH245 and FSKH105 for HELL - [NEW] - ADIF 3.1.5 - Added new contest IDs - [NEW] - ADIF 3.1.5 - Added new columns (Import/Export only) - [NEW] - ADIF 3.1.5 - Added My DARC DOK to Station Profile - [CHANGED] - Settings: disabled band and mode name modification - [CHANGED] - DX Stats contain all enabled bands (issue #538) - [CHANGED] - Removed Freq, TimeDate On/Off Data Type Indicators (issue #552) - [CHANGED] - ADIF 3.1.5 - VUCC and MY_VUCC can contain 6 or 4-chars locators - [CHANGED] - Stop exporting default value N for qsl_rcvd, qsl_sent, lotw/dcl/eslq_qsl_rcvd/sent - [CHANGED] - Extended QSL/Import Dupe matching rule to Callsign, Band, Mode, Time and Sat_Name (issue #563) - Fixed MacOS - keep floating windows visible on app unfocus (issue #530) - Fixed Contest Filter ignores the first QSO (issue #529) - Fixed It is not possible to quit Qlog with detached widgets Rot and Rig (issue #534) - Fixed ADX/CSV/JSON do not export non-ASCII chars (issue #542) - Fixed Checking the 60m checkbox in cluster filters allows 160m spots to appear (issue #543 @aa5sh) - Fixed Problems uploading to QRZ.com (issue #559 PR #561 @aa5sh) - Fixed DX Stat screen is jumping up/down - Fixed Omnirig drivers: Digi modes are not correclty recognized 2024/11/29 - 0.40.1 - Fixed Bands - Added missing 8m band (issue #515) - Fixed CW Console - EXCSTR does not work properly (issue #517) - Fixed Activity Manager - Missing Propagation Mode None (issue #519) - Fixed QSO Filter - filter fields with random order (PR #525 @aa5sh) - Fixed TCI error when you change Rig (issue #526) - Fixed NewContact - satellite mode too wide (issue #527) 2024/11/24 - 0.40.0 - [NEW] - Activity Manager - merged Layout Manager and profiles (issue #408) - [NEW] - Activity Manager - Added new dynamic fields - Contest fields, RX/TX Power - [NEW] - Added light support for contests (issue #345) - [NEW] - Added CW macros EXCHSTR, EXCHNR, EXCHNRN - [NEW] - Export Filter - Added user filter combo (original idea PR #476 @aa5sh) - [NEW] - New Contact - Added expand/collapse button to QSO field tab widget (PR #495 @kyleboyle) - [NEW] - Alert - Added CQZ and ITUZ filters - [NEW] - KSTChat - Added a new 40MHz room (PR #496 @kyleboyle) - [NEW] - Station Profile contains Operator Callsign (issue #441 @kyleboyle) - [NEW] - Station Profile contains County (issue #493 @kyleboyle) - [NEW] - Statistics - Adds time of day and better qso mapping (PR #501 @kyleboyle) - [NEW] - Bandmap - Tooltip shows a spotter callsign (PR #507 @Skittlebrau) - [CHANGED] - New Contact - Renamed DXCC Tab to DX Stats contains DXCC and Station Statistics (issue #477) - [CHANGED] - QSL Import dialog - Detail text is selectable by mouse and keyboard - [CHANGED] - Removed Main Menu Layout; Activity Manager is in the bottom-left corner - [CHANGED] - Removed Keep Options from the Equipment Menu - use Activity Manager for it - Fixed issue when CW is always selected after Settings exiting or connecting the Rig - Updated Timezone definition file - version 2024b 2024/10/05 - 0.39.0 - [NEW] - DXC - Added Full-text search - [NEW] - Select S in RST Edit when focused (issue #454) - [NEW] - Alerts - Added Member Column - [CHANGED] - HamlibDrv Rig/Rot- Added multiplatform reliable sleep - [CHANGED] - Changed Backup policy - [CHANGED] - Logbook page size - improved performance - [CHANGED] - Logbook - CTRL-A (Select All) is disabled - [CHANGED] - Awards - Bands are displayed based on the Settings (issue #452) - [CHANGED] - WSJTX - More reliable detection of CQ stations (PR #471 @aa5sh) - [CHANGED] - WSJTX - SOTA/POTA/WWFF/SIG are being added to the logged QSO (PR #463 @aa5sh) - [CHANGED] - Stats - Add a confirmation dialog for displaying over 50k QSOs on the map - [CHANGED] - New Contact - Starting QSO Timer when Rig online and WSJTX Update Callsign Status is received - [CHANGED] - Added a postponed handling for Rig soft errors (issue #472) - Fixed WSJT-X does not emit band change if rig is disconnected (issue #447) - Fixed Wrong import of ADIF file of another log program (issue #455) - Fixed WSJTX log record is stored incorrectly if it contains non-ASCII chars(issue #458) - Fixed ADIF import does not import records with old DXCC Entities (issue #459) - Fixed ADIF import incorrectly uses Station Profile parameters (issue #461) - Fixed Logbook - QSO Table Column Width Does Not Stick (issue #464) - Fixed Alerts Window displays OOB Spots (issue #469) - Fixed Field values from past QSOs are used incorrectly in case of WSJTX QSOs (#issue 470) 2024/08/29 - 0.38.0 - [NEW] - Logbook - Added Send DX Spot to the QSO Context Menu - [NEW] - DX Filter - Added Dedup Time/Freq difference setting (@aa5sh) - [NEW] - Rig Setting - Added RTS/DTR PTT Type support (issue #353) - [NEW] - Bandmap - Scrollbar position is saved per band (issue #415) - [NEW] - New Contact - Added a dynamic value completer for SIG field (issue #425) - [NEW] - Awards - Added SOTA/POTA/WWFF (@aa5sh issue #311) - [NEW] - Awards - Added Not-Worked Filter - [NEW] - New Contact - Added Long Path Azimuth info - [NEW] - POTA Fields allow a comma-delimited list of one or more POTA Refs - [NEW] - WSJTX tunes freq/mode like Rig if rig is disconnected - [CHANGED] - Alert Widget is a Dock Widget (issue #399) - [CHANGED] - QLog adds more information from callbook for WSJTX QSOs (issues #403 #405 #420) - [CHANGED] - File Open dialogs are not a native dialog under Linux (issue #427) - [CHANGED] - Profiles transferred to DB - [CHANGED] - LOV last_dates transferred to DB - [CHANGED] - DX Cluster - Login Callsign is always the base Callsign - [REMOVED] - Setting DXCC Date - Fix for MacOS Layout Geometry Restore (@aa5sh) - Fixed TQSL does not block GUI thread - Fixed MacOS build process (@aa5sh) 2024/07/26 - 0.37.2 - Fixed Field QSL Send Via should be retained (issue #413) - Fixed Set rotator position fails if azimuth > 180 (issue #417) - Fixed Windows State/Size does not save in case of fullscreen (issue #418) - Fixed Significant rounding during azimuth calculation (issue #422) - Updated Simplified Chinese translation - Updated Spanish translaction - Added Italian translation (thx IK1VQY) 2024/07/10 - 0.37.1 - Fixed QSO Table Callsign filter is not filled properly (issue #401) - Fixed DXC zero frequency for last QSO in case of FT8 QSOs (issue #404) - Fixed Callsign Context Menu does not work (issue #409) - Fixed QSO Detail Save and Edit buttons are not translated (issue #410) 2024/07/01 - 0.37.0 - [NEW] - Added Shortcuts Editor (issue #293) - [NEW] - Added QO100 Bandplan to correctly categorize the DX Spots - [NEW] - Improveded detection of SH/DX SHF Spots - [NEW] - Online Map - Added WSJTX CQ Spots - [NEW] - WSJTX - Sortable View - [NEW] - Alerts - Sortable View - [NEW] - Added Spanish translation (thx LU1IDC) - [NEW[ - Added Search Callsign Clear Button (issue #396) - [CHANGED] - QRZ auth should be over POST with form data (issue #389) - [CHANGED] - Big CTY file is used - [CHANGED] - Callbook Country DXCC ID is used in case of difference from Big CTY - [CHANGED] - Removed ALT+W and CTRL+DEL shortcuts - [CHANGED] - Removed New Contact and Save Contact from Logbook Main Menu - Fixed Guantanamo KG4 Issue (issue #372) - Fixed QRZ Lookup Not Including Full Name - History (issue #388) - Fixed Spot Last QSO contains TX freq, should contain RX freq (issue #390) - Fixed Spot Last QSO must contain Freq in kHz (issue #391) - Fixed Bandmap select previous selected callsign issue (issue #394) - Fixed Malfunctioning tuning of WSJTX Alert spot - Fixed DXCC Status for FT4 Spots incorrectly identified in WSJTX 2024/06/07 - 0.36.0 - [NEW] - WSJTX: Added support to received ADIF QSO Log record - [NEW] - Sat mode is derived from RX/TX Freq - [NEW] - Logbook filters change color when enabled - [NEW] - Frequency input boxes PageUp/Dn switches the band (issue #360) - [NEW] - CTRL + PgUp/Dn switch band on the connected rig - global shortcut (issue #360) - [NEW] - Added number of filtered QSOs (issue #374) - Fixed Callbook query does not work (issue #377) - Fixed Logbook columns are reordered after Delete (issue #383) - Fixed Missing Republic of Kosovo flag (issue #384) 2024/05/21 - 0.35.2 - Improved delete performance; added delete progress bar (issue #351) - Fixed Password with plus is incorrectly sent to online services (issue #366) - Fixed Compilation issue under v4.6 (issue #368) - Fixed Network Rig configuration is not saved (issue #370) 2024/05/06 - 0.35.1 - Fixed Free QRZ callbook - Name is not populating (issue #363) - Fixed Incorrect CW segment freqs (issue #365) 2024/05/03 - 0.35.0 - [NEW] - Added Rot Interface PSTRotator Network - [NEW] - Added QSO/QSL Since option to eQSL Dialog - [NEW] - Bandmap - Current Mode segment visualisation - [NEW] - CW Console - Added Word/Whole mode switch - [NEW] - Added Callbook Profile Image Widget - [NEW] - ASCII conversion based on Text-Unidecode/iconv algorithm (issue #316 #350) - [NEW] - ITU/CQ Zones can be defined in Station Profile (issue #358) - [CHANGED] - Spacebar is used as a focus changer for fields where space is not allowed - [CHANGED] - Focus does not select text in the input fields - [CHANGED] - Force XCB under Linux Wayland - [CHANGED] - Bandmap - Added Callsign/Freq/Mode to tooltip (issue #355) - Fixed incorrect ADIF date format for clublog_qso_upload_date (issue #342) - Fixed The last name from Callbooks queries (issue #346) 2024/03/25 - 0.34.0 - [NEW] - Rotator Widget - Azimuth by Clicking - [NEW] - Rotator Widget - QSO button provides Short/Long Path (issue #330) - [NEW] - Equipment Menu - Added Keep Options between application restart (issue #331) - Fixed TCI - Thetis Connection issue (issue #327) - Fixed TCI - Spots To Rig are not displayed (issue #328) - Fixed Bandmap unintentionally emits frequency labels (issue #333) - Fixed Failing to load grid square for G and EI SOTA summits (issue #336) - Fixed HRDLog On-Air message is not sent (issue #337) - Fixed Offline Map - Improved Path drawing 2024/03/09 - 0.33.1 - Fixed Rotator offline map is incorrectly centered (issue #324) - Fixed Hamlib integration not working (issue #325) - Fixed issue when Hamlib reopen rig caused Initialization Error - Fixed issue when Omnirig Drv did not emit rigIsReady signal 2024/03/08 - 0.33.0 - [NEW] - Added Rig Interface TCI - [NEW] - Callbook search can be temporarily paused - Improved DXC Mode recognition - Fixed Modal dialog blinks - Windows platform (issue #315) - Fixed LoTW and eQSL download are only QSLs dowloads - button label changed (issue #318) - Fixed i18n: Country Names and Prop-modes are translated (issue #322) 2024/02/10 - 0.32.0 - [NEW] - Added Rig Interface Omnirig v1 (Windows only) - [NEW] - Added Rig Interface Omnirig v2 (Windows only) - [NEW] - Clublog - Added Clear Clublog and reupload QSOs - [NEW] - Clublog - Added Real-time Insert/Update/Delete - [CHANGED] - Clublog - Upload callsign is derived from the Current Profile Callsign - Fixed clang linker failed issue (issue #301) - Fixed SAT Mode U/U missing (issue #308 PR #309 thanks ea5wa) - Fixed Multiple QSO selection. Callsigns modified by mistake (issue #310) - Fixed Callbook query cache is not properly cleared when Callbook settings change (issue #313) 2024/01/05 - 0.31.0 - [NEW] - DXC - Improved Mode recognition - [NEW] - DXC - Switch Rig mode based on DXC Spot Mode (issue #217) - [NEW] - DXC - Added Spot Country Column (issue #273) - [NEW] - DXC - Added Menu for server management - [NEW] - DXC - Added Auto-connect to server - [NEW] - DXC - Added Keep QSOs Context Menu - [NEW] - DXC - Added Clear QSO Context Menu - [NEW] - DXC - Added support for SH/DX response parsing - [NEW] - DXC - Added support for username, password for connection - [CHANGED] - DXC - Commands Combo changed to function button with selectable function - [CHANGED] - DXC - DX Spot is prepared via DXC Command Line, Remark dialog was removed - [NEW] - Online Map - IBP station double-click tunes freq and switch Rig mode - [NEW] - Main Window - Current profile name is shown (issue #282) - [NEW] - Import - Details can be saved to file (issue #284) - [NEW] - Added Simplified Chinese translation (PR #285 thank BG7JAF) - [NEW] - New Contact - Enter saves QSO if QSO time is running (issue #293 - partial) - [NEW] - New Contact - Callsign Enter event saves QSO if no Callbook is active - Pileup Mode (issue #293) - [NEW] - RIG Widget - RIT/XIT are displayed with user-friendly units (issue #294) - [CHANGED] - SAT List download - Shortened download period for SAT list from 30 to 7 days - Fixed ADI Import is too slow (issue #270) - Improved Import/Export Performance - Fixed Missing Satellite Mode SX (issue #291) - Fixed QSO Detail - Issue when Sat-Name field was always disabled - Fixed RPM build - Installed (but unpackaged) metainfo file issue 2023/12/01 - 0.30.0 - [NEW] - QSL Images are stored in the database - [NEW] - Added AppStream Metainfo File (PR #262 thanks AsciiWolf) - [NEW] - Added (WPX) prefix (issue #263) - [NEW] - Added WPX Award statistics - [NEW] - Added support for external translation files(issue #275) - [CHANGED] - Removed QSOID from Export dialog column setting (issue #258) - Fixed Date editor does not support NULL value in Logbook Direct Editor (issue #256) - Fixed duplicate entry in Windows Add or Remove - only Window platform (issue #260) - Fixed RST fields revert to 59 after changing them (issue #261) - Fixed Cannot change TQSL Path in Settings - flatpak (issue #271) 2023/11/13 - 0.29.2 - Fixed QLog is already running error popup on MacOS (issue #257 thanks rjesson) 2023/11/10 - 0.29.1 - Fixed QSL cards tooltip are not displayed under qt6.5 (issue #248) - Fixed Distance unit is not displayed in QSO Info under Windows (issue #250) - Fixed Editing STATION_CALLSIGN can cause unwanted change in QSO Detail (issue #251) - Fixed QSO Detail Operator Name containes an incorrect value (issue #252) - Fixed Calls with VE, VA are coding as Amsterdam & St Paul Islands instead of Canada (issue #253) - Fixed LoTW QSL import reports unmatched QSOs sometime (issue #254) 2023/10/20 - 0.29.0 - [NEW] - Added user-defined layout for New QSO Detail widget - [NEW] - Main window State and Geometry can be saved to layout profile - [NEW] - Awards - Added WAS - [NEW] - Awards - WAZ/ITU/WAC show all possible values - [NEW] - Distance unit (km/miles) is controlled by OS Locale - [CHANGED] - Removed SAT Tab - field can be added via Layout Editor - Improved Import QSO performance - Fixed QLog crashes if POTA, SOTA or WWFF contain incorrect values (issue #245) - Fixed QSOs are not uploaded to QRZ and HRDLog if fields contain HTML delimiter strings (issue #247) 2023/09/22 - 0.28.0 - [NEW] - Added ON4KST Chat Support - [NEW] - Added Az BeamWidth and Az Offset to Antenna Profile - [NEW] - Double-Clicking the IBP callsign in the online map tunes the frequency - Fixed Browse button should open an expecting folder (issue #241) - Fixed Reword QSL buttons and Settings in QSO Details and Settings (issue #242) 2023/08/21 - 0.27.0 - [NEW] - Added HRDLog Support - Fixed Text field alignment (issue #233) - Fixed Rig/Rot Connection port type selection (issue #235) - Fixed Incorrect Distance Value in WSJTX Widget (issue #236) - Fixed Incorrect WSJTX locator target on the map (issue #237) 2023/07/30 - 0.26.0 - [NEW] - Added user-defined layout for New QSO widget - [NEW] - Pressing Spacebar in Callsign field skips RST fields - [NEW] - Added user-defined URL for web lookup (issue #230) - Fixed WSJTX QSOs should have an Operator Name from Callbook (issue #223) - Fixed US call area suffixes not handled correctly (issue #226 thanks Florian) - Fixed QSO Filter Detail allows to save an empty Filter Name (issue #228) 2023/07/17 - 0.25.1 - Fixed Unexpected mode change when Setting Dialog is saved (issue #222) - Fixed QSL_SENT field has an incorrect ADIF name (issue #225) 2023/07/04 - 0.25.0 - [NEW] - Export - Added CSV Format - [NEW] - Export - Added Type of Export Generic/QSLs (issue #209) - [NEW] - Export - Added Exported Columns Setting - [NEW] - Export - All export formats use the ADIF field name convention - [CHANGED] - Export - JSON format contains a header - JSON format change - [CHANGED] - Default Statistics Interval is curr_date-1 and curr_day - Fixed Errors from Secure Storage are not shown (issue #216) - Fixed RX/TX Bands are uneditable when RX/TX freqs are missing (issue #220) 2023/06/16 - 0.24.0 - Fixed Incorrect FT4 mode-submode (issue #212) - Fixed CONTESTIA mode should be CONTESTI (issue #213) - Fixed Context menu deselects NewContactEditLine (issue #215) - FIxed incorrect WSJTX Filter initialization (issue #218) 2023/06/09 - 0.23.0 - [NEW] - Added CWDaemon Keyer Support - [NEW] - Added FLDigi Keyer Support - [NEW] - Online Map - based on locale, the map language is selected (Only EN, FR, GE supported - issue #180) - Fixed After entering longer QTH, the field content is not left-aligned (issue #157) - Fixed wrong QSO Time in case of JTDX (issue #204) - Fixed QSL Sent Date fields are not filled if QSL Sent Status fields are Y (issue #207) 2023/05/07 - 0.22.0 - [NEW] - ADIF Import - My Profile is used to define default values - [NEW] - ADIF Import - Checking a minimal set of input fields (start_time, call, band, mode, station_callsign) - [NEW] - ADIF Import - Added Import Result Summary + Import Detail Info - [NEW] - Main Menu - Added Help -> Mailing List. - [NEW] - Export - Filter for the exported QSOs - [CHANGE] - Renamed Locator to Gridsquare - Fixed Some anomalies in the input and processing of QSLr Date (issue #192) - Fixed User unfriedly CW Keyer Error (issue #194) - Fixed ADIF import (issue #196) - Fixed Operator field is incorrectly used (issue #197) - Fixed Crash if an unknown POTA & SOTA/WWFF Setting is entered (issue #198) - Fixed FLDIGI cannot connect QLog (issue #199) - Fixed if ADIF record is missing band info, add this from freq field (thx DJ5CW) 2023/04/16 - 0.21.0 - [NEW] - Rotator - Added Used-Defined Buttons - [NEW] - Rotator - Added Destination Azimuth Needle - [NEW] - Online Map - Added Antenna Beam Path - [NEW] - Rig - Combos are disbled when disconnected - [NEW] - Club Member Lists (issue #60) - [NEW] - Alert Table shows rule names - [CHANGED] - Alerts, DXC and WSJTX Network Notifications - Fixed Antenna Azimuth Negative Value (issue #191) - Fixed CTY file is not loaded when duplicate record (issue #193) 2023/03/14 - 0.20.0 - [NEW] - Added MUF Layer to online map - [NEW] - Added International Beacon Project (IBP) Beacons to online map - [NEW] - Centering the map on the current profile at start (issue #185) - Fixed incorrect ADIF interpretation of _SENT fields (issue #176) - Fixed Awards Dialog, Table double click for ITU/CQZ/WAZ/IOTA shows incorrect QSOs (issue #177) - Fixed ADIF double-type fields when 0.0 is currently mapped to NULL (issue #178) - Fixed QSO Detail to save NULL instead of empty string (issue #179) - Fixed ADIF Import default _INTL values are now stored correctly (issue #183) - Fixed Maps show an incorrect path if from/to grids are the same (issue #186) - Fixed Online Maps incorrect Bounds if Bandmap callsign double-click (issue #188) - Updated German translation (thx DL2KI) 2023/02/17 - 0.19.0 - [NEW] - Added Aurora Layer to online map - [NEW] - Logbook - filter options are saved and restored - [NEW] - Map Setting is saved and restored (issue #140) - [NEW] - QSO Duration (issue #158) - [NEW] - DX Cluster uses monospace font (issue #164) - [NEW] - Awards - if click on the Entity/band the logbook filter is set (issue #168) - [NEW] - WSJTX - Added Multicast support (issue #172) - Fixed WWFF LOV Download (issue #169) 2023/01/15 - 0.18.0 - [NEW] - ADIF 3.1.4 updates - Added new modes FREEDV and M17 - Added new band (submm) - Adopted Altitude (for SOTA only) - Adopted POTA (includes POTA List) - Adopted Gridsquare_ext (only import/export) - Adopted Hamlogeu_* (only import/export) - Adopted HamQTH_* (only import/export) - [NEW] - Added new DXCC Status and color for it - Confirmed - [NEW] - New Contact - Tab selection is saved - [NEW] - Grid can contain 8-characters - [NEW] - User filter can contain NULL value - [NEW] - Compilation - added variables for external sources - [NEW] - My DXCC/CQZ/ITUZ/Country is filled - [NEW] - Alerts - Added Aging (issue #153) - [NEW] - Alerts - Added DXCC Status Color (issue #153) - [NEW] - DXC - Added Log Status to filter (issue #154) - [NEW] - DXC - Added Spot deduplication to filter (issue #154) - [NEW] - WSJTX - Added CQ-Spot Filter (issue #155) - [NEW] - QSO Detail contains DXCC Tab (issue #156) - [CHANGED] - New QSO DXCC Tab reworked (issue #144) - [CHANGED] - All DXCC Stats are computed based on My DXCC instead of My Callsign - [CHANGED] - Station Profile Setting layout 2022/12/18 - 0.17.0 - [NEW] - NetPort and Polling interval can be defined for NET Rigs - [NEW] - NetPort can be defined for NET Rots - [NEW] - Added Saving Bandmap Zoom per band (issue #137) - [NEW] - CW speed synchronisation (issue #139) - Fixed Missing callbook data when callsign has prefix (issue #133) - Fixed Winkey2 echo chars are incorrectly displayed in CW Console (issue #141) - [CHANGED] - Online Map - Gray-Line is enabled by default - Update Timezone database 2022/11/20 - 0.16.0 - [NEW] - SOTA/IOTA lists updated regularly - [NEW] - Added WWFF list, updated regularly - [NEW] - QTH/Grid are filled based on SOTA/WWFF - [NEW] - DXC/WSJTX columns are movable, added column visibility setting - [NEW] - DXC/WSJTX columns layout is saved - [NEW] - Added Wiki&Report Issue links to Help section - [NEW] - About dialog contains run-time information - [NEW] - Solar Info as a ToolTip - [NEW] - QSO Manual Entry Mode - Fixed Bandmap unlogical animation when band is changed (issue #128) - Fixed Bandmap marks are not displayed correctly when RIT/XI (issue #131) - Fixed Setting Dialog size - Update Timezone database 2022/10/16 - 0.15.0 - Fixed Keeping the Bandmap RX mark always visible when centre RX is disabled (issue #115) - Fixed Equipment Menu: Swapped Connect Keyer and Rig (issue #122) - Fixed Callsign is deleted when clicking bandmap (issue #126) - Fixed typo in the Map layer menu (issue #127) - Fixed compilation issues & warning under QT6 - preparation for QT6 migration 2022/10/02 - 0.14.1 - Fixed CW Console - HALT Button is not enabled under Ubuntu flavours (issue #124) 2022/09/29 - 0.14.0 - [NEW] CW Console (Winkey2, Morse over CAT support) - [NEW] DX Cluster pre-defined commands (send last spot, get stats) - [NEW] Added DX Cluster Views (Spots, WCY, WWV, ToALL) - [NEW] Implemented DX Cluster Reconnection - [NEW] Remember last used DX Cluster - [CHANGED] - UI unifications - Rot/Rig/DXC - Fixed COM port validation for Windows platform - Fixed Reconnecting (DXC/Callbook) (issue #110) - Fixed DX Cluster crashes when DXC server is not connected and a command is sent (issue #111) - Fixed Bandmap callsign selection not fully works (issue #116) 2022/08/06 - 0.13.0 - [NEW] QSY Contact Wiping (issue #100) - [NEW] Timeoff is highlighted when QSO timer is running (issue #100) - [NEW] Callsign whisperer - [NEW] Bandmap - Spot's color is recalculated when QSO is saved - [NEW] BandMap - CTRL + Wheel zooming - [NEW] BandMap - Zooming via buttons keeps a focus on centre freq - [NEW] BandMap - DX Spot's Comment as a tooltip - [CHANGED] BandMap - UI Layout - Fixed MacOS builds (PR #102) (thx gerbert) - Fixed templates under MacOS (PR #101) (thx gerbert) - Fixed WindowsOS Installer - Unable to upgrade version 2022/07/15 - 0.12.0 - [NEW] Statistics - Show ODX on the map - [EXPERIMENTAL] Support for QT Styles (issue #88) - [CHANGED] - Removed F2 as a shortcut for QSO field editing - Next fixing of a high CPU load when DXC is processed (issue #52) - Fixed QSO fields from prev QSOs when Prefix - Callsign - Suffix (issue #90) - Fixed Chaotic QSO start time (issue #93) - Offline maps - Lighter colors, night sky removed, Sun position removed (issue #97) - Fixed incorrect A-Index colort (issue #98) - Fixed Stats Widget - percents - does not reflect date range (issue #99) - Fixed potential LogParam Cache issue - Import/Export polishing 2022/06/26 - 0.11.0 - [NEW] QSO Detail/Edit Dialog - [NEW] Added mW power Support - [NEW] Implemented ADIF 3.1.3 - [NEW] Rigwidget saves last used freq for bands - Fixed Rig Combo size when Rig Profile name is long (issue #31) - Fixed CQZ, ITUZ do not validate whether their entered value is a number (issue #75) - Fixed vucc, myvucc must be uppercase - Edit mode (issue #76) - Fixed Greyline-Map is very dark (issue #78) - Fixed DX Country is not saved properly when name is between S-Z (issue #79) - Fixed Bandmap call selection - only left mouse button (issue #82) - Fixed My Notes Copy & Paste - Rich Text (issue #83) - Fixed Font appearance in the context menu (issue #84) 2022/06/05 - 0.10.0 - [NEW] Bandmap shows XIT/RIT Freq - [NEW] Bandmap RX Mark Center (issue #69) - [NEW] Getting PTT State from RIG - only for CAT-controlled rigs - [NEW] PTT Shortchut - only for CAT-controlled rigs - Fixed Lost internet conneciton is not detected properly (issue #56) - Fixed Cannot manually edit QSO Date&Time (issue #66) - Fixed Field contents in capital letters (issue #67) - Fixed Band RX is not updated when RX Freq is edited (issue #72) - Fixed Stat Windget does not handle a date range correctly (issue #73) - Fixed eQSL card is incorreclty handled when a callsign contains special characters (issue #74) 2022/05/20 - 0.9.0 - [NEW] User-defined Spot Alerts - [NEW] User filter contains a new operator "Starts with" - [NEW] a real local time is shown for the DX callsign (issue #45) - [NEW] Lotw/eQSL registration info is showed from callbooks - [NEW] Added shortcuts for menu and tabs - [NEW] Bandmap - Switching a band view via Bandmap context menu (issue #57) - [CHANGED] - Network Notification format - logid field is included in all messages - Fixed issue with My Notes multiple lines edit/show mode (issue 39) - Fixed issue when GUI froze when Rig disconnect was called (issue #50) - Partially fixed a high CPU load when DXC is processed (issue #52) - Fixed crashes under Debian "bullseye" - 32bit (issue #55) - Fixed Bandmap Callsign selection margin (issue #61) - Fixed issue when it was not possible to enter RX/TX freq manually 2022/04/22 - 0.8.0 - RIT/XIT offset enable/disable detection (issue #26) - Fixed Rig Setting, Data Bits (issue #28) - Added default PWR for Rig profile (issue #30) - Fixed issue when GUI freezes during Rig connection (issue #32 & #33) - Fixed issue with an incorrect value of A-Index (issue #34) - Fixed ADI Import - incorrect _INTL fields import (issue #35) - Fixed isuue with an editing of bands in Setting dialog (issue #36) - Fixed issue with hamlib when get_pwr crashes for a network rig (issue #37) - Improved new QSO fields are filled from prev QSO (issue #40) - Added mode for a network Rig (issue #41) - Fixed warning - processing a new request but the previous one hasn't been completed (issue #42) - Fixed Info widget when Country name is long (issue #43) - Reordered column visibility Tabs (issue #46) - Improved Rig tunning when XIT/RIT is enabled (issue #47) 2022/04/08 - 0.7.0 - Settings - Ant/Rig/Rot are profiles - Reworked Ant/Rig/Rot Pages - Added RIG Properties (issue #18) - Rig Widget - added Band/Rig/Mode selection (issue #5) - added VFO/XIT/RIT/PWR Indicators (issue #20 and issue #23) - Rot Widget - works again - AZ/EL are stored to database if rot is connected (issue #22) - Fixed issues with the Statistic Widget Combos (issue 25) 2022/03/10 - 0.6.5 - Fixed missing modes in Setting Dialog (issue #11) - Fixed Station Profile text color in dark mode (issue #10) - Fixed DXCluster Server Combo (issue #12) - Fixed TAB focus on QSO Fields (issue #14) 2022/03/06 - 0.6.0 - [NEW] QSL - added import a file with QSL - with QSLr column - Fixed QLog start when Band is 3cm (too long start time due to the Bandmap drawing) (issue #6) - Fixed Rotator Widget Warning - map transformation issue (issue #8) - Changed Bandmap window narrow size (issue #3) - Changed User Filter Widget size - Removed Units from Logbook widget - Removed UTC string - Renamed RSTs, RSTr etc. (issue #4) - Renamed Main Menu Services->Service and Station->Equipment - Internal - reworked Service networking signal handling 2022/02/19 - 0.5.0 - DB: Added submodes used by FLDigi and added their mapping to LoTW, Clublog etc. - DB: Added all ADIF-defined modes/submodes - DB: Remapped QSO fields to International field - NAME_INTL etc. - DB is converted to a new schema to use *_INTL columns - non-INTL columns are recalculated from _INTL columns - accents removal function - GUI: Added Dark mode - GUI: Time/date format is controlled by Locale (except WSJTX, FLDigi inputs) - Import/Export: ADI do not export UTF-8 characters and *_INTL fields - Import/Export: ADX exports UTF-8 characters and *_INTL fields - Import/Export: Added Import of ADX file format - Logbook: Shows QSO summary as a Callsign's tooltip - Logbook: QSO time is shown with seconds; added timezone - New QSO: Added My notes - free text for your personal notes - Backup: Change backup format form ADI to ADX (ADX supports UTF-8) - Settings: WSJTX Port is changable 2022/01/09 - 0.4.0 - Stats: Added Show on Map - QSOs and Worked&Confirmed Grids - Stats: Stats are refreshed after every QSO - WSJTX: Remove TRX/Monitoring Status - Added Split mode - RX/TX RIG Offset - Added export of selected QSOs - Fixed FLdigi interface - CPPChecks & Clazy cleanup 2021/12/19 - 0.3.0 - Added new fields to Station Profile - Station Profile is stored in DB (not in QSetting) - Added VUCC field for QSO - Added BandMap marks (CTRL+M) - Clublog is uploaded the same way as EQSL and LOTW (modifications are resent too) - Clublog real-time upload was removed (temporary) - QRZ.com - Added callsign query and upload QSO support - Callbook cooperation - Primary&Secondary - Secondary used when Primary did not find 2021/11/28 - 0.2.0 - Initial fork changes - Changed Logging format (Time + severity + context) - Added Application singleton - GUI Tweaking - Changed Tab-key behaviour - DXC Widget - manu others - DXCCInfo is clean correctly when callsign is reset - Password are stored in a Secure Storage - Changed sorting criteria for BandFilter Combobox [Logbook View] - Added DXCluster Filters - Context Menu of the DXC - DXCluster spot time in UTC - Changed Style for Enable/Disable column in QTableView (Checkbox) - Fixed issue when mode combo is not refreshed after editing modes in Setting Dialog - Database export to ADIF before starting - Added Splashscreen - Hamlib rework - Reworked Hamlib Setting Dialog - Detailed Setting for Serial Port - Added Network Radio/Rot Support - Connect/Disconnect Rig and Rot - Improved Error Handling from Rig/Rot - Fixed Setting freq/mode/submode from/to GUI - Debug mode is more verbose and controled by QT_LOGGING_RULES variable - BandMap automatically clear spots when Aging Time is enabled - BandMap band is set based on NewContact Widget frequency - Many changes and improvements in LogWindow - Minor changes in the input QSO forms - Changed Editing QSO flow - Full ADIF parsing and storing - Added Column Visibility Setting - Added DEB control files - CTY is updated regularly - Main&NewContact Window reworking - Removed Contest Tab - Saving correct values for PROPMODE, QSL Sent/RCVD, SATs, IOTA, SOTA SIG, SIG_INFO, DOK - Added k-index, SFI saving - Added my Ant parameter - LoTW Import/Export is verified and improved - Added Rig offset support (support for Transverters) - Added Station Location Profiles - Added User-defined filters - Added eQSL upload/download ADIF, download QSL Image - Added Online Map Widget - Reworked WSJTX Widget - Added Spot Aging - Sorted based on Last Activity Time - Reworked Stats - Added Awards - Added Czech Translation foldynl-QLog-3252ff9/LICENSE000066400000000000000000001726731517334601000154100ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ZoneDetect ========== (https://github.com/BertoldVdb/ZoneDetect) Copyright (c) 2018-2019, Bertold Van den Bergh (vandenbergh@bertold.org) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTOR 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. TimeZone Database ================= (https://github.com/evansiroky/timezone-boundary-builder/blob/master/DATA_LICENSE) Open Database License (ODbL) v1.0 Disclaimer Open Data Commons is not a law firm and does not provide legal services of any kind. Open Data Commons has no formal relationship with you. Your receipt of this document does not create any kind of agent-client relationship. Please seek the advice of a suitably qualified legal professional licensed to practice in your jurisdiction before using this document. No warranties and disclaimer of any damages. This information is provided ‘as is‘, and this site makes no warranties on the information provided. Any damages resulting from its use are disclaimed. Plain language summary A plain language summary of the Open Database License is available. Alternative formats: Plain Text ODC Open Database License (ODbL) Preamble The Open Database License (ODbL) is a license agreement intended to allow users to freely share, modify, and use this Database while maintaining this same freedom for others. Many databases are covered by copyright, and therefore this document licenses these rights. Some jurisdictions, mainly in the European Union, have specific rights that cover databases, and so the ODbL addresses these rights, too. Finally, the ODbL is also an agreement in contract for users of this Database to act in certain ways in return for accessing this Database. Databases can contain a wide variety of types of content (images, audiovisual material, and sounds all in the same database, for example), and so the ODbL only governs the rights over the Database, and not the contents of the Database individually. Licensors should use the ODbL together with another license for the contents, if the contents have a single set of rights that uniformly covers all of the contents. If the contents have multiple sets of different rights, Licensors should describe what rights govern what contents together in the individual record or in some other way that clarifies what rights apply. Sometimes the contents of a database, or the database itself, can be covered by other rights not addressed here (such as private contracts, trade mark over the name, or privacy rights / data protection rights over information in the contents), and so you are advised that you may have to consult other documents or clear other rights before doing activities not covered by this License. The Licensor (as defined below) and You (as defined below) agree as follows: 1.0 Definitions of Capitalised Words “Collective Database” – Means this Database in unmodified form as part of a collection of independent databases in themselves that together are assembled into a collective whole. A work that constitutes a Collective Database will not be considered a Derivative Database. “Convey” – As a verb, means Using the Database, a Derivative Database, or the Database as part of a Collective Database in any way that enables a Person to make or receive copies of the Database or a Derivative Database. Conveying does not include interaction with a user through a computer network, or creating and Using a Produced Work, where no transfer of a copy of the Database or a Derivative Database occurs. “Contents” – The contents of this Database, which includes the information, independent works, or other material collected into the Database. For example, the contents of the Database could be factual data or works such as images, audiovisual material, text, or sounds. “Database” – A collection of material (the Contents) arranged in a systematic or methodical way and individually accessible by electronic or other means offered under the terms of this License. “Database Directive” – Means Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended or succeeded. “Database Right” – Means rights resulting from the Chapter III (“sui generis”) rights in the Database Directive (as amended and as transposed by member states), which includes the Extraction and Re-utilisation of the whole or a Substantial part of the Contents, as well as any similar rights available in the relevant jurisdiction under Section 10.4. “Derivative Database” – Means a database based upon the Database, and includes any translation, adaptation, arrangement, modification, or any other alteration of the Database or of a Substantial part of the Contents. This includes, but is not limited to, Extracting or Re-utilising the whole or a Substantial part of the Contents in a new Database. “Extraction” – Means the permanent or temporary transfer of all or a Substantial part of the Contents to another medium by any means or in any form. “License” – Means this license agreement and is both a license of rights such as copyright and Database Rights and an agreement in contract. “Licensor” – Means the Person that offers the Database under the terms of this License. “Person” – Means a natural or legal person or a body of persons corporate or incorporate. “Produced Work” – a work (such as an image, audiovisual material, text, or sounds) resulting from using the whole or a Substantial part of the Contents (via a search or other query) from this Database, a Derivative Database, or this Database as part of a Collective Database. “Publicly” – means to Persons other than You or under Your control by either more than 50% ownership or by the power to direct their activities (such as contracting with an independent consultant). “Re-utilisation” – means any form of making available to the public all or a Substantial part of the Contents by the distribution of copies, by renting, by online or other forms of transmission. “Substantial” – Means substantial in terms of quantity or quality or a combination of both. The repeated and systematic Extraction or Re-utilisation of insubstantial parts of the Contents may amount to the Extraction or Re-utilisation of a Substantial part of the Contents. “Use” – As a verb, means doing any act that is restricted by copyright or Database Rights whether in the original medium or any other; and includes without limitation distributing, copying, publicly performing, publicly displaying, and preparing derivative works of the Database, as well as modifying the Database as may be technically necessary to use it in a different mode or format. “You” – Means a Person exercising rights under this License who has not previously violated the terms of this License with respect to the Database, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. Words in the singular include the plural and vice versa. 2.0 What this License covers 2.1. Legal effect of this document. This License is: a. A license of applicable copyright and neighbouring rights; b. A license of the Database Right; and c. An agreement in contract between You and the Licensor. 2.2 Legal rights covered. This License covers the legal rights in the Database, including: a. Copyright. Any copyright or neighbouring rights in the Database. The copyright licensed includes any individual elements of the Database, but does not cover the copyright over the Contents independent of this Database. See Section 2.4 for details. Copyright law varies between jurisdictions, but is likely to cover: the Database model or schema, which is the structure, arrangement, and organisation of the Database, and can also include the Database tables and table indexes; the data entry and output sheets; and the Field names of Contents stored in the Database; b. Database Rights. Database Rights only extend to the Extraction and Re-utilisation of the whole or a Substantial part of the Contents. Database Rights can apply even when there is no copyright over the Database. Database Rights can also apply when the Contents are removed from the Database and are selected and arranged in a way that would not infringe any applicable copyright; and c. Contract. This is an agreement between You and the Licensor for access to the Database. In return you agree to certain conditions of use on this access as outlined in this License. 2.3 Rights not covered. a. This License does not apply to computer programs used in the making or operation of the Database; b. This License does not cover any patents over the Contents or the Database; and c. This License does not cover any trademarks associated with the Database. 2.4 Relationship to Contents in the Database. The individual items of the Contents contained in this Database may be covered by other rights, including copyright, patent, data protection, privacy, or personality rights, and this License does not cover any rights (other than Database Rights or in contract) in individual Contents contained in the Database. For example, if used on a Database of images (the Contents), this License would not apply to copyright over individual images, which could have their own separate licenses, or one single license covering all of the rights over the images. 3.0 Rights granted 3.1 Subject to the terms and conditions of this License, the Licensor grants to You a worldwide, royalty-free, non-exclusive, terminable (but only under Section 9) license to Use the Database for the duration of any applicable copyright and Database Rights. These rights explicitly include commercial use, and do not exclude any field of endeavour. To the extent possible in the relevant jurisdiction, these rights may be exercised in all media and formats whether now known or created in the future. The rights granted cover, for example: a. Extraction and Re-utilisation of the whole or a Substantial part of the Contents; b. Creation of Derivative Databases; c. Creation of Collective Databases; d. Creation of temporary or permanent reproductions by any means and in any form, in whole or in part, including of any Derivative Databases or as a part of Collective Databases; and e. Distribution, communication, display, lending, making available, or performance to the public by any means and in any form, in whole or in part, including of any Derivative Database or as a part of Collective Databases. 3.2 Compulsory license schemes. For the avoidance of doubt: a. Non-waivable compulsory license schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; b. Waivable compulsory license schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, c. Voluntary license schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. 3.3 The right to release the Database under different terms, or to stop distributing or making available the Database, is reserved. Note that this Database may be multiple-licensed, and so You may have the choice of using alternative licenses for this Database. Subject to Section 10.4, all other rights not expressly granted by Licensor are reserved. 4.0 Conditions of Use 4.1 The rights granted in Section 3 above are expressly made subject to Your complying with the following conditions of use. These are important conditions of this License, and if You fail to follow them, You will be in material breach of its terms. 4.2 Notices. If You Publicly Convey this Database, any Derivative Database, or the Database as part of a Collective Database, then You must: a. Do so only under the terms of this License or another license permitted under Section 4.4; b. Include a copy of this License (or, as applicable, a license permitted under Section 4.4) or its Uniform Resource Identifier (URI) with the Database or Derivative Database, including both in the Database or Derivative Database and in any relevant documentation; and c. Keep intact any copyright or Database Right notices and notices that refer to this License. d. If it is not possible to put the required notices in a particular file due to its structure, then You must include the notices in a location (such as a relevant directory) where users would be likely to look for it. 4.3 Notice for using output (Contents). Creating and Using a Produced Work does not require the notice in Section 4.2. However, if you Publicly Use a Produced Work, You must include a notice associated with the Produced Work reasonably calculated to make any Person that uses, views, accesses, interacts with, or is otherwise exposed to the Produced Work aware that Content was obtained from the Database, Derivative Database, or the Database as part of a Collective Database, and that it is available under this License. a. Example notice. The following text will satisfy notice under Section 4.3: Contains information from DATABASE NAME, which is made available here under the Open Database License (ODbL). DATABASE NAME should be replaced with the name of the Database and a hyperlink to the URI of the Database. “Open Database License” should contain a hyperlink to the URI of the text of this License. If hyperlinks are not possible, You should include the plain text of the required URI’s with the above notice. 4.4 Share alike. a. Any Derivative Database that You Publicly Use must be only under the terms of: i. This License; ii. A later version of this License similar in spirit to this License; or iii. A compatible license. If You license the Derivative Database under one of the licenses mentioned in (iii), You must comply with the terms of that license. b. For the avoidance of doubt, Extraction or Re-utilisation of the whole or a Substantial part of the Contents into a new database is a Derivative Database and must comply with Section 4.4. c. Derivative Databases and Produced Works. A Derivative Database is Publicly Used and so must comply with Section 4.4. if a Produced Work created from the Derivative Database is Publicly Used. d. Share Alike and additional Contents. For the avoidance of doubt, You must not add Contents to Derivative Databases under Section 4.4 a that are incompatible with the rights granted under this License. e. Compatible licenses. Licensors may authorise a proxy to determine compatible licenses under Section 4.4 a iii. If they do so, the authorised proxy’s public statement of acceptance of a compatible license grants You permission to use the compatible license. 4.5 Limits of Share Alike. The requirements of Section 4.4 do not apply in the following: a. For the avoidance of doubt, You are not required to license Collective Databases under this License if You incorporate this Database or a Derivative Database in the collection, but this License still applies to this Database or a Derivative Database as a part of the Collective Database; b. Using this Database, a Derivative Database, or this Database as part of a Collective Database to create a Produced Work does not create a Derivative Database for purposes of Section 4.4; and c. Use of a Derivative Database internally within an organisation is not to the public and therefore does not fall under the requirements of Section 4.4. 4.6 Access to Derivative Databases. If You Publicly Use a Derivative Database or a Produced Work from a Derivative Database, You must also offer to recipients of the Derivative Database or Produced Work a copy in a machine readable form of: a. The entire Derivative Database; or b. A file containing all of the alterations made to the Database or the method of making the alterations to the Database (such as an algorithm), including any additional Contents, that make up all the differences between the Database and the Derivative Database. The Derivative Database (under a.) or alteration file (under b.) must be available at no more than a reasonable production cost for physical distributions and free of charge if distributed over the internet. 4.7 Technological measures and additional terms a. This License does not allow You to impose (except subject to Section 4.7 b.) any terms or any technological measures on the Database, a Derivative Database, or the whole or a Substantial part of the Contents that alter or restrict the terms of this License, or any rights granted under it, or have the effect or intent of restricting the ability of any person to exercise those rights. b. Parallel distribution. You may impose terms or technological measures on the Database, a Derivative Database, or the whole or a Substantial part of the Contents (a “Restricted Database”) in contravention of Section 4.74 a. only if You also make a copy of the Database or a Derivative Database available to the recipient of the Restricted Database: i. That is available without additional fee; ii. That is available in a medium that does not alter or restrict the terms of this License, or any rights granted under it, or have the effect or intent of restricting the ability of any person to exercise those rights (an “Unrestricted Database”); and iii. The Unrestricted Database is at least as accessible to the recipient as a practical matter as the Restricted Database. c. For the avoidance of doubt, You may place this Database or a Derivative Database in an authenticated environment, behind a password, or within a similar access control scheme provided that You do not alter or restrict the terms of this License or any rights granted under it or have the effect or intent of restricting the ability of any person to exercise those rights. 4.8 Licensing of others. You may not sublicense the Database. Each time You communicate the Database, the whole or Substantial part of the Contents, or any Derivative Database to anyone else in any way, the Licensor offers to the recipient a license to the Database on the same terms and conditions as this License. You are not responsible for enforcing compliance by third parties with this License, but You may enforce any rights that You have over a Derivative Database. You are solely responsible for any modifications of a Derivative Database made by You or another Person at Your direction. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. 5.0 Moral rights 5.1 Moral rights. This section covers moral rights, including any rights to be identified as the author of the Database or to object to treatment that would otherwise prejudice the author’s honour and reputation, or any other derogatory treatment: a. For jurisdictions allowing waiver of moral rights, Licensor waives all moral rights that Licensor may have in the Database to the fullest extent possible by the law of the relevant jurisdiction under Section 10.4; b. If waiver of moral rights under Section 5.1 a in the relevant jurisdiction is not possible, Licensor agrees not to assert any moral rights over the Database and waives all claims in moral rights to the fullest extent possible by the law of the relevant jurisdiction under Section 10.4; and c. For jurisdictions not allowing waiver or an agreement not to assert moral rights under Section 5.1 a and b, the author may retain their moral rights over certain aspects of the Database. Please note that some jurisdictions do not allow for the waiver of moral rights, and so moral rights may still subsist over the Database in some jurisdictions. 6.0 Fair dealing, Database exceptions, and other rights not affected 6.1 This License does not affect any rights that You or anyone else may independently have under any applicable law to make any use of this Database, including without limitation: a. Exceptions to the Database Right including: Extraction of Contents from non-electronic Databases for private purposes, Extraction for purposes of illustration for teaching or scientific research, and Extraction or Re-utilisation for public security or an administrative or judicial procedure. b. Fair dealing, fair use, or any other legally recognised limitation or exception to infringement of copyright or other applicable laws. 6.2 This License does not affect any rights of lawful users to Extract and Re-utilise insubstantial parts of the Contents, evaluated quantitatively or qualitatively, for any purposes whatsoever, including creating a Derivative Database (subject to other rights over the Contents, see Section 2.4). The repeated and systematic Extraction or Re-utilisation of insubstantial parts of the Contents may however amount to the Extraction or Re-utilisation of a Substantial part of the Contents. 7.0 Warranties and Disclaimer 7.1 The Database is licensed by the Licensor “as is” and without any warranty of any kind, either express, implied, or arising by statute, custom, course of dealing, or trade usage. Licensor specifically disclaims any and all implied warranties or conditions of title, non-infringement, accuracy or completeness, the presence or absence of errors, fitness for a particular purpose, merchantability, or otherwise. Some jurisdictions do not allow the exclusion of implied warranties, so this exclusion may not apply to You. 8.0 Limitation of liability 8.1 Subject to any liability that may not be excluded or limited by law, the Licensor is not liable for, and expressly excludes, all liability for loss or damage however and whenever caused to anyone by any use under this License, whether by You or by anyone else, and whether caused by any fault on the part of the Licensor or not. This exclusion of liability includes, but is not limited to, any special, incidental, consequential, punitive, or exemplary damages such as loss of revenue, data, anticipated profits, and lost business. This exclusion applies even if the Licensor has been advised of the possibility of such damages. 8.2 If liability may not be excluded by law, it is limited to actual and direct financial loss to the extent it is caused by proved negligence on the part of the Licensor. 9.0 Termination of Your rights under this License 9.1 Any breach by You of the terms and conditions of this License automatically terminates this License with immediate effect and without notice to You. For the avoidance of doubt, Persons who have received the Database, the whole or a Substantial part of the Contents, Derivative Databases, or the Database as part of a Collective Database from You under this License will not have their licenses terminated provided their use is in full compliance with this License or a license granted under Section 4.8 of this License. Sections 1, 2, 7, 8, 9 and 10 will survive any termination of this License. 9.2 If You are not in breach of the terms of this License, the Licensor will not terminate Your rights under it. 9.3 Unless terminated under Section 9.1, this License is granted to You for the duration of applicable rights in the Database. 9.4 Reinstatement of rights. If you cease any breach of the terms and conditions of this License, then your full rights under this License will be reinstated: a. Provisionally and subject to permanent termination until the 60th day after cessation of breach; b. Permanently on the 60th day after cessation of breach unless otherwise reasonably notified by the Licensor; or c. Permanently if reasonably notified by the Licensor of the violation, this is the first time You have received notice of violation of this License from the Licensor, and You cure the violation prior to 30 days after your receipt of the notice. Persons subject to permanent termination of rights are not eligible to be a recipient and receive a license under Section 4.8. 9.5 Notwithstanding the above, Licensor reserves the right to release the Database under different license terms or to stop distributing or making available the Database. Releasing the Database under different license terms or stopping the distribution of the Database will not withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 10.0 General 10.1 If any provision of this License is held to be invalid or unenforceable, that must not affect the validity or enforceability of the remainder of the terms and conditions of this License and each remaining provision of this License shall be valid and enforced to the fullest extent permitted by law. 10.2 This License is the entire agreement between the parties with respect to the rights granted here over the Database. It replaces any earlier understandings, agreements or representations with respect to the Database. 10.3 If You are in breach of the terms of this License, You will not be entitled to rely on the terms of this License or to complain of any breach by the Licensor. 10.4 Choice of law. This License takes effect in and will be governed by the laws of the relevant jurisdiction in which the License terms are sought to be enforced. If the standard suite of rights granted under applicable copyright law and Database Rights in the relevant jurisdiction includes additional rights not granted under this License, these additional rights are granted in this License in order to meet the terms of this License. foldynl-QLog-3252ff9/QLog.pro000066400000000000000000000476541517334601000157670ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2019-06-10T09:13:09 # #------------------------------------------------- QT += core gui sql network xml charts webenginewidgets serialport dbus quickwidgets webchannel websockets printsupport greaterThan(QT_MAJOR_VERSION, 5): QT += widgets TARGET = qlog TEMPLATE = app VERSION = 0.50.0 DEFINES += VERSION=\\\"$$VERSION\\\" # Define paths to HAMLIB. Leave empty if system libraries should be used #HAMLIBINCLUDEPATH = #HAMLIBLIBPATH = # Define Hamlib version. Leave empty if pkg-config should detect the version (lib must be installed and registered) #HAMLIBVERSION_MAJOR = #HAMLIBVERSION_MINOR = #HAMLIBVERSION_PATCH = # Define paths to pthread - needed for Hamlib4.5 and later. Leave empty if system libraries should be used #PTHREADINCLUDEPATH = #PTHREADLIBPATH = # Define paths to QTKeyChain. Leave empty if system libraries should be used #QTKEYCHAININCLUDEPATH = #QTKEYCHAINLIBPATH = # Define paths to zlib - Leave empty if system libraries should be used #ZLIBINCLUDEPATH = #ZLIBLIBPATH = # Define paths to OpenSSL - Leave empty if system libraries should be used #OPENSSLINCLUDEPATH = #OPENSSLLIBPATH = # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS QT_MESSAGELOGCONTEXT # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 macx:QT_CONFIG -= no-pkg-config CONFIG += c++11 force_debug_info #CONFIG += sanitizer sanitize_address CONFIG *= link_pkgconfig SOURCES += \ awards/AwardDefinition.cpp \ awards/AwardDXCC.cpp \ awards/AwardGridsquare.cpp \ awards/AwardIOTA.cpp \ awards/AwardITU.cpp \ awards/AwardJapan.cpp \ awards/AwardNZ.cpp \ awards/AwardRDA.cpp \ awards/AwardSpanishDME.cpp \ awards/AwardUKD.cpp \ awards/AwardUSCounty.cpp \ awards/AwardPOTAActivator.cpp \ awards/AwardPOTAHunter.cpp \ awards/AwardSOTA.cpp \ awards/SecondarySubdivisionAward.cpp \ awards/AwardWAC.cpp \ awards/AwardWAS.cpp \ awards/AwardWAZ.cpp \ awards/AwardWPX.cpp \ awards/AwardWWFF.cpp \ awards/BandTableAward.cpp \ core/AlertEvaluator.cpp \ core/AppGuard.cpp \ core/CallbookManager.cpp \ core/CredentialStore.cpp \ core/FileCompressor.cpp \ core/FldigiTCPServer.cpp \ core/LOVDownloader.cpp \ core/LogDatabase.cpp \ core/LogLocale.cpp \ core/LogParam.cpp \ core/MembershipQE.cpp \ core/Migration.cpp \ core/NetworkNotification.cpp \ core/PasswordCipher.cpp \ core/PlatformParameterManager.cpp \ core/PotaQE.cpp \ core/PropConditions.cpp \ core/QSLPrintLabelRenderer.cpp \ core/QSLStorage.cpp \ core/QSOFilterManager.cpp \ core/WsjtxUDPReceiver.cpp \ core/debug.cpp \ core/EmergencyFrequency.cpp \ core/main.cpp \ core/zonedetect.c \ cwkey/CWKeyer.cpp \ cwkey/drivers/CWCatKey.cpp \ cwkey/drivers/CWDaemonKey.cpp \ cwkey/drivers/CWDummyKey.cpp \ cwkey/drivers/CWFldigiKey.cpp \ cwkey/drivers/CWKey.cpp \ cwkey/drivers/CWWinKey.cpp \ data/ActivityProfile.cpp \ data/AntProfile.cpp \ data/BandPlan.cpp \ data/Accents.cpp \ data/CWKeyProfile.cpp \ data/CWShortcutProfile.cpp \ data/Callsign.cpp \ data/Data.cpp \ data/DxServerString.cpp \ data/Gridsquare.cpp \ data/HostsPortString.cpp \ data/MainLayoutProfile.cpp \ data/RigProfile.cpp \ data/RotProfile.cpp \ data/RotUsrButtonsProfile.cpp \ data/SerialPort.cpp \ data/StationProfile.cpp \ data/UpdatableSQLRecord.cpp \ logformat/AdiFormat.cpp \ logformat/AdxFormat.cpp \ logformat/CabrilloFormat.cpp \ logformat/CSVFormat.cpp \ logformat/JsonFormat.cpp \ logformat/LogFormat.cpp \ logformat/PotaAdiFormat.cpp \ models/AlertTableModel.cpp \ models/AwardsTableModel.cpp \ models/DxccTableModel.cpp \ models/LogbookModel.cpp \ models/RigTypeModel.cpp \ models/RotTypeModel.cpp \ models/SearchFilterProxyModel.cpp \ models/ShortcutEditorModel.cpp \ models/SqlListModel.cpp \ models/WsjtxTableModel.cpp \ rig/Rig.cpp \ rig/RigCaps.cpp \ rig/RigctldManager.cpp \ rig/drivers/FlrigRigDrv.cpp \ rig/drivers/GenericRigDrv.cpp \ rig/drivers/HamlibRigDrv.cpp \ rig/drivers/TCIRigDrv.cpp \ rotator/RotCaps.cpp \ rotator/Rotator.cpp \ rotator/drivers/GenericRotDrv.cpp \ rotator/drivers/HamlibRotDrv.cpp \ rotator/drivers/PSTRotDrv.cpp \ service/GenericCallbook.cpp \ service/GenericQSLDownloader.cpp \ service/GenericQSOUploader.cpp \ service/cloudlog/Cloudlog.cpp \ service/clublog/ClubLog.cpp \ service/eqsl/Eqsl.cpp \ service/hamqth/HamQTH.cpp \ service/hrdlog/HRDLog.cpp \ service/kstchat/KSTChat.cpp \ service/lotw/Lotw.cpp \ service/potaapp/PotaApp.cpp \ service/qrzcom/QRZ.cpp \ ui/ActivityEditor.cpp \ ui/AlertRuleDetail.cpp \ ui/AlertSettingDialog.cpp \ ui/AlertWidget.cpp \ ui/AwardsDialog.cpp \ ui/DXCCSubmissionDialog.cpp \ ui/BandmapWidget.cpp \ ui/CWConsoleWidget.cpp \ ui/ChatWidget.cpp \ ui/ClockWidget.cpp \ ui/ColumnSettingDialog.cpp \ ui/DevToolsDialog.cpp \ ui/DownloadQSLDialog.cpp \ ui/DxFilterDialog.cpp \ ui/DxWidget.cpp \ ui/DxccTableWidget.cpp \ ui/EditActivitiesDialog.cpp \ ui/CabrilloExportDialog.cpp \ ui/CabrilloTemplateDialog.cpp \ ui/ExportDialog.cpp \ ui/ExportPasswordDialog.cpp \ ui/LoadDatabaseDialog.cpp \ ui/PlatformSettingsDialog.cpp \ ui/QSLGalleryDialog.cpp \ ui/QSLPrintLabelDialog.cpp \ ui/RigctldAdvancedDialog.cpp \ ui/ImportDialog.cpp \ ui/InputPasswordDialog.cpp \ ui/KSTChatWidget.cpp \ ui/KSTHighlightRuleDetail.cpp \ ui/KSTHighlighterSettingDialog.cpp \ ui/LogbookWidget.cpp \ ui/MainWindow.cpp \ ui/MapWebChannelHandler.cpp \ ui/MapWidget.cpp \ ui/ModeSelectionController.cpp \ ui/NewContactWidget.cpp \ ui/OnlineMapWidget.cpp \ ui/PaperQSLDialog.cpp \ ui/ProfileImageWidget.cpp \ ui/QSLImportStatDialog.cpp \ ui/QSODetailDialog.cpp \ ui/QSOFilterDetail.cpp \ ui/QSOFilterDialog.cpp \ ui/QTableQSOView.cpp \ ui/RigWidget.cpp \ ui/RotatorWidget.cpp \ ui/SettingsDialog.cpp \ ui/ShowUploadDialog.cpp \ ui/StatisticsWidget.cpp \ ui/UploadQSODialog.cpp \ ui/WebEnginePage.cpp \ ui/WsjtxFilterDialog.cpp \ ui/WsjtxWidget.cpp \ ui/component/BaseDoubleSpinBox.cpp \ ui/component/EditLine.cpp \ ui/component/FreqQSpinBox.cpp \ ui/component/MultiselectCompleter.cpp \ ui/component/RepeatButton.cpp \ ui/component/SmartSearchBox.cpp \ ui/component/SqlHighlighter.cpp \ ui/component/SwitchButton.cpp HEADERS += \ awards/AwardDefinition.h \ awards/AwardDXCC.h \ awards/AwardGridsquare.h \ awards/AwardIOTA.h \ awards/AwardITU.h \ awards/AwardJapan.h \ awards/AwardNZ.h \ awards/AwardRDA.h \ awards/AwardSpanishDME.h \ awards/AwardUKD.h \ awards/AwardUSCounty.h \ awards/AwardPOTAActivator.h \ awards/AwardPOTAHunter.h \ awards/AwardSOTA.h \ awards/SecondarySubdivisionAward.h \ awards/AwardWAC.h \ awards/AwardWAS.h \ awards/AwardWAZ.h \ awards/AwardWPX.h \ awards/AwardWWFF.h \ awards/BandTableAward.h \ core/AlertEvaluator.h \ core/AppGuard.h \ core/CallbookManager.h \ core/CredentialStore.h \ core/FileCompressor.h \ core/FldigiTCPServer.h \ core/LOVDownloader.h \ core/LogDatabase.h \ core/LogLocale.h \ core/LogParam.h \ core/MembershipQE.h \ core/Migration.h \ core/NetworkNotification.h \ core/PasswordCipher.h \ core/PlatformParameterManager.h \ core/PotaQE.h \ core/PropConditions.h \ core/QSLPrintLabelRenderer.h \ core/QSLStorage.h \ core/QSOFilterManager.h \ core/QuadKeyCache.h \ core/WsjtxUDPReceiver.h \ core/csv.hpp \ core/debug.h \ core/EmergencyFrequency.h \ core/zonedetect.h \ cwkey/CWKeyer.h \ cwkey/drivers/CWCatKey.h \ cwkey/drivers/CWDaemonKey.h \ cwkey/drivers/CWDummyKey.h \ cwkey/drivers/CWFldigiKey.h \ cwkey/drivers/CWKey.h \ cwkey/drivers/CWWinKey.h \ data/ActivityProfile.h \ data/AntProfile.h \ data/Band.h \ data/BandPlan.h \ data/CWKeyProfile.h \ data/CWShortcutProfile.h \ data/Callsign.h \ data/Data.h \ data/DxServerString.h \ data/DxSpot.h \ data/Dxcc.h \ data/Gridsquare.h \ data/HostsPortString.h \ data/MainLayoutProfile.h \ data/POTAEntity.h \ data/POTASpot.h \ data/ProfileManager.h \ data/RigProfile.h \ data/RotProfile.h \ data/RotUsrButtonsProfile.h \ data/SOTAEntity.h \ data/SerialPort.h \ data/SpotAlert.h \ data/StationProfile.h \ data/ToAllSpot.h \ data/UpdatableSQLRecord.h \ data/WCYSpot.h \ data/WWFFEntity.h \ data/WWVSpot.h \ data/WsjtxDecode.h \ data/WsjtxEntry.h \ data/WsjtxLog.h \ data/WsjtxLogADIF.h \ data/WsjtxStatus.h \ logformat/AdiFormat.h \ logformat/AdxFormat.h \ logformat/CabrilloFormat.h \ logformat/CSVFormat.h \ logformat/JsonFormat.h \ logformat/LogFormat.h \ logformat/PotaAdiFormat.h \ models/AlertTableModel.h \ models/AwardsTableModel.h \ models/DxccTableModel.h \ models/LogbookModel.h \ models/RigTypeModel.h \ models/RotTypeModel.h \ models/SearchFilterProxyModel.h \ models/ShortcutEditorModel.h \ models/SqlListModel.h \ models/WsjtxTableModel.h \ rig/Rig.h \ rig/RigCaps.h \ rig/RigctldManager.h \ rig/drivers/FlrigRigDrv.h \ rig/drivers/GenericRigDrv.h \ rig/drivers/HamlibRigDrv.h \ rig/drivers/TCIRigDrv.h \ rig/macros.h \ rotator/RotCaps.h \ rotator/Rotator.h \ rotator/drivers/GenericRotDrv.h \ rotator/drivers/HamlibRotDrv.h \ rotator/drivers/PSTRotDrv.h \ service/GenericCallbook.h \ service/GenericQSLDownloader.h \ service/GenericQSOUploader.h \ service/cloudlog/Cloudlog.h \ service/clublog/ClubLog.h \ service/eqsl/Eqsl.h \ service/hamqth/HamQTH.h \ service/hrdlog/HRDLog.h \ service/kstchat/KSTChat.h \ service/lotw/Lotw.h \ service/potaapp/PotaApp.h \ service/qrzcom/QRZ.h \ ui/ActivityEditor.h \ ui/AlertRuleDetail.h \ ui/AlertSettingDialog.h \ ui/AlertWidget.h \ ui/AwardsDialog.h \ ui/DXCCSubmissionDialog.h \ ui/BandmapWidget.h \ ui/CWConsoleWidget.h \ ui/ChatWidget.h \ ui/ClockWidget.h \ ui/ColumnSettingDialog.h \ ui/DevToolsDialog.h \ ui/DownloadQSLDialog.h \ ui/DxFilterDialog.h \ ui/DxWidget.h \ ui/DxccTableWidget.h \ ui/EditActivitiesDialog.h \ ui/CabrilloExportDialog.h \ ui/CabrilloTemplateDialog.h \ ui/ExportDialog.h \ ui/ExportPasswordDialog.h \ ui/LoadDatabaseDialog.h \ ui/PlatformSettingsDialog.h \ ui/QSLGalleryDialog.h \ ui/QSLPrintLabelDialog.h \ ui/RigctldAdvancedDialog.h \ ui/ImportDialog.h \ ui/InputPasswordDialog.h \ ui/KSTChatWidget.h \ ui/KSTHighlightRuleDetail.h \ ui/KSTHighlighterSettingDialog.h \ ui/LogbookWidget.h \ ui/MainWindow.h \ ui/MapWebChannelHandler.h \ ui/MapWidget.h \ ui/ModeSelectionController.h \ ui/NewContactWidget.h \ ui/OnlineMapWidget.h \ ui/PaperQSLDialog.h \ ui/ProfileImageWidget.h \ ui/QSLImportStatDialog.h \ ui/QSODetailDialog.h \ ui/QSOFilterDetail.h \ ui/QSOFilterDialog.h \ ui/QTableQSOView.h \ ui/ShowUploadDialog.h \ ui/SplashScreen.h \ ui/RigWidget.h \ ui/RotatorWidget.h \ ui/SettingsDialog.h \ ui/StatisticsWidget.h \ ui/UploadQSODialog.h \ ui/WebEnginePage.h \ ui/WsjtxFilterDialog.h \ ui/WsjtxWidget.h \ i18n/dbstrings.tri \ i18n/datastrings.tri \ ui/component/BaseDoubleSpinBox.h \ ui/component/ButtonStyle.h \ ui/component/EditLine.h \ ui/component/FreqQSpinBox.h \ ui/component/MultiselectCompleter.h \ ui/component/RepeatButton.h \ ui/component/ShutdownAwareWidget.h \ ui/component/SmartSearchBox.h \ ui/component/SqlHighlighter.h \ ui/component/StyleItemDelegate.h \ ui/component/SwitchButton.h FORMS += \ ui/ActivityEditor.ui \ ui/AlertRuleDetail.ui \ ui/AlertSettingDialog.ui \ ui/AlertWidget.ui \ ui/AwardsDialog.ui \ ui/DXCCSubmissionDialog.ui \ ui/BandmapWidget.ui \ ui/CWConsoleWidget.ui \ ui/ChatWidget.ui \ ui/ClockWidget.ui \ ui/ColumnSettingDialog.ui \ ui/ColumnSettingSimpleDialog.ui \ ui/DevToolsDialog.ui \ ui/DownloadQSLDialog.ui \ ui/DxFilterDialog.ui \ ui/DxWidget.ui \ ui/EditActivitiesDialog.ui \ ui/CabrilloExportDialog.ui \ ui/CabrilloTemplateDialog.ui \ ui/ExportDialog.ui \ ui/ExportPasswordDialog.ui \ ui/LoadDatabaseDialog.ui \ ui/PlatformSettingsDialog.ui \ ui/QSLGalleryDialog.ui \ ui/QSLPrintLabelDialog.ui \ ui/RigctldAdvancedDialog.ui \ ui/ImportDialog.ui \ ui/InputPasswordDialog.ui \ ui/KSTChatWidget.ui \ ui/KSTHighlightRuleDetail.ui \ ui/KSTHighlighterSettingDialog.ui \ ui/LogbookWidget.ui \ ui/MainWindow.ui \ ui/NewContactWidget.ui \ ui/PaperQSLDialog.ui \ ui/ProfileImageWidget.ui \ ui/QSLImportStatDialog.ui \ ui/QSODetailDialog.ui \ ui/QSOFilterDetail.ui \ ui/QSOFilterDialog.ui \ ui/RigWidget.ui \ ui/RotatorWidget.ui \ ui/SettingsDialog.ui \ ui/ShowUploadDialog.ui \ ui/StatisticsWidget.ui \ ui/UploadQSODialog.ui \ ui/WsjtxFilterDialog.ui \ ui/WsjtxWidget.ui RESOURCES += \ i18n/i18n.qrc \ res/flags/flags.qrc \ res/icons/icons.qrc \ res/res.qrc OTHER_FILES += \ res/stylesheet.css \ res/qlog.rc \ res/qlog.desktop \ res/qlog.1 \ res/io.github.foldynl.QLog.metainfo.xml TRANSLATIONS = i18n/qlog_cs.ts \ i18n/qlog_de.ts \ i18n/qlog_es.ts \ i18n/qlog_fr.ts \ i18n/qlog_it.ts \ i18n/qlog_zh_CN.ts RC_ICONS = res/qlog.ico ICON = res/qlog.icns # https://stackoverflow.com/questions/56734224/qmake-and-pkg-config?rq=1 defineReplace(findPackage) { pkg = $${1}Version !defined($$pkg, var) { $$pkg = $$system($$pkgConfigExecutable() --modversion $$1) isEmpty($$pkg): $$pkg = 0 cache($$pkg, stash) } return($$eval($$pkg)) } defineReplace(removeNonDigi) { output = $$1 output = $$replace(output, [^0-9], " ") output = $$split(output, " ") return($$member(output, 0)) } isEmpty(HAMLIBVERSION_MAJOR) { HAMLIBVERSIONSTRING = $$findPackage(hamlib) HAMLIBVERSIONS = $$split(HAMLIBVERSIONSTRING, ".") HAMLIBVERSION_MAJOR = $$member(HAMLIBVERSIONS, 0) HAMLIBVERSION_MINOR = $$member(HAMLIBVERSIONS, 1) HAMLIBVERSION_PATCH = $$member(HAMLIBVERSIONS, 2) } HAMLIBVERSION_MINOR = $$removeNonDigi($$HAMLIBVERSION_MINOR) isEmpty(HAMLIBVERSION_MINOR){ HAMLIBVERSION_MINOR=0 } HAMLIBVERSION_PATCH = $$removeNonDigi($$HAMLIBVERSION_PATCH) isEmpty(HAMLIBVERSION_PATCH){ HAMLIBVERSION_PATCH=0 } !isEmpty(HAMLIBINCLUDEPATH) { INCLUDEPATH += $$HAMLIBINCLUDEPATH } !isEmpty(QTKEYCHAININCLUDEPATH) { INCLUDEPATH += $$QTKEYCHAININCLUDEPATH } !isEmpty(PTHREADINCLUDEPATH) { INCLUDEPATH += $$PTHREADINCLUDEPATH } !isEmpty(ZLIBINCLUDEPATH) { INCLUDEPATH += $$ZLIBINCLUDEPATH } !isEmpty(OPENSSLINCLUDEPATH) { INCLUDEPATH += $$OPENSSLINCLUDEPATH } !isEmpty(HAMLIBLIBPATH) { LIBS += -L$$HAMLIBLIBPATH } !isEmpty(QTKEYCHAINLIBPATH) { LIBS += -L$$QTKEYCHAINLIBPATH } !isEmpty(PTHREADINCLUDEPATH) { LIBS += -L$$PTHREADINCLUDEPATH } !isEmpty(ZLIBLIBPATH) { LIBS += -L$$ZLIBLIBPATH } !isEmpty(OPENSSLLIBPATH) { LIBS += -L$$OPENSSLLIBPATH } unix:!macx { isEmpty(PREFIX) { PREFIX = /usr/local } target.path = $$PREFIX/bin desktop.path = $$PREFIX/share/applications/ desktop.files += res/$${TARGET}.desktop manpage.path = $$PREFIX/share/man/man1 manpage.files += res/$${TARGET}.1 icon.path = $$PREFIX/share/icons/hicolor/256x256/apps icon.files += res/$${TARGET}.png metainfo.path = $$PREFIX/share/metainfo/ metainfo.files += res/io.github.foldynl.QLog.metainfo.xml INSTALLS += target desktop icon metainfo manpage INCLUDEPATH += /usr/local/include PKGCONFIG += openssl LIBS += -L/usr/local/lib -lhamlib -lsqlite3 -lz equals(QT_MAJOR_VERSION, 6): LIBS += -lqt6keychain equals(QT_MAJOR_VERSION, 5): LIBS += -lqt5keychain } macx: { # This allows the app to be shipped in a non-bundeled version !isEmpty(PREFIX) { target.path = $$PREFIX INSTALLS += target } INCLUDEPATH += /usr/local/include /opt/homebrew/include /opt/local/include LIBS += -L/usr/local/lib -L/opt/homebrew/lib -lhamlib -lsqlite3 -lz -L/opt/local/lib -lssl -lcrypto equals(QT_MAJOR_VERSION, 6): LIBS += -lqt6keychain equals(QT_MAJOR_VERSION, 5): LIBS += -lqt5keychain DISTFILES += } win32: { INCLUDEPATH += \ /usr/local/include \ $$[QT_INSTALL_PREFIX]/../Src/qtbase/src/3rdparty/sqlite/ SOURCES += \ rig/drivers/OmnirigRigDrv.cpp \ rig/drivers/Omnirigv2RigDrv.cpp \ $$[QT_INSTALL_PREFIX]/../Src/qtbase/src/3rdparty/sqlite/sqlite3.c HEADERS += \ rig/drivers/OmnirigRigDrv.h \ rig/drivers/Omnirigv2RigDrv.h \ rig/drivers/OmniRigEventSink.h \ $$[QT_INSTALL_PREFIX]/../Src/qtbase/src/3rdparty/sqlite/sqlite3.h TARGET = qlog QMAKE_TARGET_COMPANY = OK1MLG QMAKE_TARGET_DESCRIPTION = Hamradio logging LIBS += -lws2_32 -llibhamlib-4 -lzlib -llibssl -llibcrypto equals(QT_MAJOR_VERSION, 6): LIBS += -lqt6keychain equals(QT_MAJOR_VERSION, 5): LIBS += -lqt5keychain DEFINES += WIN32_LEAN_AND_MEAN DEFINES += ZD_EXPORT= } DEFINES += HAMLIBVERSION_MAJOR=$$HAMLIBVERSION_MAJOR DEFINES += HAMLIBVERSION_MINOR=$$HAMLIBVERSION_MINOR DEFINES += HAMLIBVERSION_PATCH=$$HAMLIBVERSION_PATCH DISTFILES += \ Changelog \ i18n/dbstrings.tri \ res/data/sat_modes foldynl-QLog-3252ff9/README.md000066400000000000000000000304041517334601000156430ustar00rootroot00000000000000# QLog QLog is an Amateur Radio logging application for Linux, Windows. It is based on the Qt framework and uses SQLite as database backend. QLogs aims to be as simple as possible, but to provide everything the operator expects from the log to be. This log is not currently focused on contests. ![Screenshot](https://foldynl.github.io/QLog/screens/qlog_main.png) ## Features - Customizable GUI - Rig control via Hamlib, Omnirig v1 (Windows only), Omnirig v2 (Windows only), TCI, FLRig - Rotator control via Hamlib, PSTRotator - HamQTH and QRZ.com callbook integration - DX cluster integration - **LoTW**, **eQSL**, **QRZ.com**, **Clublog**, **HRDLog.net**, **ON4KST Chat**, **Cloudlog/Wavelog** integration (**eQSL includes QSL pictures download**) - **Secure Password Storage** for all services with password or security token - **Online** and **Offline** map - Club Member lookup - CW Keyer Support - CWDaemon, FLDigi (all supported modes), Morse Over CAT, WinKey v1 or v2 - Bandmap - CW Console - WSJT-X integration - Station Location Profile support - Various station statistics - Basic Awards support - Basic Contest support - Custom QSO Filters - **NO** ads, **NO** user tracking, **NO** hidden telemetry - simply free and open-source - SQLite backend. ### Supported OS * Linux * Windows 10/11 (64bit) * MacOS (experimental - only for developers) ### Supported Rigs * all supported by [Hamlib](https://hamlib.github.io/) * all supported by [Omnirig v1](https://www.dxatlas.com/omnirig/) (Windows only) * all supported by [Omnirig v2](https://www.hb9ryz.ch/omnirig/) (Windows only) * all supported by [TCI](https://eesdr.com/en/software-en/software-en) * all supported by [FLRig](http://www.w1hkj.com/flrig-help/supported_transceivers.html) ### Supported Rotators * all supported by [Hamlib](https://hamlib.github.io/) ### Supported Keyers * [CWDaemon](https://cwdaemon.sourceforge.net/) * [FLDigi](http://www.w1hkj.com/) * Morse Over CAT * WinKey v1 or v2 compatible hardware ### Supported Secure Password Storage * Linux: LibSecretKeyring, GnomeKeyring, Kwallet4, Kwallet5 * Windows: Windows Credential Store * MacOS: macOS Keychain ### Third-party software * [TQSL](http://www.arrl.org/tqsl-download) – optional, needed for LoTW support For more details, screenshots etc, please, see [QLog Wiki](https://github.com/foldynl/QLog/wiki) Please, used [QLog Issues](https://github.com/foldynl/QLog/issues) for reporting any issue or open a [discussion](https://github.com/foldynl/QLog/discussions). You can also use [QLog mailing list](https://groups.io/g/qlog) ## Installation ### Minimum Hardware Requirements - The recommended graphical resolution: 1920x1080 - CPU and memory: minimum requirements the same as for your OS - Graphic Card with OpenGL support - Serial connection if radio control is used ### Linux Prerequisites: - Installed Trusted QSL (Optional) - `sudo apt install trustedqsl` or from [ARRL](http://www.arrl.org/tqsl-download) **DEB packages** for currently supported Ubuntu versions are available for amd64, arm64 platforms via [Ubuntu PPA](https://launchpad.net/~foldyna/+archive/ubuntu/qlog). Ubuntu users can use following commands: `sudo add-apt-repository ppa:foldyna/qlog` `sudo apt update` `sudo apt install qlog` Fedora **RPM packages** are available via GitHub [Releases](https://github.com/foldynl/QLog/releases/latest) Download on Flathub **Flatpak** package is available via [Flathub](https://flathub.org/apps/io.github.foldynl.QLog). The package contains built-in TrustedQSL. The above packages are maintained by the application maintainer. However, there are many other unofficial packages available for other distributions — see the Unofficial Repositories on [QLog Wiki](https://github.com/foldynl/QLog/wiki). ### Windows Prerequisites: - Installed [Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-supported-redistributable-version) - Installed [Trusted QSL](http://www.arrl.org/tqsl-download) (Optional) - Installed [Omnirig v1](https://www.dxatlas.com/omnirig/) (Optional) - Installed [Omnirig v2](https://www.hb9ryz.ch/omnirig/) (Optional) Installation package is available via GitHub [Releases](https://github.com/foldynl/QLog/releases) . ### MacOS MacOS DMG: https://github.com/aa5sh/QLog/releases ## Disclaimer Regarding Forks and Clones This project is released as open source and may be forked or modified in accordance with its license. If you are using a fork, clone, or any modified version of this project that is not maintained in this official repository, please note: - We do **not** provide support for any forks, clones, or modified versions of this project. - This includes support requests related to "core features" as changes introduced in forks may directly or indirectly affect their behavior. - Any issues, bug reports, or feature requests concerning a forked or modified version must be directed to the maintainer of that specific repository. Support is provided exclusively for the original, unmodified version of the project distributed from this official source. By using a fork or modified version, you acknowledge that compatibility, stability, and functionality may differ from the original project, and responsibility for such differences lies solely with the maintainer of that fork. ## Compilation ### General Prerequisites - Installed Qt - Installed [qtkeychain-devel](https://github.com/frankosterfeld/qtkeychain) library and headers - Installed [OpenSSL-devel](https://wiki.openssl.org/index.php/Binaries) libraries and headers - Installed [HamLib-devel](https://github.com/Hamlib/Hamlib/releases/latest) libraries and headers `qmake` supports listed input parameters that affect the compilation process. - `HAMLIBINCLUDEPATH` - the path to Hamlib Includes - `HAMLIBLIBPATH` - the path to Hamlib Library - `HAMLIBVERSION_MAJOR` - Hamlib version - major number (must be present if `pkg-config` cannot determine Hamlib version) - `HAMLIBVERSION_MINOR` - Hamlib version - minor number (must be present if `pkg-config` cannot determine Hamlib version) - `HAMLIBVERSION_PATCH` - Hamlib version - patch number (must be present if `pkg-config` cannot determine Hamlib version) - `PTHREADINCLUDEPATH` - the path to pthread Includes - needed for Windows Hamlib 4.5 and later. Leave empty if system libraries should be used. - `PTHREADLIBPATH` - the path to pthread Library - needed for Windows Hamlib 4.5 and later. Leave empty if system libraries should be used. - `QTKEYCHAININCLUDEPATH` - the path to QtKeyChain Includes - `QTKEYCHAINLIBPATH`- the path to QtKeyChain Library - `ZLIBINCLUDEPATH` - the path to ZLIB Includes - `ZLIBLIBPATH` - the path to ZLIB Library Leave variables empty if system libraries and Hamlib version autodetect (calling `pkg-config`) should be used during compilation (for Windows, the parameter must be present) An example of use: ` C:/Qt/6.4.1/msvc2019_64/bin/qmake.exe C:\Users\devel\development\QLog\QLog.pro -spec win32-msvc "CONFIG+=qtquickcompiler" "HAMLIBINCLUDEPATH = C:\Users\devel\development\hamlib\include" "HAMLIBLIBPATH = C:\Users\devel\development\hamlib\lib\gcc" "HAMLIBVERSION_MAJOR = 4" "HAMLIBVERSION_MINOR = 5" "HAMLIBVERSION_PATCH = 0" "QTKEYCHAININCLUDEPATH = C:\Users\devel\development\qtkeychain_build\include" "QTKEYCHAINLIBPATH = C:\Users\devel\development\qtkeychain_build\lib" && C:/Qt/Tools/QtCreator/bin/jom/jom.exe qmake_all ` ### Windows Prerequisites - [Visual Studio 2022](https://visualstudio.microsoft.com/vs/community/) - QT with source codes (6.x, Qt Webengine, OpenSSL Toolkit) - [Omnirig v1](https://www.dxatlas.com/omnirig/) - [Omnirig v2](https://www.hb9ryz.ch/omnirig/) - [Hamlib](https://github.com/Hamlib/Hamlib/releases) - hamlib-w64-4.5.5.exe is the latest - Need to run the following commands to "fix" the library *** Fix Paths if necessary *** CD "C:\Program Files\hamlib-w64-4.5.5\lib\msvc" "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\bin\Hostx64\x64\link.exe" /lib /machine:X64 /def:libhamlib-4.def copy libhamlib-4.lib hamlib.lib - Install C++ Module - https://learn.microsoft.com/en-us/vcpkg/get_started/get-started-vscode?pivots=shell-powershell cd C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg vcpkg install pthreads vcpkg install qtkeychain-qt6 System Environmental Path Settings C:\Program Files\hamlib-w64-4.5.5\bin C:\QTTools\vcpkg\packages\qtkeychain-qt6_x64-windows\bin Clone QLog Master Branch In QT Creator Projects->Desktop Qt 6.8.0 MSVC2022 64Bit->Build Steps->Additional Arguments **** You need to update the paths accordingly **** **** Need to be on same line seperated by spaces **** "HAMLIBINCLUDEPATH='C:\Program Files\hamlib-w64-4.5.5\include'" "HAMLIBLIBPATH='C:\Program Files\hamlib-w64-4.5.5\lib\msvc'" "HAMLIBVERSION_MAJOR=4" "HAMLIBVERSION_MINOR=5" "HAMLIBVERSION_PATCH=5" "QTKEYCHAININCLUDEPATH=C:\QTTools\vcpkg\packages\qtkeychain-qt6_x64-windows\include" "QTKEYCHAINLIBPATH=C:\QTTools\vcpkg\packages\qtkeychain-qt6_x64-windows\lib" "PTHREADLIBPATH=C:\QTTools\vcpkg\packages\pthreads_x64-windows\lib" "PTHREADINCLUDEPATH=C:\QTTools\vcpkg\packages\pthreads_x64-windows\include" ### Linux for Debian: `sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libsqlite3-dev libhamlib++-dev libqt5charts5-dev qttools5-dev-tools libqt5keychain1 qt5keychain-dev qtwebengine5-dev build-essential libqt5serialport5-dev pkg-config libqt5websockets5-dev libssl-dev` for Debian (QT6): `sudo apt-get -y install libhamlib-dev build-essential pkg-config qt6-base-dev qtkeychain-qt6-dev qt6-webengine-dev libqt6charts6-dev libqt6serialport6 libqt6webenginecore6-bin libqt6svg6-dev libgl-dev libqt6websockets6-dev qt6-serialport-dev libsqlite3-dev libssl-dev` for Fedora: `dnf install qt5-qtbase-devel qt5-qtwebengine-devel qt5-qtcharts-devel hamlib-devel qtkeychain-qt5-devel qt5-qtserialport-devel pkg-config qt5-qtwebsockets-devel libsqlite3x-devel openssl-devel` for both: `git clone https://github.com/foldynl/QLog.git` `cd QLog` for Debian: `qmake QLog.pro` for Debian (QT6): `qmake6 QLog.pro` for Fedora: `/usr/bin/qmake-qt5` NOTE: if it is necessary then use `qmake` input parameters described above to affect compilation. The input parameter must be use in case when Hamlib or qtkeychain are compiled from their source code repos. for all: `make` ### MacOS In order to build QLog on MacOS, following prerequisites must be satisfied. 1. [Xcode](#xcode) command line tools 2. [Homebrew](https://brew.sh) 3. [Qt](https://www.qt.io) with QtCreator ##### Xcode Xcode command line tools can be installed by issuing a command in command terminal: ``` xcode-select --install ``` **N.B.:** This command doesn't install Xcode itself, however It will take some time to download and install the tools anyway. ##### MacOS build Last dependencies before building QLog are: ``` brew install qt6 brew link qt6 --force brew install hamlib brew link hamlib --force brew install qtkeychain brew install dbus-glib brew install brotli brew install icu4c brew install pkg-config ``` As soon as the steps above are finished, QLog source can be opened in QtCreator, configured, built and run. QLog app (qlog.app) from the build artifacts folder can be later copied (`installed`) to `~/Applications` and accessed via Spotlight search bar. NOTE: if it is necessary then use `qmake` input parameters described above to affect compilation. The input parameter must be use in case when hamlib or qtkeychain is compiled from their source code repos. ## License Copyright (C) 2020 Thomas Gatzweiler Copyright (C) 2021-2026 Ladislav Foldyna 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 3 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, see . foldynl-QLog-3252ff9/awards/000077500000000000000000000000001517334601000156445ustar00rootroot00000000000000foldynl-QLog-3252ff9/awards/AwardDXCC.cpp000066400000000000000000000023001517334601000200430ustar00rootroot00000000000000#include #include "AwardDXCC.h" QString AwardDXCC::displayName() const { return QCoreApplication::translate("AwardsDialog", "DXCC"); } QString AwardDXCC::headersColumns(const QString &) const { return QStringLiteral("translate_to_locale(d.name) col1, d.prefix col2 "); } QString AwardDXCC::sqlDetailTable(const QString &entity) const { return " FROM (SELECT id, name, prefix FROM dxcc_entities_clublog WHERE deleted = 0 " " UNION " " SELECT DISTINCT dxcc, b.name, b.prefix || ' (" + QCoreApplication::translate("AwardsDialog", "DELETED") + ")' " " FROM source_contacts a INNER JOIN dxcc_entities_clublog b ON a.dxcc = b.id AND b.deleted = 1 where a.my_dxcc = '" + entity + "') d " " LEFT OUTER JOIN source_contacts c ON (d.id = c.dxcc AND (c.id IS NULL OR c.my_dxcc = '" + entity + "'))" " LEFT OUTER JOIN modes m on c.mode = m.name "; } QString AwardDXCC::additionalWhere(const QString &) const { return QString(); } QString AwardDXCC::clickFilter(const QString &, const QString &) const { return QString(); } bool AwardDXCC::clickUsesCountryName() const { return true; } foldynl-QLog-3252ff9/awards/AwardDXCC.h000066400000000000000000000012031517334601000175110ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDDXCC_H #define QLOG_AWARDS_AWARDDXCC_H #include "BandTableAward.h" class AwardDXCC : public BandTableAward { public: QString key() const override { return QStringLiteral("dxcc"); } QString displayName() const override; protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; bool clickUsesCountryName() const override; }; #endif // QLOG_AWARDS_AWARDDXCC_H foldynl-QLog-3252ff9/awards/AwardDefinition.cpp000066400000000000000000000004561517334601000214240ustar00rootroot00000000000000#include "AwardDefinition.h" bool AwardDefinition::entityInputEnabled() const { return true; } bool AwardDefinition::notWorkedEnabled() const { return true; } AwardDefinition::ConditionResult AwardDefinition::getConditionSelected(const QModelIndex &) const { return ConditionResult(); } foldynl-QLog-3252ff9/awards/AwardDefinition.h000066400000000000000000000056741517334601000211000ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDDEFINITION_H #define QLOG_AWARDS_AWARDDEFINITION_H #include #include #include #include /* Filter parameters collected from the AwardsDialog UI controls. * Passed to AwardDefinition::updateData() on every filter change. */ struct AwardFilterParams { QString entitySelected; /* DXCC entity ID from the "My DXCC Entity" combo */ QStringList modes; /* SQL IN-list values, e.g. {"'NONE'", "'CW'", "'PHONE'"} */ QStringList confirmedConditions; /* SQL OR-conditions for confirmed status */ bool notWorkedOnly; /* Show only entities with no QSOs on any band */ bool notConfirmedOnly; /* Show only entities worked but not confirmed */ QString userFilterWhereClause; /* Extra WHERE clause from QSOFilterManager (includes leading "AND") */ }; /* Abstract base class for all award definitions. * * To add a completely custom award (non-table display), subclass this directly * and implement createWidget() / updateData(). * * For the common band-column table display, subclass BandTableAward instead. * * Registration: add one line to AwardsDialog::createAwards(). */ class AwardDefinition { public: virtual ~AwardDefinition() = default; /* Unique internal key (e.g. "dxcc", "sota", "grid4"). Used as combo item data. */ virtual QString key() const = 0; /*Translatable display name shown in the Award combo box. */ virtual QString displayName() const = 0; /*Whether the "My DXCC Entity" combo is shown. Default: true. */ virtual bool entityInputEnabled() const; /*Whether the Not-Worked / Not-Confirmed checkboxes are shown. Default: true. */ virtual bool notWorkedEnabled() const; /*Create the display widget. Called once on first selection. Store in m_widget. */ virtual QWidget* createWidget(QWidget *parent) = 0; /*Refresh data using the current filter parameters. Called on every filter change. */ virtual void updateData(const AwardFilterParams ¶ms) = 0; /* Return filter data for the logbook based on a double-clicked cell. * The dialog uses ConditionResult to emit AwardConditionSelected(country, band, filter) * which opens the logbook filtered to matching QSOs. * Default implementation returns an invalid (no-op) result. */ struct ConditionResult { QString country; /* Country name for the logbook filter (empty = not used) */ QString band; /* Band name from the column header (empty = all bands) */ QString filter; /* SQL WHERE clause fragment, e.g. "(sota_ref = 'OE/TI-001')" */ bool valid = false; }; virtual ConditionResult getConditionSelected(const QModelIndex &clickedIndex) const; /*Returns the cached widget (nullptr before createWidget()). */ QWidget* widget() const { return m_widget; } protected: QWidget *m_widget = nullptr; }; #endif // QLOG_AWARDS_AWARDDEFINITION_H foldynl-QLog-3252ff9/awards/AwardGridsquare.cpp000066400000000000000000000024221517334601000214350ustar00rootroot00000000000000#include #include "AwardGridsquare.h" AwardGridsquare::AwardGridsquare(int chars) : m_chars(chars) { } QString AwardGridsquare::key() const { return QString("grid%1").arg(m_chars); } QString AwardGridsquare::displayName() const { switch ( m_chars ) { case 2: return QCoreApplication::translate("AwardsDialog", "Gridsquare 2-Chars"); case 4: return QCoreApplication::translate("AwardsDialog", "Gridsquare 4-Chars"); case 6: return QCoreApplication::translate("AwardsDialog", "Gridsquare 6-Chars"); default: return QCoreApplication::translate("AwardsDialog", "Gridsquare %1-Chars").arg(m_chars); } } QString AwardGridsquare::headersColumns(const QString &) const { return QString("substr(c.gridsquare, 1, %1) col1, NULL col2 ").arg(m_chars); } QString AwardGridsquare::sqlDetailTable(const QString &entity) const { return " FROM source_contacts c" " INNER JOIN modes m ON c.mode = m.name AND c.my_dxcc = '" + entity + "' "; } QString AwardGridsquare::additionalWhere(const QString &) const { return QString(" AND length(c.gridsquare) >= %1 ").arg(m_chars); } QString AwardGridsquare::clickFilter(const QString &col1Value, const QString &) const { return QString("gridsquare LIKE '%1%%'").arg(col1Value); } foldynl-QLog-3252ff9/awards/AwardGridsquare.h000066400000000000000000000013131517334601000211000ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDGRIDSQUARE_H #define QLOG_AWARDS_AWARDGRIDSQUARE_H #include "BandTableAward.h" class AwardGridsquare : public BandTableAward { public: explicit AwardGridsquare(int chars); QString key() const override; QString displayName() const override; bool notWorkedEnabled() const override { return false; } protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; private: int m_chars; }; #endif // QLOG_AWARDS_AWARDGRIDSQUARE_H foldynl-QLog-3252ff9/awards/AwardIOTA.cpp000066400000000000000000000013041517334601000200610ustar00rootroot00000000000000#include #include "AwardIOTA.h" QString AwardIOTA::displayName() const { return QCoreApplication::translate("AwardsDialog", "IOTA"); } QString AwardIOTA::headersColumns(const QString &) const { return QStringLiteral("c.iota col1, NULL col2 "); } QString AwardIOTA::sqlDetailTable(const QString &entity) const { return " FROM source_contacts c" " INNER JOIN modes m ON c.mode = m.name AND c.my_dxcc = '" + entity + "'"; } QString AwardIOTA::additionalWhere(const QString &) const { return " AND c.iota is not NULL "; } QString AwardIOTA::clickFilter(const QString &col1Value, const QString &) const { return QString("iota = '%1'").arg(col1Value); } foldynl-QLog-3252ff9/awards/AwardIOTA.h000066400000000000000000000012201517334601000175230ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDIOTA_H #define QLOG_AWARDS_AWARDIOTA_H #include "BandTableAward.h" class AwardIOTA : public BandTableAward { public: QString key() const override { return QStringLiteral("iota"); } QString displayName() const override; bool notWorkedEnabled() const override { return false; } protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDIOTA_H foldynl-QLog-3252ff9/awards/AwardITU.cpp000066400000000000000000000015611517334601000177730ustar00rootroot00000000000000#include #include "AwardITU.h" QString AwardITU::displayName() const { return QCoreApplication::translate("AwardsDialog", "ITU"); } QString AwardITU::headersColumns(const QString &) const { return QStringLiteral("d.n col1, null col2 "); } QString AwardITU::sqlDetailTable(const QString &entity) const { return " FROM ituzCTE d " " LEFT OUTER JOIN source_contacts c ON d.n = c.ituz AND c.my_dxcc = '" + entity + "'" " LEFT OUTER JOIN modes m on c.mode = m.name"; } QString AwardITU::additionalWhere(const QString &) const { return QString(); } QStringList AwardITU::additionalCTEs(const QString &, const QString &) const { return { generateNumberRangeCTE("ituzCTE", 1, 90) }; } QString AwardITU::clickFilter(const QString &col1Value, const QString &) const { return QString("ituz = '%1'").arg(col1Value); } foldynl-QLog-3252ff9/awards/AwardITU.h000066400000000000000000000012621517334601000174360ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDITU_H #define QLOG_AWARDS_AWARDITU_H #include "BandTableAward.h" class AwardITU : public BandTableAward { public: QString key() const override { return QStringLiteral("itu"); } QString displayName() const override; protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QStringList additionalCTEs(const QString &entity, const QString &contactFilter) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDITU_H foldynl-QLog-3252ff9/awards/AwardJapan.cpp000066400000000000000000000004421517334601000203600ustar00rootroot00000000000000#include #include "AwardJapan.h" AwardJapan::AwardJapan() : SecondarySubdivisionAward(QStringLiteral("japan"), QStringLiteral("339")) { } QString AwardJapan::displayName() const { return QCoreApplication::translate("AwardsDialog", "Japanese Cities/Ku/Guns"); } foldynl-QLog-3252ff9/awards/AwardJapan.h000066400000000000000000000004141517334601000200240ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDJAPAN_H #define QLOG_AWARDS_AWARDJAPAN_H #include "SecondarySubdivisionAward.h" class AwardJapan : public SecondarySubdivisionAward { public: AwardJapan(); QString displayName() const override; }; #endif // QLOG_AWARDS_AWARDJAPAN_H foldynl-QLog-3252ff9/awards/AwardNZ.cpp000066400000000000000000000004071517334601000176570ustar00rootroot00000000000000#include #include "AwardNZ.h" AwardNZ::AwardNZ() : SecondarySubdivisionAward(QStringLiteral("nz"), QStringLiteral("170")) { } QString AwardNZ::displayName() const { return QCoreApplication::translate("AwardsDialog", "NZ Counties"); } foldynl-QLog-3252ff9/awards/AwardNZ.h000066400000000000000000000003751517334601000173300ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDNZ_H #define QLOG_AWARDS_AWARDNZ_H #include "SecondarySubdivisionAward.h" class AwardNZ : public SecondarySubdivisionAward { public: AwardNZ(); QString displayName() const override; }; #endif // QLOG_AWARDS_AWARDNZ_H foldynl-QLog-3252ff9/awards/AwardPOTAActivator.cpp000066400000000000000000000024671517334601000217600ustar00rootroot00000000000000#include #include "AwardPOTAActivator.h" QString AwardPOTAActivator::displayName() const { return QCoreApplication::translate("AwardsDialog", "POTA Activator"); } QString AwardPOTAActivator::headersColumns(const QString &) const { return QStringLiteral("p.reference col1, p.name col2 "); } QString AwardPOTAActivator::sqlDetailTable(const QString &) const { return " FROM pota_directory p " " INNER JOIN source_contacts c ON SUBSTR(c.my_pota_ref_str, 1, COALESCE(NULLIF(INSTR(c.my_pota_ref_str, '@'), 0) - 1, LENGTH(c.my_pota_ref_str))) = p.reference" " INNER JOIN modes m on c.mode = m.name "; } QString AwardPOTAActivator::additionalWhere(const QString &) const { return " AND c.my_pota_ref_str is not NULL "; } QStringList AwardPOTAActivator::additionalCTEs(const QString &, const QString &contactFilter) const { return { generateSplitCTE("my_pota_ref", "my_pota_ref_str", contactFilter) }; } QString AwardPOTAActivator::sourceContactsOverride(const QString &) const { return generateSplitSourceContacts("my_pota_ref_str"); } QString AwardPOTAActivator::clickFilter(const QString &col1Value, const QString &) const { // Bug fix: original had "my_pota_ref LIKE = '%%1%'" (extra '=') return QString("my_pota_ref LIKE '%%1%'").arg(col1Value); } foldynl-QLog-3252ff9/awards/AwardPOTAActivator.h000066400000000000000000000016511517334601000214170ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDPOTAACTIVATOR_H #define QLOG_AWARDS_AWARDPOTAACTIVATOR_H #include "BandTableAward.h" class AwardPOTAActivator : public BandTableAward { public: QString key() const override { return QStringLiteral("potaa"); } QString displayName() const override; bool entityInputEnabled() const override { return false; } bool notWorkedEnabled() const override { return false; } protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QStringList additionalCTEs(const QString &entity, const QString &contactFilter) const override; QString sourceContactsOverride(const QString &contactFilter) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDPOTAACTIVATOR_H foldynl-QLog-3252ff9/awards/AwardPOTAHunter.cpp000066400000000000000000000022171517334601000212620ustar00rootroot00000000000000#include #include "AwardPOTAHunter.h" QString AwardPOTAHunter::displayName() const { return QCoreApplication::translate("AwardsDialog", "POTA Hunter"); } QString AwardPOTAHunter::headersColumns(const QString &) const { return QStringLiteral("p.reference col1, p.name col2 "); } QString AwardPOTAHunter::sqlDetailTable(const QString &) const { return " FROM pota_directory p " " INNER JOIN source_contacts c ON SUBSTR(c.pota, 1, COALESCE(NULLIF(INSTR(c.pota, '@'), 0) - 1, LENGTH(c.pota))) = p.reference" " INNER JOIN modes m on c.mode = m.name "; } QString AwardPOTAHunter::additionalWhere(const QString &) const { return " AND c.pota is not NULL "; } QStringList AwardPOTAHunter::additionalCTEs(const QString &, const QString &contactFilter) const { return { generateSplitCTE("pota_ref", "pota", contactFilter) }; } QString AwardPOTAHunter::sourceContactsOverride(const QString &) const { return generateSplitSourceContacts("pota"); } QString AwardPOTAHunter::clickFilter(const QString &col1Value, const QString &) const { return QString("pota_ref LIKE '%%1%'").arg(col1Value); } foldynl-QLog-3252ff9/awards/AwardPOTAHunter.h000066400000000000000000000016351517334601000207320ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDPOTAHUNTER_H #define QLOG_AWARDS_AWARDPOTAHUNTER_H #include "BandTableAward.h" class AwardPOTAHunter : public BandTableAward { public: QString key() const override { return QStringLiteral("potah"); } QString displayName() const override; bool entityInputEnabled() const override { return false; } bool notWorkedEnabled() const override { return false; } protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QStringList additionalCTEs(const QString &entity, const QString &contactFilter) const override; QString sourceContactsOverride(const QString &contactFilter) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDPOTAHUNTER_H foldynl-QLog-3252ff9/awards/AwardRDA.cpp000066400000000000000000000004431517334601000177360ustar00rootroot00000000000000#include #include "AwardRDA.h" AwardRDA::AwardRDA() : SecondarySubdivisionAward(QStringLiteral("rda"), QStringLiteral("15, 54, 61, 126, 151")) { } QString AwardRDA::displayName() const { return QCoreApplication::translate("AwardsDialog", "Russian Districts"); } foldynl-QLog-3252ff9/awards/AwardRDA.h000066400000000000000000000004021517334601000173760ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDRDA_H #define QLOG_AWARDS_AWARDRDA_H #include "SecondarySubdivisionAward.h" class AwardRDA : public SecondarySubdivisionAward { public: AwardRDA(); QString displayName() const override; }; #endif // QLOG_AWARDS_AWARDRDA_H foldynl-QLog-3252ff9/awards/AwardSOTA.cpp000066400000000000000000000013431517334601000200760ustar00rootroot00000000000000#include #include "AwardSOTA.h" QString AwardSOTA::displayName() const { return QCoreApplication::translate("AwardsDialog", "SOTA"); } QString AwardSOTA::headersColumns(const QString &) const { return QStringLiteral("s.summit_code col1, NULL col2 "); } QString AwardSOTA::sqlDetailTable(const QString &) const { return " FROM sota_summits s " " INNER JOIN source_contacts c ON c.sota_ref = s.summit_code " " INNER JOIN modes m on c.mode = m.name "; } QString AwardSOTA::additionalWhere(const QString &) const { return QString(); } QString AwardSOTA::clickFilter(const QString &col1Value, const QString &) const { return QString("sota_ref = '%1'").arg(col1Value); } foldynl-QLog-3252ff9/awards/AwardSOTA.h000066400000000000000000000013171517334601000175440ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDSOTA_H #define QLOG_AWARDS_AWARDSOTA_H #include "BandTableAward.h" class AwardSOTA : public BandTableAward { public: QString key() const override { return QStringLiteral("sota"); } QString displayName() const override; bool entityInputEnabled() const override { return false; } bool notWorkedEnabled() const override { return false; } protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDSOTA_H foldynl-QLog-3252ff9/awards/AwardSpanishDME.cpp000066400000000000000000000004741517334601000212670ustar00rootroot00000000000000#include #include "AwardSpanishDME.h" AwardSpanishDME::AwardSpanishDME() : SecondarySubdivisionAward(QStringLiteral("spanishdme"), QStringLiteral("21, 29, 32, 281")) { } QString AwardSpanishDME::displayName() const { return QCoreApplication::translate("AwardsDialog", "Spanish DMEs"); } foldynl-QLog-3252ff9/awards/AwardSpanishDME.h000066400000000000000000000004451517334601000207320ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDSPANISHDME_H #define QLOG_AWARDS_AWARDSPANISHDME_H #include "SecondarySubdivisionAward.h" class AwardSpanishDME : public SecondarySubdivisionAward { public: AwardSpanishDME(); QString displayName() const override; }; #endif // QLOG_AWARDS_AWARDSPANISHDME_H foldynl-QLog-3252ff9/awards/AwardUKD.cpp000066400000000000000000000004241517334601000177520ustar00rootroot00000000000000#include #include "AwardUKD.h" AwardUKD::AwardUKD() : SecondarySubdivisionAward(QStringLiteral("ukd"), QStringLiteral("288")) { } QString AwardUKD::displayName() const { return QCoreApplication::translate("AwardsDialog", "Ukrainian Districts"); } foldynl-QLog-3252ff9/awards/AwardUKD.h000066400000000000000000000004021517334601000174130ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDUKD_H #define QLOG_AWARDS_AWARDUKD_H #include "SecondarySubdivisionAward.h" class AwardUKD : public SecondarySubdivisionAward { public: AwardUKD(); QString displayName() const override; }; #endif // QLOG_AWARDS_AWARDUKD_H foldynl-QLog-3252ff9/awards/AwardUSCounty.cpp000066400000000000000000000004551517334601000210640ustar00rootroot00000000000000#include #include "AwardUSCounty.h" AwardUSCounty::AwardUSCounty() : SecondarySubdivisionAward(QStringLiteral("uscounty"), QStringLiteral("291, 6, 110")) { } QString AwardUSCounty::displayName() const { return QCoreApplication::translate("AwardsDialog", "US Counties"); } foldynl-QLog-3252ff9/awards/AwardUSCounty.h000066400000000000000000000004331517334601000205250ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDUSCOUNTY_H #define QLOG_AWARDS_AWARDUSCOUNTY_H #include "SecondarySubdivisionAward.h" class AwardUSCounty : public SecondarySubdivisionAward { public: AwardUSCounty(); QString displayName() const override; }; #endif // QLOG_AWARDS_AWARDUSCOUNTY_H foldynl-QLog-3252ff9/awards/AwardWAC.cpp000066400000000000000000000031701517334601000177420ustar00rootroot00000000000000#include #include "AwardWAC.h" /* https://www.arrl.org/wac */ QString AwardWAC::displayName() const { return QCoreApplication::translate("AwardsDialog", "WAC"); } QString AwardWAC::headersColumns(const QString &) const { return QStringLiteral("d.column2 col1, d.column1 col2 "); } QString AwardWAC::sqlDetailTable(const QString &entity) const { return " FROM continents d " " LEFT OUTER JOIN source_contacts c ON d.column1 = c.cont AND c.my_dxcc = '" + entity + "'" " LEFT OUTER JOIN modes m on c.mode = m.name "; } QString AwardWAC::additionalWhere(const QString &) const { return QString(); } QStringList AwardWAC::additionalCTEs(const QString &, const QString &) const { return { generateValuesCTE("continents", { { QStringLiteral("NA"), QCoreApplication::translate("AwardsDialog", "North America") }, { QStringLiteral("SA"), QCoreApplication::translate("AwardsDialog", "South America") }, { QStringLiteral("EU"), QCoreApplication::translate("AwardsDialog", "Europe") }, { QStringLiteral("AF"), QCoreApplication::translate("AwardsDialog", "Africa") }, { QStringLiteral("OC"), QCoreApplication::translate("AwardsDialog", "Oceania") }, { QStringLiteral("AS"), QCoreApplication::translate("AwardsDialog", "Asia") } }) }; } QString AwardWAC::clickFilter(const QString &, const QString &col2Value) const { return QString("cont = '%1'").arg(col2Value); } foldynl-QLog-3252ff9/awards/AwardWAC.h000066400000000000000000000012621517334601000174070ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDWAC_H #define QLOG_AWARDS_AWARDWAC_H #include "BandTableAward.h" class AwardWAC : public BandTableAward { public: QString key() const override { return QStringLiteral("wac"); } QString displayName() const override; protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QStringList additionalCTEs(const QString &entity, const QString &contactFilter) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDWAC_H foldynl-QLog-3252ff9/awards/AwardWAS.cpp000066400000000000000000000015611517334601000177640ustar00rootroot00000000000000#include #include "AwardWAS.h" QString AwardWAS::displayName() const { return QCoreApplication::translate("AwardsDialog", "WAS"); } QString AwardWAS::headersColumns(const QString &) const { return QStringLiteral("d.subdivision_name col1, d.code col2 "); } QString AwardWAS::sqlDetailTable(const QString &entity) const { return " FROM adif_enum_primary_subdivision d" " LEFT OUTER JOIN source_contacts c ON d.dxcc = c.dxcc AND d.code = c.state AND c.my_dxcc = '" + entity + "' AND d.dxcc in (6, 110, 291)" " LEFT OUTER JOIN modes m on c.mode = m.name"; } QString AwardWAS::additionalWhere(const QString &) const { return " AND d.dxcc in (6, 110, 291) "; } QString AwardWAS::clickFilter(const QString &, const QString &col2Value) const { return QString("state = '%1' and dxcc in (6, 110, 291)").arg(col2Value); } foldynl-QLog-3252ff9/awards/AwardWAS.h000066400000000000000000000011161517334601000174250ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDWAS_H #define QLOG_AWARDS_AWARDWAS_H #include "BandTableAward.h" class AwardWAS : public BandTableAward { public: QString key() const override { return QStringLiteral("was"); } QString displayName() const override; protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDWAS_H foldynl-QLog-3252ff9/awards/AwardWAZ.cpp000066400000000000000000000015561517334601000177770ustar00rootroot00000000000000#include #include "AwardWAZ.h" QString AwardWAZ::displayName() const { return QCoreApplication::translate("AwardsDialog", "WAZ"); } QString AwardWAZ::headersColumns(const QString &) const { return QStringLiteral("d.n col1, null col2 "); } QString AwardWAZ::sqlDetailTable(const QString &entity) const { return " FROM cqzCTE d " " LEFT OUTER JOIN source_contacts c ON d.n = c.cqz AND c.my_dxcc = '" + entity + "'" " LEFT OUTER JOIN modes m on c.mode = m.name "; } QString AwardWAZ::additionalWhere(const QString &) const { return QString(); } QStringList AwardWAZ::additionalCTEs(const QString &, const QString &) const { return { generateNumberRangeCTE("cqzCTE", 1, 40) }; } QString AwardWAZ::clickFilter(const QString &col1Value, const QString &) const { return QString("cqz = '%1'").arg(col1Value); } foldynl-QLog-3252ff9/awards/AwardWAZ.h000066400000000000000000000012621517334601000174360ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDWAZ_H #define QLOG_AWARDS_AWARDWAZ_H #include "BandTableAward.h" class AwardWAZ : public BandTableAward { public: QString key() const override { return QStringLiteral("waz"); } QString displayName() const override; protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QStringList additionalCTEs(const QString &entity, const QString &contactFilter) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDWAZ_H foldynl-QLog-3252ff9/awards/AwardWPX.cpp000066400000000000000000000012721517334601000200070ustar00rootroot00000000000000#include #include "AwardWPX.h" QString AwardWPX::displayName() const { return QCoreApplication::translate("AwardsDialog", "WPX"); } QString AwardWPX::headersColumns(const QString &) const { return QStringLiteral("c.pfx col1, null col2 "); } QString AwardWPX::sqlDetailTable(const QString &entity) const { return " FROM source_contacts c" " INNER JOIN modes m ON c.mode = m.name AND c.my_dxcc = '" + entity + "'"; } QString AwardWPX::additionalWhere(const QString &) const { return " AND c.pfx is not null "; } QString AwardWPX::clickFilter(const QString &col1Value, const QString &) const { return QString("pfx = '%1'").arg(col1Value); } foldynl-QLog-3252ff9/awards/AwardWPX.h000066400000000000000000000012131517334601000174470ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDWPX_H #define QLOG_AWARDS_AWARDWPX_H #include "BandTableAward.h" class AwardWPX : public BandTableAward { public: QString key() const override { return QStringLiteral("wpx"); } QString displayName() const override; bool notWorkedEnabled() const override { return false; } protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDWPX_H foldynl-QLog-3252ff9/awards/AwardWWFF.cpp000066400000000000000000000013431517334601000201010ustar00rootroot00000000000000#include #include "AwardWWFF.h" QString AwardWWFF::displayName() const { return QCoreApplication::translate("AwardsDialog", "WWFF"); } QString AwardWWFF::headersColumns(const QString &) const { return QStringLiteral("w.reference col1, w.name col2 "); } QString AwardWWFF::sqlDetailTable(const QString &) const { return " FROM wwff_directory w " " INNER JOIN source_contacts c ON c.wwff_ref = w.reference " " INNER JOIN modes m on c.mode = m.name "; } QString AwardWWFF::additionalWhere(const QString &) const { return QString(); } QString AwardWWFF::clickFilter(const QString &col1Value, const QString &) const { return QString("wwff_ref = '%1'").arg(col1Value); } foldynl-QLog-3252ff9/awards/AwardWWFF.h000066400000000000000000000013171517334601000175470ustar00rootroot00000000000000#ifndef QLOG_AWARDS_AWARDWWFF_H #define QLOG_AWARDS_AWARDWWFF_H #include "BandTableAward.h" class AwardWWFF : public BandTableAward { public: QString key() const override { return QStringLiteral("wwff"); } QString displayName() const override; bool entityInputEnabled() const override { return false; } bool notWorkedEnabled() const override { return false; } protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; }; #endif // QLOG_AWARDS_AWARDWWFF_H foldynl-QLog-3252ff9/awards/BandTableAward.cpp000066400000000000000000000314131517334601000211450ustar00rootroot00000000000000#include #include "BandTableAward.h" #include "core/debug.h" #include "data/Band.h" #include "data/BandPlan.h" MODULE_IDENTIFICATION("qlog.awards.bandtableaward"); QWidget* BandTableAward::createWidget(QWidget *parent) { FCT_IDENTIFICATION; m_tableView = new QTableView(parent); m_model = new AwardsTableModel(m_tableView); m_tableView->setFocusPolicy(Qt::ClickFocus); m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_tableView->setAlternatingRowColors(true); m_tableView->setSelectionMode(QAbstractItemView::SingleSelection); m_tableView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_tableView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); m_tableView->horizontalHeader()->setVisible(true); m_tableView->horizontalHeader()->setCascadingSectionResizes(true); m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); m_tableView->verticalHeader()->setVisible(false); m_tableView->verticalHeader()->setMinimumSectionSize(20); m_tableView->verticalHeader()->setDefaultSectionSize(20); m_tableView->verticalHeader()->setHighlightSections(false); m_widget = m_tableView; return m_widget; } void BandTableAward::updateData(const AwardFilterParams ¶ms) { FCT_IDENTIFICATION; const QList& dxccBands = BandPlan::bandsList(false, true); if ( dxccBands.size() == 0 ) return; m_currentEntity = params.entitySelected; const QString innerConfirmedCase(QString(" CASE WHEN (%1) THEN 2 ELSE 1 END ") .arg(params.confirmedConditions.isEmpty() ? QStringLiteral("1=2") : params.confirmedConditions.join(" or "))); QStringList stmt_max_part; QStringList stmt_total_padding; QStringList stmt_sum_confirmed; QStringList stmt_sum_worked; QStringList stmt_sum_total; QStringList stmt_having; QStringList stmt_total_band_condition_work; QStringList stmt_total_band_condition_confirmed; QStringList stmt_not_confirmed; QStringList stmt_any_worked; for ( const Band& band : dxccBands ) { stmt_max_part << QString(" MAX(CASE WHEN band = '%1' AND m.dxcc IN (%2) THEN %3 ELSE 0 END) as '%4'") .arg(band.name, params.modes.join(","), innerConfirmedCase, band.name); stmt_total_padding << QString(" NULL '%1'").arg(band.name); stmt_sum_confirmed << QString("SUM(CASE WHEN a.'%1' > 1 THEN 1 ELSE 0 END) '%2'").arg(band.name, band.name); stmt_sum_worked << QString("SUM(CASE WHEN a.'%1' > 0 THEN 1 ELSE 0 END) '%2'").arg(band.name, band.name); stmt_sum_total << QString("SUM(d.'%1') '%2'").arg(band.name, band.name); stmt_having << QString("SUM(d.'%1') = 0").arg(band.name); stmt_total_band_condition_work << QString("e.'%1' > 0").arg(band.name); stmt_total_band_condition_confirmed << QString("e.'%1' > 1").arg(band.name); stmt_not_confirmed << QString("MAX(d.'%1') < 2").arg(band.name); stmt_any_worked << QString("MAX(d.'%1') > 0").arg(band.name); } stmt_max_part << QString(" MAX(CASE WHEN prop_mode = 'SAT' AND m.dxcc IN (%1) THEN %2 ELSE 0 END) as 'SAT' ").arg(params.modes.join(","), innerConfirmedCase) << QString(" MAX(CASE WHEN prop_mode = 'EME' AND m.dxcc IN (%1) THEN %2 ELSE 0 END) as 'EME' ").arg(params.modes.join(","), innerConfirmedCase); stmt_total_padding << " NULL 'SAT' " << " NULL 'EME' "; stmt_sum_confirmed << " SUM(CASE WHEN a.'SAT' > 1 THEN 1 ELSE 0 END) 'SAT' " << " SUM(CASE WHEN a.'EME' > 1 THEN 1 ELSE 0 END) 'EME' "; stmt_sum_worked << " SUM(CASE WHEN a.'SAT' > 0 THEN 1 ELSE 0 END) 'SAT' " << " SUM(CASE WHEN a.'EME' > 0 THEN 1 ELSE 0 END) 'EME' "; stmt_sum_total << " SUM(d.'SAT') 'SAT' " << " SUM(d.'EME') 'EME' "; stmt_having << " SUM(d.'SAT') = 0" << " SUM(d.'EME') = 0"; stmt_total_band_condition_work << "e.'SAT' > 0" << "e.'EME' > 0"; stmt_total_band_condition_confirmed << "e.'SAT' > 1" << "e.'EME' > 1"; stmt_not_confirmed << " MAX(d.'SAT') < 2" << " MAX(d.'EME') < 2"; stmt_any_worked << " MAX(d.'SAT') > 0" << " MAX(d.'EME') > 0"; const QString &entity = params.entitySelected; QString sourceContactsTable = sourceContactsOverride(params.userFilterWhereClause); if ( sourceContactsTable.isEmpty() ) { sourceContactsTable = QString(" source_contacts AS " " (SELECT * " " FROM contacts " " WHERE 1=1 %1 ) ").arg(params.userFilterWhereClause); } QStringList addlCTEs = additionalCTEs(entity, params.userFilterWhereClause); addlCTEs.append(sourceContactsTable); QStringList havingConditions; if ( params.notWorkedOnly ) havingConditions << QString("(%1)").arg(stmt_having.join(" AND ")); if ( params.notConfirmedOnly ) havingConditions << QString("(%1) AND (%2)").arg(stmt_not_confirmed.join(" AND "), stmt_any_worked.join(" OR ")); QString havingClause; if ( !havingConditions.isEmpty() ) havingClause = QString("HAVING %1").arg(havingConditions.join(" OR ")); QString finalSQL(QString( "WITH " " %1, " " detail_table AS ( " " SELECT %2, %3 " " %4" " WHERE 1=1 %5" " GROUP BY 1,2), " " unique_worked AS (" " SELECT DISTINCT col1" " FROM detail_table e" " WHERE %6), " " unique_confirmed AS (" " SELECT DISTINCT col1" " FROM detail_table e" " WHERE %7) " "SELECT * FROM ( " " SELECT 0 column_idx, '%8', COUNT(*), %9" " FROM unique_worked" " UNION ALL " " SELECT 0 column_idx, '%10', COUNT(*), %11" " FROM unique_confirmed" " UNION ALL " " SELECT 1 column_idx, '%12', NULL prefix, %13" " FROM detail_table a " " GROUP BY 1 " " UNION ALL " " SELECT 2 column_idx, '%14', NULL prefix, %15" " FROM detail_table a " " GROUP BY 1 " " UNION ALL " " SELECT 3 column_idx, col1, col2, %16" " FROM detail_table d " " GROUP BY 2,3 " " %17" ") " "ORDER BY 1,2 COLLATE LOCALEAWARE ASC ").arg(addlCTEs.join(","), // 1 headersColumns(entity), // 2 stmt_max_part.join(","), // 3 sqlDetailTable(entity), // 4 additionalWhere(entity), // 5 stmt_total_band_condition_work.join(" OR "), // 6 stmt_total_band_condition_confirmed.join(" OR "), // 7 QObject::tr("TOTAL Worked"), // 8 stmt_total_padding.join(",") // 9 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) , #else ).arg( #endif QObject::tr("TOTAL Confirmed"), // 10 stmt_total_padding.join(","), // 11 QObject::tr("Confirmed"), // 12 stmt_sum_confirmed.join(",") // 13 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) , #else ).arg( #endif QObject::tr("Worked")).arg( // 14 stmt_sum_worked.join(","), // 15 stmt_sum_total.join(","), // 16 havingClause) // 17 ); qCDebug(runtime) << finalSQL; m_model->setQuery(finalSQL); m_model->setHeaderData(1, Qt::Horizontal, ""); m_model->setHeaderData(2, Qt::Horizontal, ""); m_tableView->setModel(m_model); m_tableView->setColumnHidden(0, true); } BandTableAward::ConditionResult BandTableAward::getConditionSelected(const QModelIndex &clickedIndex) const { FCT_IDENTIFICATION; ConditionResult result; if ( !clickedIndex.isValid() || clickedIndex.row() <= 3 ) return result; const QString col1Value = m_model->data(m_model->index(clickedIndex.row(), 1), Qt::DisplayRole).toString(); const QString col2Value = m_model->data(m_model->index(clickedIndex.row(), 2), Qt::DisplayRole).toString(); QStringList addlFilters; if ( entityInputEnabled() ) addlFilters << QString("my_dxcc='%1'").arg(m_currentEntity); if ( clickUsesCountryName() ) { result.country = col1Value; } else { const QString filter = clickFilter(col1Value, col2Value); Q_ASSERT_X(!filter.isEmpty(), "BandTableAward::getConditionSelected", "clickFilter() returned empty string — subclass must override clickFilter() or clickUsesCountryName()"); addlFilters << filter; } if ( clickedIndex.column() > 2 ) result.band = m_model->headerData(clickedIndex.column(), Qt::Horizontal).toString(); result.filter = QString("(") + addlFilters.join(" and ") + QString(")"); result.valid = true; return result; } QStringList BandTableAward::additionalCTEs(const QString &, const QString &) const { return QStringList(); } QString BandTableAward::sourceContactsOverride(const QString &) const { return QString(); } QString BandTableAward::clickFilter(const QString &, const QString &) const { return QString(); } bool BandTableAward::clickUsesCountryName() const { return false; } QString BandTableAward::generateNumberRangeCTE(const QString &name, int min, int max) { return QString(" %1 AS (" " SELECT %2 AS n, %2 AS value" " UNION ALL" " SELECT n + 1, value + 1" " FROM %1" " WHERE n < %3 )").arg(name).arg(min).arg(max); } QString BandTableAward::generateValuesCTE(const QString &name, const QList> &values) { QStringList rows; for ( const QPair &pair : values ) rows << QString("('%1', '%2')").arg(pair.first, pair.second); return QString(" %1 AS (VALUES %2)").arg(name, rows.join(",")); } QString BandTableAward::generateSplitCTE(const QString &sourceColumn, const QString &outputColumn, const QString &contactFilter) { return QString(" split(id, callsign, station_callsign, my_dxcc, band, dxcc, eqsl_qsl_rcvd, lotw_qsl_rcvd, qsl_rcvd, prop_mode, mode, %1, str) AS (" " SELECT id, callsign, station_callsign, my_dxcc, band, " " dxcc, eqsl_qsl_rcvd, lotw_qsl_rcvd, qsl_rcvd, prop_mode, mode, " " '', %2||',' " " FROM contacts WHERE 1=1 %3" " UNION ALL " " SELECT id, callsign, station_callsign, my_dxcc, band, " " dxcc, eqsl_qsl_rcvd, lotw_qsl_rcvd, qsl_rcvd, prop_mode, mode, " " substr(str, 0, instr(str, ',')), TRIM(substr(str, instr(str, ',') + 1)) " " FROM split " " WHERE str != '') ").arg(outputColumn, sourceColumn, contactFilter); } QString BandTableAward::generateSplitSourceContacts(const QString &outputColumn) { return QString(" source_contacts AS (" " SELECT id, callsign, station_callsign, my_dxcc, band, dxcc, eqsl_qsl_rcvd, lotw_qsl_rcvd, qsl_rcvd, prop_mode, mode, %1 " " FROM split " " WHERE %1 != '' ) ").arg(outputColumn); } foldynl-QLog-3252ff9/awards/BandTableAward.h000066400000000000000000000264671517334601000206270ustar00rootroot00000000000000#ifndef QLOG_AWARDS_BANDTABLEAWARD_H #define QLOG_AWARDS_BANDTABLEAWARD_H #include #include #include "AwardDefinition.h" #include "models/AwardsTableModel.h" /* Standard band-column table award — the default display for most awards. * * This class builds and executes a SQL query that produces a table where: * - Rows = award entities (countries, zones, parks, summits, ...) * - Cols = amateur bands + SAT + EME * - Cells = worked / confirmed / not-worked status (color-coded) * * Summary rows (TOTAL Worked, TOTAL Confirmed, per-band Worked/Confirmed counts) * are prepended automatically. * * === How to add a new band-table award === * * 1. Create a subclass of BandTableAward. * 2. Implement key() and displayName() (identity). * 3. Override entityInputEnabled() / notWorkedEnabled() if needed. * 4. Implement the three REQUIRED SQL fragment methods: * - headersColumns() — what goes into SELECT as col1, col2 * - sqlDetailTable() — FROM + JOINs * - additionalWhere() — extra WHERE conditions * 5. Override clickFilter() so double-click navigates to the right QSOs. * 6. Register in AwardsDialog::createAwards(). * * That's it for simple awards. For awards that need a CTE (e.g. a number range * or a comma-separated field split), override additionalCTEs() and optionally * sourceContactsOverride(). Use the static helper methods to build CTEs without * writing raw SQL. * * === The generated SQL structure === * * WITH * , -- optional, from additionalCTEs() * source_contacts AS (SELECT ... FROM contacts WHERE ...), -- or sourceContactsOverride() * detail_table AS ( * SELECT col1, col2, * MAX(CASE WHEN band='160m' ... END) as '160m', * ... -- one column per band + SAT + EME * -- FROM ... JOIN ... * -- AND ... * GROUP BY 1,2 * ), * unique_worked AS (...), * unique_confirmed AS (...) * SELECT ... -- summary rows + detail rows * ORDER BY 1,2 COLLATE LOCALEAWARE ASC * * === Double-click behavior === * * When a user double-clicks a detail row (row > 3), getConditionSelected() * builds a ConditionResult by calling clickFilter(col1, col2). The dialog * then emits AwardConditionSelected() to filter the logbook. * * Override clickUsesCountryName() to return true if col1 is a country name * that should be passed as the "country" parameter instead of a filter clause * (used by DXCC). */ class BandTableAward : public AwardDefinition { public: QWidget* createWidget(QWidget *parent) override; void updateData(const AwardFilterParams ¶ms) override; ConditionResult getConditionSelected(const QModelIndex &clickedIndex) const override; protected: // =================================================================== // REQUIRED — every subclass must implement these three methods // =================================================================== /* SQL fragment for the SELECT clause that defines the two label columns. * * Must return exactly two expressions aliased as "col1" and "col2". * col1 is the primary identifier (displayed in the first column). * col2 is a secondary label (displayed in the second column), or NULL. * * The expressions can reference: * - "d" — the directory/reference table (if using a CTE or lookup table) * - "c" — the source_contacts table * - "s", "p", "w" — any alias used in sqlDetailTable() * * entity - the selected DXCC entity ID (may be unused if entityInputEnabled() == false) * * Examples: * "d.n col1, null col2" — WAZ (zone number, no secondary) * "translate_to_locale(d.name) col1, d.prefix col2" — DXCC (country name + prefix) * "p.reference col1, p.name col2" — POTA (park reference + park name) */ virtual QString headersColumns(const QString &entity) const = 0; /* SQL fragment starting with FROM that defines the source tables and joins. * * This is inserted into the detail_table CTE after the SELECT clause. * Must join to "source_contacts c" and "modes m" (m.dxcc is used for mode filtering). * * IMPORTANT: Must NOT contain a WHERE clause at the outer level. * The SQL template adds "WHERE 1=1" automatically after this fragment, * followed by additionalWhere(). Place entity filtering in the JOIN ON * conditions, and any other WHERE-level filters in additionalWhere(). * * The join to source_contacts can be: * - LEFT OUTER JOIN -- when all possible entities should appear (even unworked ones). * Use this for awards with a fixed set of targets (DXCC, WAZ, WAC, WAS, ITU). * - INNER JOIN -- when only worked entities should appear. * Use this for open-ended awards (WPX, IOTA, POTA, SOTA, WWFF, Gridsquare). * * entity - the selected DXCC entity ID * * Examples: * " FROM cqzCTE d" * " LEFT OUTER JOIN source_contacts c ON d.n = c.cqz AND c.my_dxcc = ''" * " LEFT OUTER JOIN modes m ON c.mode = m.name" * * " FROM sota_summits s" * " INNER JOIN source_contacts c ON c.sota_ref = s.summit_code" * " INNER JOIN modes m ON c.mode = m.name" */ virtual QString sqlDetailTable(const QString &entity) const = 0; /* Extra WHERE conditions appended to the detail_table query. * * The SQL template always emits "WHERE 1=1" before this fragment, * so sqlDetailTable() must NOT contain its own WHERE clause. * * Must start with " AND " if non-empty. Return empty QString() if not needed. * * Use this for: * - filtering the directory/reference table (LEFT OUTER JOIN awards) * - requiring non-null fields (INNER JOIN awards) * Do NOT duplicate entity filters that are already in sqlDetailTable's JOIN ON. * * entity - the selected DXCC entity ID * * Examples: * " AND d.dxcc IN (6, 110, 291)" -- filter directory table * " AND c.iota is not NULL" -- require non-null field * QString() -- no extra filter (SOTA, WWFF) */ virtual QString additionalWhere(const QString &entity) const = 0; // =================================================================== // OPTIONAL — override only when the default behavior is not enough // =================================================================== /* Return additional CTEs to prepend before source_contacts. * * Override this when the award needs a reference table that doesn't exist * in the database (e.g. a numbered range for zones, a values list for continents, * or a split CTE for comma-separated fields). * * Each string in the list is a single CTE definition (without leading comma). * Default: empty list. * * Use the static helper methods to build CTEs: * - generateNumberRangeCTE() — for ITU (1-90), WAZ (1-40) * - generateValuesCTE() — for WAC continents * - generateSplitCTE() — for POTA (comma-separated references) * * entity - the selected DXCC entity ID * contactFilter - the user filter WHERE clause (needed by split CTEs) */ virtual QStringList additionalCTEs(const QString &entity, const QString &contactFilter) const; /* Override the default source_contacts CTE. * * By default, source_contacts is: SELECT * FROM contacts WHERE 1=1 . * Override this when the award needs a transformed contact source (e.g. POTA splits * comma-separated references into individual rows). * * Return empty QString() to use the default. Otherwise return a complete CTE definition * for "source_contacts AS (...)". * * contactFilter - the user filter WHERE clause * * See generateSplitSourceContacts() — helper for the split pattern. */ virtual QString sourceContactsOverride(const QString &contactFilter) const; /* Return a SQL WHERE fragment for logbook filtering on double-click. * * Called when the user double-clicks a detail row. The returned string is * combined with entity filter and band into a complete WHERE clause. * * col1Value - value from column 1 (the primary identifier) * col2Value - value from column 2 (the secondary label) * * Examples: * "cqz = '15'" — WAZ: filter by CQ zone * "sota_ref = 'OE/TI-001'" — SOTA: filter by summit * "pota_ref LIKE '%K-0001%'" — POTA: LIKE match for multi-ref field * "state = 'CA' and dxcc in (...)" — WAS: compound filter */ virtual QString clickFilter(const QString &col1Value, const QString &col2Value) const; /* Return true if col1 is a country name to be passed as the "country" * parameter of AwardConditionSelected (instead of a filter clause). * Only DXCC uses this. Default: false. */ virtual bool clickUsesCountryName() const; // =================================================================== // STATIC HELPERS — use these in additionalCTEs() / sourceContactsOverride() // =================================================================== /* Generate a recursive CTE that produces integers from min to max. * Output columns: n (the integer), value (same as n). * Example: generateNumberRangeCTE("cqzCTE", 1, 40) produces zones 1-40. */ static QString generateNumberRangeCTE(const QString &name, int min, int max); /* Generate a VALUES CTE from a list of (key, label) pairs. * Output columns: column1 (key), column2 (label). * Example: generateValuesCTE("continents", {{"NA","North America"}, {"EU","Europe"}, ...}) */ static QString generateValuesCTE(const QString &name, const QList> &values); /* Generate a recursive split CTE that expands comma-separated values * from sourceColumn into individual rows with column outputColumn. * * Used for POTA where pota_ref or my_pota_ref may contain "K-0001,K-0002". * The CTE is named "split" and should be paired with generateSplitSourceContacts(). * * sourceColumn - the contacts table column to split (e.g. "pota_ref") * outputColumn - the name for the split output column (e.g. "pota") * contactFilter - the user filter WHERE clause */ static QString generateSplitCTE(const QString &sourceColumn, const QString &outputColumn, const QString &contactFilter); /* Generate a source_contacts CTE that reads from the "split" CTE. * Companion to generateSplitCTE(). Returns a CTE definition for source_contacts * that selects non-empty rows from the split result. * outputColumn - must match the outputColumn used in generateSplitCTE(). */ static QString generateSplitSourceContacts(const QString &outputColumn); private: QTableView *m_tableView = nullptr; AwardsTableModel *m_model = nullptr; QString m_currentEntity; }; #endif // QLOG_AWARDS_BANDTABLEAWARD_H foldynl-QLog-3252ff9/awards/SecondarySubdivisionAward.cpp000066400000000000000000000021661517334601000235020ustar00rootroot00000000000000#include "SecondarySubdivisionAward.h" SecondarySubdivisionAward::SecondarySubdivisionAward(const QString &key, const QString &dxccFilter) : m_key(key), m_dxccFilter(dxccFilter) { } QString SecondarySubdivisionAward::headersColumns(const QString &) const { return QStringLiteral("d.subdivision_name col1, d.code col2 "); } QString SecondarySubdivisionAward::sqlDetailTable(const QString &) const { return " FROM adif_enum_secondary_subdivision d " " LEFT OUTER JOIN (SELECT * FROM source_contacts " " WHERE dxcc IN (" + m_dxccFilter + ") " " AND cnty IS NOT NULL AND cnty != '') c " " ON d.dxcc = c.dxcc AND upper(d.code) = upper(c.cnty) " " LEFT OUTER JOIN modes m ON c.mode = m.name "; } QString SecondarySubdivisionAward::additionalWhere(const QString &) const { return " AND d.dxcc IN (" + m_dxccFilter + ") "; } QString SecondarySubdivisionAward::clickFilter(const QString &, const QString &col2Value) const { return QString("upper(cnty) = upper('%1') and dxcc in (%2)").arg(col2Value, m_dxccFilter); } foldynl-QLog-3252ff9/awards/SecondarySubdivisionAward.h000066400000000000000000000021001517334601000231330ustar00rootroot00000000000000#ifndef QLOG_AWARDS_SECONDARYSUBDIVISIONAWARD_H #define QLOG_AWARDS_SECONDARYSUBDIVISIONAWARD_H #include "BandTableAward.h" /* Base class for awards based on adif_enum_secondary_subdivision table. * * These awards share identical SQL structure — only the DXCC entity filter, * display name, and key differ. Subclasses only need to provide identity * (key, displayName) and the DXCC filter via constructor. */ class SecondarySubdivisionAward : public BandTableAward { public: SecondarySubdivisionAward(const QString &key, const QString &dxccFilter); QString key() const override { return m_key; } bool entityInputEnabled() const override { return false; } protected: QString headersColumns(const QString &entity) const override; QString sqlDetailTable(const QString &entity) const override; QString additionalWhere(const QString &entity) const override; QString clickFilter(const QString &col1Value, const QString &col2Value) const override; private: QString m_key; QString m_dxccFilter; }; #endif // QLOG_AWARDS_SECONDARYSUBDIVISIONAWARD_H foldynl-QLog-3252ff9/build/000077500000000000000000000000001517334601000154625ustar00rootroot00000000000000foldynl-QLog-3252ff9/build/README.md000066400000000000000000000000551517334601000167410ustar00rootroot00000000000000this directory is only for the build process foldynl-QLog-3252ff9/core/000077500000000000000000000000001517334601000153135ustar00rootroot00000000000000foldynl-QLog-3252ff9/core/AlertEvaluator.cpp000066400000000000000000000335721517334601000207630ustar00rootroot00000000000000#include #include #include #include "AlertEvaluator.h" #include "debug.h" #include "data/DxSpot.h" #include "data/WsjtxEntry.h" #include "data/SpotAlert.h" #include "data/BandPlan.h" MODULE_IDENTIFICATION("qlog.ui.alertevaluator"); AlertEvaluator::AlertEvaluator(QObject *parent) : QObject(parent) { FCT_IDENTIFICATION; loadRules(); } void AlertEvaluator::clearRules() { FCT_IDENTIFICATION; qDeleteAll(ruleList); ruleList.clear(); } void AlertEvaluator::dxSpot(const DxSpot & spot) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "DX Spot"; QStringList matchedRules; for ( const AlertRule *rule : static_cast&>(ruleList) ) { qCDebug(runtime) << "Processing " << *rule; if ( rule->match(spot) ) { matchedRules << rule->ruleName; } } if ( matchedRules.size() > 0 ) { SpotAlert alert(matchedRules, spot); emit spotAlert(alert); } } void AlertEvaluator::WSJTXCQSpot(const WsjtxEntry &wsjtx) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "WSJTX CQ Spot"; QStringList matchedRules; for ( const AlertRule *rule : static_cast&>(ruleList) ) { qCDebug(runtime) << "Processing " << *rule; if ( rule->match(wsjtx) ) { matchedRules << rule->ruleName; } } if ( matchedRules.size() > 0 ) { SpotAlert alert(matchedRules, wsjtx); emit spotAlert(alert); } } void AlertEvaluator::loadRules() { FCT_IDENTIFICATION; if ( ruleList.size() > 0 ) { clearRules(); } QSqlQuery ruleStmt; if ( ! ruleStmt.prepare("SELECT rule_name FROM alert_rules") ) { qWarning() << "Cannot prepare select statement"; } else { if ( ruleStmt.exec() ) { while (ruleStmt.next()) { AlertRule *rule; rule = new AlertRule(); if ( rule ) { rule->load(ruleStmt.value(0).toString()); ruleList.append(rule); } } } else { qInfo()<< "Cannot get filters names from DB" << ruleStmt.lastError(); } } } AlertRule::AlertRule(QObject *parent) : QObject(parent), enabled(false), sourceMap(SpotAlert::UKNOWN), dxCountry(-1), dxLogStatusMap(0), spotterCountry(-1), ituz(0), cqz(0), pota(false), sota(false), iota(false), wwff(false), ruleValid(false) { FCT_IDENTIFICATION; } bool AlertRule::save() { FCT_IDENTIFICATION; if ( ruleName.isEmpty() ) { qCDebug(runtime) << "rule name is empty - do not save"; return false; } QSqlQuery insertUpdateStmt; if ( ! insertUpdateStmt.prepare("INSERT INTO alert_rules(rule_name, enabled, source, dx_callsign, dx_country, " "dx_logstatus, dx_continent, spot_comment, mode, band, spotter_country, spotter_continent, dx_member, ituz, cqz, pota, sota, iota, wwff) " " VALUES (:ruleName, :enabled, :source, :dxCallsign, :dxCountry, " ":dxLogstatus, :dxContinent, :spotComment, :mode, :band, :spotterCountry, :spotterContinent, :dxMember, :ituz, :cqz, :pota, :sota, :iota, :wwff) " " ON CONFLICT(rule_name) DO UPDATE SET enabled = :enabled, source = :source, dx_callsign =:dxCallsign, " "dx_country = :dxCountry, dx_logstatus = :dxLogstatus, dx_continent = :dxContinent, spot_comment = :spotComment, " "mode = :mode, band = :band, spotter_country = :spotterCountry, spotter_continent = :spotterContinent, dx_member = :dxMember, ituz = :ituz, cqz = :cqz, pota = :pota, sota = :sota, iota = :iota, wwff = :wwff " " WHERE rule_name = :ruleName")) { qWarning() << "Cannot prepare insert/update Alert Rule statement" << insertUpdateStmt.lastError(); return false; } insertUpdateStmt.bindValue(":ruleName", ruleName); insertUpdateStmt.bindValue(":enabled", enabled); insertUpdateStmt.bindValue(":source", sourceMap); insertUpdateStmt.bindValue(":dxCallsign", dxCallsign); insertUpdateStmt.bindValue(":dxCountry", dxCountry); insertUpdateStmt.bindValue(":dxLogstatus", dxLogStatusMap); insertUpdateStmt.bindValue(":dxContinent", dxContinent); insertUpdateStmt.bindValue(":dxMember", dxMember.join(",")); insertUpdateStmt.bindValue(":spotComment", dxComment); insertUpdateStmt.bindValue(":mode", mode); insertUpdateStmt.bindValue(":band", band); insertUpdateStmt.bindValue(":spotterCountry", spotterCountry); insertUpdateStmt.bindValue(":spotterContinent", spotterContinent); insertUpdateStmt.bindValue(":cqz", cqz); insertUpdateStmt.bindValue(":ituz", ituz); insertUpdateStmt.bindValue(":pota", pota); insertUpdateStmt.bindValue(":sota", sota); insertUpdateStmt.bindValue(":iota", iota); insertUpdateStmt.bindValue(":wwff", wwff); if ( ! insertUpdateStmt.exec() ) { qCDebug(runtime)<< "Cannot Update Alert Rules - " << insertUpdateStmt.lastError().text(); return false; } return true; } bool AlertRule::load(const QString &in_ruleName) { FCT_IDENTIFICATION; qCDebug(function_parameters) << in_ruleName; QSqlQuery query; if ( ! query.prepare("SELECT rule_name, enabled, source, dx_callsign, dx_country, dx_logstatus, " "dx_continent, spot_comment, mode, band, spotter_country, spotter_continent, dx_member, ituz, cqz, pota, sota, iota, wwff " "FROM alert_rules " "WHERE rule_name = :rule") ) { qWarning() << "Cannot prepare select statement"; return false; } query.bindValue(":rule", in_ruleName); if ( query.exec() ) { query.next(); QSqlRecord record = query.record(); ruleName = in_ruleName; enabled = record.value("enabled").toBool(); sourceMap = record.value("source").toInt(); dxCallsign = record.value("dx_callsign").toString(); dxCountry = record.value("dx_country").toInt(); dxLogStatusMap = record.value("dx_logstatus").toInt(); dxContinent = record.value("dx_continent").toString(); dxComment = record.value("spot_comment").toString(); dxMember = record.value("dx_member").toString().split(","); #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) dxMemberSet = QSet(dxMember.begin(), dxMember.end()); #else /* Due to ubuntu 20.04 where qt5.12 is present */ dxMemberSet = QSet(QSet::fromList(dxMember)); #endif mode = record.value("mode").toString(); band = record.value("band").toString(); spotterCountry = record.value("spotter_country").toInt(); spotterContinent = record.value("spotter_continent").toString(); ituz = record.value("ituz").toInt(); cqz = record.value("cqz").toInt(); pota = record.value("pota").toBool(); sota = record.value("sota").toBool(); iota = record.value("iota").toBool(); wwff = record.value("wwff").toBool(); callsignRE.setPattern(dxCallsign); callsignRE.setPatternOptions(QRegularExpression::CaseInsensitiveOption); commentRE.setPattern(dxComment); commentRE.setPatternOptions(QRegularExpression::CaseInsensitiveOption); } else { qCDebug(runtime) << "SQL execution error: " << query.lastError().text(); return false; } qCDebug(runtime) << "Rule: " << ruleName << " was loaded"; ruleValid = true; return true; } bool AlertRule::match(const WsjtxEntry &wsjtx) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << wsjtx; auto fail = [&]() -> bool { qCDebug(runtime) << "Rule name:" << ruleName << "- result false"; return false; }; /* the first part validates a primitive types */ if ( !isValid() || !enabled ) return fail(); if ( !(sourceMap & SpotAlert::WSJTXCQSPOT) ) return fail(); if ( dxCountry && dxCountry != wsjtx.dxcc.dxcc ) return fail(); if ( ituz && ituz != wsjtx.dxcc.ituz ) return fail(); if ( cqz && cqz != wsjtx.dxcc.cqz ) return fail(); if ( pota || sota || iota || wwff ) { const bool refMatch = (pota && wsjtx.containsPOTA) || (sota && wsjtx.containsSOTA) || (iota && wsjtx.containsIOTA) || (wwff && wsjtx.containsWWFF); if ( !refMatch ) return fail(); } if ( !(wsjtx.status & dxLogStatusMap) ) return fail(); if ( mode != "*" ) { const QString &group = BandPlan::isFTxMode(wsjtx.decodedMode) ? BandPlan::MODE_GROUP_STRING_FTx : BandPlan::MODE_GROUP_STRING_DIGITAL; if ( !mode.contains(QLatin1Char('|') + group) ) return fail(); } if ( band != "*" && !band.contains(QLatin1Char('|') + wsjtx.band) ) return fail(); if ( spotterCountry && spotterCountry != wsjtx.dxcc_spotter.dxcc) return fail(); if ( dxContinent != "*" && !dxContinent.contains(QLatin1Char('|') + wsjtx.dxcc.cont)) return fail(); if ( spotterContinent != "*" && !spotterContinent.contains(QLatin1Char('|') + wsjtx.dxcc_spotter.cont)) return fail(); if ( !(dxMember.size() == 1 && dxMember.front() == QLatin1String("*"))) { if ( !wsjtx.memberList2Set().intersects(dxMemberSet) ) return fail(); } qCDebug(runtime) << "Rule match - phase 1 - OK"; qCDebug(runtime) << "Callsign RE" << callsignRE.pattern(); qCDebug(runtime) << "Comment RE" << commentRE.pattern(); const bool ret = callsignRE.match(wsjtx.callsign).hasMatch() && commentRE.match(wsjtx.decode.message).hasMatch(); qCDebug(runtime) << "Rule name: " << ruleName << " - result " << ret; return ret; } bool AlertRule::match(const DxSpot &spot) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << spot; auto fail = [&]() -> bool { qCDebug(runtime) << "Rule name:" << ruleName << "- result false"; return false; }; /* the first part validates a primitive types */ if ( !isValid() || !enabled ) return fail(); if ( !(sourceMap & SpotAlert::DXSPOT) ) return fail(); if ( dxCountry != 0 && dxCountry != spot.dxcc.dxcc ) return fail(); if ( ituz != 0 && ituz != spot.dxcc.ituz ) return fail(); if ( cqz != 0 && cqz != spot.dxcc.cqz ) return fail(); if ( pota || sota || iota || wwff ) { const bool refMatch = (pota && spot.containsPOTA) || (sota && spot.containsSOTA) || (iota && spot.containsIOTA) || (wwff && spot.containsWWFF); if ( !refMatch ) return fail(); } if ( !(spot.status & dxLogStatusMap) ) return fail(); if ( mode != "*" ) { if (spot.modeGroupString.isEmpty()) return fail(); if (!mode.contains(QLatin1Char('|') + spot.modeGroupString)) return fail(); } if ( band != "*" ) { if (spot.band.isEmpty()) return fail(); if (!band.contains(QLatin1Char('|') + spot.band)) return fail(); } if ( spotterCountry != 0 && spotterCountry != spot.dxcc_spotter.dxcc ) return fail(); if ( dxContinent != "*" ) { if ( spot.dxcc.cont.isEmpty() ) return fail(); if ( !dxContinent.contains(QLatin1Char('|') + spot.dxcc.cont) ) return fail(); } if ( spotterContinent != "*" ) { if ( spot.dxcc_spotter.cont.isEmpty() ) return fail(); if ( !spotterContinent.contains(QLatin1Char('|') + spot.dxcc_spotter.cont) ) return fail(); } if ( !(dxMember.size() == 1 && dxMember.front() == QLatin1String("*")) ) { if (!spot.memberList2Set().intersects(dxMemberSet)) return fail(); } qCDebug(runtime) << "Rule match - phase 1 - OK"; qCDebug(runtime) << "Callsign RE" << callsignRE.pattern(); qCDebug(runtime) << "Comment RE" << commentRE.pattern(); const bool ret = callsignRE.match(spot.callsign).hasMatch() && commentRE.match(spot.comment).hasMatch(); qCDebug(runtime) << "Rule name:" << ruleName << "- result" << ret; return ret; } bool AlertRule::isValid() const { FCT_IDENTIFICATION; return ruleValid; } AlertRule::operator QString() const { return QString("AlerRule: ") + "(" + "Rule Name: " + ruleName + "; " + "isValid: " + QString::number(isValid()) + "; " + "Enabled: " + QString::number(enabled) + "; " + "SourceMap: 0b" + QString::number(sourceMap,2) + "; " + "dxCallsign: " + dxCallsign + "; " + "CQZ: " + QString::number(cqz) + "; " + "ITUZ: " + QString::number(ituz) + "; " + "POTA: " + (pota ? "true" : "false") + "; " + "SOTA: " + (sota ? "true" : "false") + "; " + "IOTA: " + (iota ? "true" : "false") + "; " + "WWFF: " + (wwff ? "true" : "false") + "; " + "dxMember: " + dxMember.join(", ") + "; " + "dxCountry: " + QString::number(dxCountry) + "; " + "dxLogStatusMap: 0b" + QString::number(dxLogStatusMap,2) + "; " + "dxComment: " + dxComment + "; " + "mode: " + mode + "; " + "band: " + band + "; " + "spotterCountry: " + QString::number(spotterCountry) + "; " + "spotterContinent: " + spotterContinent + "; " + ")"; } foldynl-QLog-3252ff9/core/AlertEvaluator.h000066400000000000000000000026731517334601000204260ustar00rootroot00000000000000#ifndef QLOG_CORE_ALERTEVALUATOR_H #define QLOG_CORE_ALERTEVALUATOR_H #include #include "data/DxSpot.h" #include "data/WsjtxEntry.h" #include "data/SpotAlert.h" #include class AlertRule : public QObject { Q_OBJECT public: explicit AlertRule(QObject *parent = nullptr); ~AlertRule() {}; bool save(); bool load(const QString &); bool match(const WsjtxEntry &wsjtx) const; bool match(const DxSpot & spot) const; bool isValid() const; operator QString() const; public: QString ruleName; bool enabled; int sourceMap; QString dxCallsign; int dxCountry; int dxLogStatusMap; QString dxContinent; QString dxComment; QStringList dxMember; QString mode; QString band; int spotterCountry; QString spotterContinent; int ituz; int cqz; bool pota; bool sota; bool iota; bool wwff; private: bool ruleValid; QRegularExpression callsignRE; QRegularExpression commentRE; QSet dxMemberSet; }; class AlertEvaluator : public QObject { Q_OBJECT public: explicit AlertEvaluator(QObject *parent = nullptr); ~AlertEvaluator() {clearRules();} void clearRules(); public slots: void dxSpot(const DxSpot&); void WSJTXCQSpot(const WsjtxEntry&); void loadRules(); signals: void spotAlert(SpotAlert alert); private: QListruleList; }; #endif // QLOG_CORE_ALERTEVALUATOR_H foldynl-QLog-3252ff9/core/AppGuard.cpp000066400000000000000000000051631517334601000175270ustar00rootroot00000000000000#include #include #if QT_VERSION >= QT_VERSION_CHECK(6,6,0) #include #endif #include "AppGuard.h" #include "debug.h" MODULE_IDENTIFICATION("qlog.core.appguard"); namespace { QString generateKeyHash( const QString& key, const QString& salt ) { QByteArray data; data.append( key.toUtf8() ); data.append( salt.toUtf8() ); data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex(); return data; } } AppGuard::AppGuard( const QString& key ) : key( key ) , memLockKey( generateKeyHash( key, "_memLockKey" ) ) , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) ) , sharedMem( #if QT_VERSION >= QT_VERSION_CHECK(6,6,0) QSharedMemory::legacyNativeKey(sharedmemKey) #else sharedmemKey #endif ) , memLock( #if QT_VERSION >= QT_VERSION_CHECK(6,6,0) QSystemSemaphore::legacyNativeKey(memLockKey), #else memLockKey, #endif 1 ) { FCT_IDENTIFICATION; memLock.acquire(); { // linux / unix shared memory is not freed when the application terminates abnormally, // so you need to get rid of the garbage QSharedMemory fix( #if QT_VERSION >= QT_VERSION_CHECK(6,6,0) QSharedMemory::legacyNativeKey(sharedmemKey) #else sharedmemKey #endif ); if ( fix.attach() ) { fix.detach(); } } memLock.release(); } AppGuard::~AppGuard() { release(); } bool AppGuard::isAnotherRunning(void) { FCT_IDENTIFICATION; if ( sharedMem.isAttached() ) return false; memLock.acquire(); const bool isRunning = sharedMem.attach(); if ( isRunning ) { sharedMem.detach(); } memLock.release(); return isRunning; } bool AppGuard::tryToRun(void) { FCT_IDENTIFICATION; if ( isAnotherRunning() ) // Extra check { return false; } memLock.acquire(); // The following 'attach' call is a workaround required for 'create' to run properly under QT 6.6 and MacOS. // See more details about it in issue #257. // It has no impact on other platforms and versions of Qt, therefore there is no compilation condition. sharedMem.attach(); const bool result = sharedMem.create( sizeof( quint64 ) ); memLock.release(); if ( !result ) { release(); return false; } return true; } void AppGuard::release(void) { FCT_IDENTIFICATION; memLock.acquire(); if ( sharedMem.isAttached() ) { sharedMem.detach(); } memLock.release(); } foldynl-QLog-3252ff9/core/AppGuard.h000066400000000000000000000010151517334601000171640ustar00rootroot00000000000000#ifndef QLOG_CORE_APPGUARD_H #define QLOG_CORE_APPGUARD_H #include #include #include class AppGuard { public: explicit AppGuard( const QString& key ); ~AppGuard(); bool isAnotherRunning(void); bool tryToRun(void); void release(void); private: const QString key; const QString memLockKey; const QString sharedmemKey; QSharedMemory sharedMem; QSystemSemaphore memLock; Q_DISABLE_COPY( AppGuard ) }; #endif // QLOG_CORE_APPGUARD_H foldynl-QLog-3252ff9/core/CallbookManager.cpp000066400000000000000000000152161517334601000210450ustar00rootroot00000000000000#include #include "CallbookManager.h" #include "core/debug.h" #include "service/hamqth/HamQTH.h" #include "service/qrzcom/QRZ.h" #include "data/Callsign.h" #include "LogParam.h" MODULE_IDENTIFICATION("qlog.ui.callbookmanager"); CallbookManager::CallbookManager(QObject *parent) : QObject{parent}, primaryCallbookAuthSuccess(false), secondaryCallbookAuthSuccess(false) { FCT_IDENTIFICATION; initCallbooks(); } void CallbookManager::queryCallsign(const QString &callsign) { FCT_IDENTIFICATION; qCDebug(function_parameters) << callsign; if ( queryCache.contains(callsign) ) { emit callsignResult(CallbookResponseData(*queryCache.object(callsign))); return; } // create an empty object in cache // if there is the second query for the same call immediately after // the first query, then it returns a result of empty object queryCache.insert(callsign, new CallbookResponseData); if ( !primaryCallbook.isNull() ) { currentQueryCallsign = callsign; primaryCallbook->queryCallsign(currentQueryCallsign); } else { queryCache.remove(callsign); emit callsignNotFound(callsign); } } bool CallbookManager::isActive() { FCT_IDENTIFICATION; bool ret = primaryCallbookAuthSuccess || secondaryCallbookAuthSuccess; qCDebug(runtime) << ret; return ret; } GenericCallbook *CallbookManager::createCallbook(const QString &callbookID) { FCT_IDENTIFICATION; GenericCallbook *ret = nullptr; if (callbookID == HamQTHCallbook::CALLBOOK_NAME ) { ret = new HamQTHCallbook(this); } else if ( callbookID == QRZCallbook::CALLBOOK_NAME ) { ret = new QRZCallbook(this); } if ( ret ) { connect(ret, &GenericCallbook::callsignResult, this, &CallbookManager::processCallsignResult); } return ret; } void CallbookManager::initCallbooks() { primaryCallbook.clear(); secondaryCallbook.clear(); primaryCallbookAuthSuccess = false; secondaryCallbookAuthSuccess = false; queryCache.clear(); currentQueryCallsign = QString(); primaryCallbook = createCallbook(LogParam::getPrimaryCallbook(GenericCallbook::CALLBOOK_NAME)); secondaryCallbook = createCallbook(LogParam::getSecondaryCallbook(GenericCallbook::CALLBOOK_NAME)); if ( !primaryCallbook.isNull() ) { connect(primaryCallbook, &GenericCallbook::callsignNotFound, this, &CallbookManager::primaryCallbookCallsignNotFound); connect(primaryCallbook, &GenericCallbook::loginFailed, this, [this]() { primaryCallbookAuthSuccess = false; emit loginFailed(primaryCallbook->getDisplayName()); }); connect(primaryCallbook, &GenericCallbook::lookupError, this, [this](const QString &error) { emit lookupError(primaryCallbook->getDisplayName() + " - " + error + ((!secondaryCallbook.isNull()) ? tr("

The secondary callbook will be used

") : "")); primaryCallbookCallsignNotFound(currentQueryCallsign); }); primaryCallbookAuthSuccess = true; } if ( !secondaryCallbook.isNull() ) { connect(secondaryCallbook, &GenericCallbook::callsignNotFound, this, &CallbookManager::secondaryCallbookCallsignNotFound); connect(secondaryCallbook, &GenericCallbook::loginFailed, this, [this]() { secondaryCallbookAuthSuccess = false; emit loginFailed(secondaryCallbook->getDisplayName()); }); connect(secondaryCallbook, &GenericCallbook::lookupError, this, [this](const QString &error) { emit lookupError(secondaryCallbook->getDisplayName() + " - " + error); secondaryCallbookCallsignNotFound(currentQueryCallsign); }); secondaryCallbookAuthSuccess = true; } } void CallbookManager::abortQuery() { FCT_IDENTIFICATION; queryCache.remove(currentQueryCallsign); if ( ! primaryCallbook.isNull() ) primaryCallbook->abortQuery(); if ( ! secondaryCallbook.isNull() ) secondaryCallbook->abortQuery(); } void CallbookManager::primaryCallbookCallsignNotFound(const QString ¬FoundCallsign) { FCT_IDENTIFICATION; qCDebug(function_parameters) << notFoundCallsign; queryCache.remove(notFoundCallsign); if ( notFoundCallsign != currentQueryCallsign ) return ; if ( secondaryCallbook.isNull() ) { emit callsignNotFound(notFoundCallsign); return; } qCDebug(runtime) << "Callsign not found - primary - trying the secondary callbook"; secondaryCallbook->queryCallsign(notFoundCallsign); } void CallbookManager::secondaryCallbookCallsignNotFound(const QString ¬FoundCallsign) { FCT_IDENTIFICATION; qCDebug(function_parameters) << notFoundCallsign; queryCache.remove(notFoundCallsign); if ( notFoundCallsign != currentQueryCallsign ) return ; qCDebug(runtime) << "Callsign not found - secondary "; emit callsignNotFound(notFoundCallsign); } void CallbookManager::processCallsignResult(const CallbookResponseData &data) { FCT_IDENTIFICATION; CallbookResponseData *cacheData = new CallbookResponseData; *cacheData = data; queryCache.insert(data.call, cacheData); // Callbook returned queried callsign if ( data.call == currentQueryCallsign ) { emit callsignResult(data); return; } Callsign queryCall(currentQueryCallsign); if ( ! queryCall.isValid() ) { qCDebug(runtime) << "Query callsign is not valid " << currentQueryCallsign; return; } // If not exists full match record for example for SP/OK1xxx in a callbook // then callbooks return a partial result (usually base callsign) OK1xxx. In this case, QLog // takes only selected fields from the callbook response. if ( queryCall.getBase() == data.call ) { qCDebug(runtime) << "Partial match for result - forwarding limited set of information"; CallbookResponseData newData; newData.call = currentQueryCallsign; newData.fname = data.fname; newData.lname = data.lname; newData.lic_year = data.lic_year; newData.qsl_via = data.qsl_via; newData.email = data.email; newData.born = data.born; newData.url = data.url; newData.name_fmt = data.name_fmt; newData.nick = data.nick; newData.image_url = data.image_url; CallbookResponseData *cdata = new CallbookResponseData; *cdata = newData; queryCache.insert(currentQueryCallsign, cdata); emit callsignResult(newData); } } QCache CallbookManager::queryCache(100); foldynl-QLog-3252ff9/core/CallbookManager.h000066400000000000000000000021661517334601000205120ustar00rootroot00000000000000#ifndef QLOG_CORE_CALLBOOKMANAGER_H #define QLOG_CORE_CALLBOOKMANAGER_H #include #include #include "service/GenericCallbook.h" class CallbookManager : public QObject { Q_OBJECT public: explicit CallbookManager(QObject *parent = nullptr); void queryCallsign(const QString &callsign); bool isActive(); signals: void loginFailed(QString); void callsignResult(CallbookResponseData); void callsignNotFound(QString); void lookupError(QString); public slots: void initCallbooks(); void abortQuery(); private slots: void primaryCallbookCallsignNotFound(const QString&); void secondaryCallbookCallsignNotFound(const QString&); void processCallsignResult(const CallbookResponseData &data); private: GenericCallbook *createCallbook(const QString&); private: QPointer primaryCallbook; bool primaryCallbookAuthSuccess; QPointer secondaryCallbook; bool secondaryCallbookAuthSuccess; QString currentQueryCallsign; static QCache queryCache; }; #endif // QLOG_CORE_CALLBOOKMANAGER_H foldynl-QLog-3252ff9/core/CredentialStore.cpp000066400000000000000000000224651517334601000211170ustar00rootroot00000000000000#include #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #include #else #include #endif #include #include #include #include #include #include #include "CredentialStore.h" #include "core/debug.h" #include "core/PasswordCipher.h" #include "core/LogParam.h" #include "core/LogDatabase.h" MODULE_IDENTIFICATION("qlog.core.credentialstore"); using namespace QKeychain; CredentialRegistry &CredentialRegistry::instance() { static CredentialRegistry r; return r; } void CredentialRegistry::add(const QString &, const std::function()> &fn) { callbacks.append(fn); } QList CredentialRegistry::allDescriptors() const { FCT_IDENTIFICATION; QList result; for ( const std::function()> &fn : callbacks ) result.append(fn()); return result; } CredentialStore::CredentialStore(QObject *parent) : QObject(parent) { FCT_IDENTIFICATION; } int CredentialStore::savePassword(const QString &storage_key, const QString &user, const QString &pass) { FCT_IDENTIFICATION; qCDebug(function_parameters) << storage_key << " " << user; if ( user.isEmpty() || storage_key.isEmpty() || pass.isEmpty() ) return 1; QString locStorageKey = qApp->applicationName() + ":" + storage_key; QString locUser = user; QString locPass = pass; QEventLoop loop; // write a password to Credential Storage WritePasswordJob job(QLatin1String(locStorageKey.toStdString().c_str())); job.setAutoDelete(false); #ifdef Q_OS_WIN // see more qtkeychain issue #105 locUser.prepend(locStorageKey + ":"); #endif job.setKey(locUser); job.setTextData(locPass); job.connect(&job, &WritePasswordJob::finished, &loop, &QEventLoop::quit); job.start(); loop.exec(); if ( job.error() && job.error() != EntryNotFound ) { QMessageBox::critical(nullptr, QMessageBox::tr("QLog Critical"), QMessageBox::tr("Cannot save a password for %1 to the Credential Store").arg(storage_key) + "

" + job.errorString()); qWarning() << "Cannot save a password. Error " << job.errorString(); return 1; } return 0; } QString CredentialStore::getPassword(const QString &storage_key, const QString &user) { FCT_IDENTIFICATION; qCDebug(function_parameters) << storage_key << " " << user; if ( user.isEmpty() || storage_key.isEmpty() ) return QString(); QString locStorageKey = qApp->applicationName() + ":" + storage_key; QString locUser = user; QString pass; QEventLoop loop; // get a password from Credential Storage ReadPasswordJob job(QLatin1String(locStorageKey.toStdString().c_str())); job.setAutoDelete(false); #ifdef Q_OS_WIN // see more qtkeychain issue #105 locUser.prepend(locStorageKey + ":"); #endif job.setKey(locUser); job.connect(&job, &ReadPasswordJob::finished, &loop, &QEventLoop::quit); job.start(); loop.exec(); pass = job.textData(); if ( job.error() && job.error() != EntryNotFound ) { QMessageBox::critical(nullptr, QMessageBox::tr("QLog Critical"), QMessageBox::tr("Cannot get a password for %1 from the Credential Store").arg(storage_key) + "

" + job.errorString()); qCDebug(runtime) << "Cannot get a password. Error " << job.errorString(); return QString(); } return pass; } void CredentialStore::deletePassword(const QString &storage_key, const QString &user) { FCT_IDENTIFICATION; qCDebug(function_parameters) << storage_key << " " << user; if ( user.isEmpty() || storage_key.isEmpty() ) return; QString locStorageKey = qApp->applicationName() + ":" + storage_key; QString locUser = user; QEventLoop loop; // delete password from Secure Storage DeletePasswordJob job(QLatin1String(locStorageKey.toStdString().c_str())); job.setAutoDelete(false); #ifdef Q_OS_WIN // see more qtkeychain issue #105 locUser.prepend(locStorageKey + ":"); #endif job.setKey(locUser); job.connect(&job, &DeletePasswordJob::finished, &loop, &QEventLoop::quit); job.start(); loop.exec(); return; } bool CredentialStore::exportPasswords(const QString &passphrase) { FCT_IDENTIFICATION; /* * Password storage format: * 1. Build JSON object: * { * "credentials": [ * {"storagekey": "...", "username": "...", "password": "..."}, * ... * ], * "padding": "" * } * 2. Encrypt JSON with AES-256-GCM using passphrase (via PasswordCipher) * 3. Store base64-encoded ciphertext in LogParam ("security/encryptedpasswords") */ const QList list = CredentialRegistry::instance().allDescriptors(); QJsonArray credArray; for ( const CredentialDescriptor &desc : list ) { QString user = desc.usernameFn(); QString pass = getPassword(desc.storageKey, user); if ( !pass.isEmpty() ) { QJsonObject entry; entry["storagekey"] = desc.storageKey; entry["username"] = user; entry["password"] = pass; credArray.append(entry); } } // generate random padding (128-512 bytes) // add this padding to make it more difficult to estimate the length of passwords. unsigned char randLenBuf[2]; if ( RAND_bytes(randLenBuf, 2) != 1 ) { qWarning() << "RAND_bytes failed for padding length"; return false; } int paddingLen = 128 + (static_cast((randLenBuf[0] << 8) | randLenBuf[1]) % (512 - 128 + 1)); QByteArray paddingRaw(paddingLen, '\0'); if ( RAND_bytes(reinterpret_cast(paddingRaw.data()), paddingLen) != 1 ) { qWarning() << "RAND_bytes failed for padding data"; return false; } QString paddingB64 = QString::fromLatin1(paddingRaw.toBase64()); QJsonObject root; root["credentials"] = credArray; root["padding"] = paddingB64; const QByteArray json = QJsonDocument(root).toJson(QJsonDocument::Compact); QByteArray blobB64; if ( !PasswordCipher::encrypt(passphrase, json, blobB64) ) { qWarning() << "Password encryption failed"; return false; } LogParam::setEncryptedPasswords(blobB64); LogParam::setSourcePlatform(LogDatabase::currentPlatformId()); return true; } bool CredentialStore::importPasswords(const QString &passphrase) { FCT_IDENTIFICATION; /* * Import process (reverse of exportPasswords): * 1. Read base64-encoded ciphertext from LogParam ("security/encryptedpasswords") * 2. Decrypt with AES-256-GCM using passphrase (via PasswordCipher) * 3. Parse JSON and restore each credential to the credential store * (padding field is ignored) */ QByteArray blobB64 = LogParam::getEncryptedPasswords(); if ( blobB64.isEmpty() ) { qWarning() << "No encrypted passwords found"; return false; } QByteArray json; if ( !PasswordCipher::decrypt(passphrase, blobB64, json) ) { qWarning() << "Password decryption failed"; return false; } QJsonParseError parseError; QJsonDocument doc = QJsonDocument::fromJson(json, &parseError); if ( parseError.error != QJsonParseError::NoError ) { qWarning() << "JSON parse error:" << parseError.errorString(); return false; } QJsonObject root = doc.object(); QJsonArray credArray = root["credentials"].toArray(); for (const QJsonValue &val : static_cast(credArray)) { QJsonObject entry = val.toObject(); QString storageKey = entry["storagekey"].toString(); QString username = entry["username"].toString(); QString password = entry["password"].toString(); if ( !storageKey.isEmpty() && !username.isEmpty() && !password.isEmpty() ) savePassword(storageKey, username, password); } return true; } void CredentialStore::deleteAllPasswords() { FCT_IDENTIFICATION; const QList list = CredentialRegistry::instance().allDescriptors(); for (const CredentialDescriptor &desc : list) { QString user = desc.usernameFn(); if ( !user.isEmpty() ) deletePassword(desc.storageKey, user); } } void CredentialStore::saveImportPassphrase(const QString &passphrase) { FCT_IDENTIFICATION; // special one-time password when QLog import external DB savePassword(QStringLiteral("ImportPassphrase"), QStringLiteral("import"), passphrase); } QString CredentialStore::getImportPassphrase() { FCT_IDENTIFICATION; // special one-time password when QLog import external DB return getPassword(QStringLiteral("ImportPassphrase"), QStringLiteral("import")); } void CredentialStore::deleteImportPassphrase() { FCT_IDENTIFICATION; // special one-time password when QLog import external DB deletePassword(QStringLiteral("ImportPassphrase"), QStringLiteral("import")); } foldynl-QLog-3252ff9/core/CredentialStore.h000066400000000000000000000111231517334601000205510ustar00rootroot00000000000000#ifndef QLOG_CORE_CREDENTIALSTORE_H #define QLOG_CORE_CREDENTIALSTORE_H #include #include // - Central registry of all services that use the CredentialStore. // - Each service registers its credential descriptor statically at load time // using the DECLARE_SECURE_SERVICE macro. // why: // - QtKeychain does not allow listing all stored passwords. // - To migrate data or validate access, we must know which services exist. // - This registry provides that authoritative list. struct CredentialDescriptor { QString storageKey; // unique key (e.g. "eQSL", "HRDLog") std::function usernameFn; // callback returning the username }; class CredentialRegistry { private: QList()>> callbacks; public: static CredentialRegistry &instance(); // Register a service descriptor callback. // Each service provides a lambda returning one or more CredentialDescriptors. void add(const QString &serviceName, const std::function()> &fn); // Returns all known credential descriptors (collected from all services). QList allDescriptors() const; }; // Macro used in each service to force the presence of registerCredentials() // and to auto-execute it during static initialization. // If the developer forgets to implement registerCredentials(), // linking will fail with "undefined reference". #define DECLARE_SECURE_SERVICE(cls) \ static void registerCredentials(); \ static int cls##ForceRegistration() { \ cls::registerCredentials(); \ return 0; \ } \ static int cls##RegistrationDummy; #define REGISTRATION_SECURE_SERVICE(cls) \ int cls::cls##RegistrationDummy = cls::cls##ForceRegistration() template class SecureServiceBase; // forward declaration // - Provides a single point of access to platform credential storage (QtKeychain). // - Ensures that only registered services can access credentials. // - Protected API: only subclasses (service classes) can call get/save/delete. // - Validation layer: prevents ad-hoc access from unregistered services. class CredentialStore : public QObject { Q_OBJECT template friend class SecureServiceBase; public: static CredentialStore* instance() { static CredentialStore instance; return &instance; }; bool exportPasswords(const QString &passphrase); bool importPasswords(const QString &passphrase); void deleteAllPasswords(); // Methods for storing import passphrase in SecureStore during application restart void saveImportPassphrase(const QString &passphrase); QString getImportPassphrase(); void deleteImportPassphrase(); private: explicit CredentialStore(QObject *parent = nullptr); // Protected methods — accessible only from derived service classes. // Direct use elsewhere is discouraged by design. int savePassword(const QString &storage_key, const QString &user, const QString &pass); QString getPassword(const QString &storage_key, const QString &user); void deletePassword(const QString &storage_key, const QString &user); private: // Verifies that the given service (storage_key) is registered. // Prevents code from querying or saving passwords. //bool isRegisteredService(const QString &storage_key) const; }; // - Base class for all components that manage user credentials. // - Enforces per-service registration and provides a safe API wrapper // for accessing the CredentialStore. // - Prevents ad-hoc direct usage of CredentialStore. // template class SecureServiceBase { public: virtual ~SecureServiceBase() {}; protected: static QString getPassword(const QString &storageKey, const QString &user) { return CredentialStore::instance()->getPassword(storageKey, user); } static void savePassword(const QString &storageKey, const QString &user, const QString &pass) { CredentialStore::instance()->savePassword(storageKey, user, pass); } static void deletePassword(const QString &storageKey, const QString &user) { CredentialStore::instance()->deletePassword(storageKey, user); } SecureServiceBase() { // --- Compile-time enforcement of registerCredentials() existence --- typedef void (*RegFn)(); static_assert( std::is_same::value, "Derived class must implement: DECLARE_SECURE_SERVICE macro;" ); } }; #endif // QLOG_CORE_CREDENTIALSTORE_H foldynl-QLog-3252ff9/core/EmergencyFrequency.cpp000066400000000000000000000022261517334601000216210ustar00rootroot00000000000000#include "EmergencyFrequency.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.emergencyfrequency"); double EmergencyFrequency::TOLERANCE_MHZ = 0.001; const QList &EmergencyFrequency::list() { FCT_IDENTIFICATION; static const QList freqs = { { 3.760, "LSB"}, { 7.110, "LSB"}, { 14.300, "USB"}, { 18.160, "USB"}, { 21.360, "USB"}, { 145.550, "FM"}, { 433.550, "FM"}, }; return freqs; } const EmergencyFreqEntry *EmergencyFrequency::inBand(double startMHz, double endMHz) { FCT_IDENTIFICATION; for ( const EmergencyFreqEntry &entry : list() ) if ( entry.frequency >= startMHz && entry.frequency <= endMHz ) return &entry; return nullptr; } const EmergencyFreqEntry *EmergencyFrequency::findEmergency(double freqMHz) { FCT_IDENTIFICATION; const QList &freqs = EmergencyFrequency::list(); for ( const EmergencyFreqEntry &entry : freqs ) if ( qAbs(freqMHz - entry.frequency) <= EmergencyFrequency::TOLERANCE_MHZ ) return &entry; return nullptr; } foldynl-QLog-3252ff9/core/EmergencyFrequency.h000066400000000000000000000007541517334601000212720ustar00rootroot00000000000000#ifndef QLOG_CORE_EMERGENCYFREQUENCY_H #define QLOG_CORE_EMERGENCYFREQUENCY_H #include struct EmergencyFreqEntry { double frequency; // MHz QString mode; }; class EmergencyFrequency { public: static double TOLERANCE_MHZ; static const QList &list(); static const EmergencyFreqEntry *inBand(double startMHz, double endMHz); static const EmergencyFreqEntry *findEmergency(double freqMHz); }; #endif // QLOG_CORE_EMERGENCYFREQUENCY_H foldynl-QLog-3252ff9/core/FileCompressor.cpp000066400000000000000000000214131517334601000207540ustar00rootroot00000000000000#include #include #include #include #include #include "FileCompressor.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.filecompressor"); QByteArray FileCompressor::gzip(const QByteArray &in) { FCT_IDENTIFICATION; if ( in.isEmpty() ) return {}; z_stream strm{}; // 16 + MAX_WBITS = gzip format if ( deflateInit2(&strm, Z_BEST_SPEED, Z_DEFLATED, 16 + MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK ) return {}; strm.next_in = reinterpret_cast(const_cast(in.data())); strm.avail_in = static_cast(in.size()); QByteArray out; char buf[8192]; int ret; do { strm.next_out = reinterpret_cast(buf); strm.avail_out = sizeof(buf); ret = deflate(&strm, Z_FINISH); if ( ret == Z_OK || ret == Z_STREAM_END ) out.append(buf, static_cast(sizeof(buf) - strm.avail_out)); } while ( ret == Z_OK ); deflateEnd(&strm); return (ret == Z_STREAM_END) ? out : QByteArray{}; } QByteArray FileCompressor::gunzip(const QByteArray &in) { FCT_IDENTIFICATION; if ( in.isEmpty() ) return {}; z_stream strm{}; strm.next_in = reinterpret_cast(const_cast(in.data())); strm.avail_in = static_cast(in.size()); // 16 + MAX_WBITS tells zlib to parse gzip header/footer if ( inflateInit2(&strm, 16 + MAX_WBITS) != Z_OK ) return {}; QByteArray out; char buf[8192]; int ret = Z_OK; while ( ret == Z_OK ) { strm.next_out = reinterpret_cast(buf); strm.avail_out = sizeof(buf); ret = inflate(&strm, Z_NO_FLUSH); if ( ret == Z_OK || ret == Z_STREAM_END ) out.append(buf, static_cast(sizeof(buf) - strm.avail_out)); } inflateEnd(&strm); return out; } bool FileCompressor::gzipFile(const QString &sourceFile, const QString &destFile, const ProgressCallback &progress) { FCT_IDENTIFICATION; qCDebug(function_parameters) << sourceFile << "->" << destFile; QFile source(sourceFile); if ( !source.open(QIODevice::ReadOnly) ) { qWarning() << "Cannot open source file:" << sourceFile; return false; } QFile dest(destFile); if ( !dest.open(QIODevice::WriteOnly) ) { qWarning() << "Cannot create dest file:" << destFile; return false; } const qint64 totalSize = source.size(); // Initialize zlib for gzip compression z_stream strm{}; // 16 + MAX_WBITS = gzip format, if ( deflateInit2(&strm, Z_BEST_SPEED, Z_DEFLATED, 16 + MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK ) { qWarning() << "deflateInit2 failed"; return false; } char inBuffer[65536]; char outBuffer[65536]; qint64 bytesProcessed = 0; bool success = true; int ret; while ( success ) { qint64 bytesRead = source.read(inBuffer, sizeof(inBuffer)); if ( bytesRead < 0 ) { qWarning() << "Read error"; success = false; break; } strm.next_in = reinterpret_cast(inBuffer); strm.avail_in = static_cast(bytesRead); int flush = source.atEnd() ? Z_FINISH : Z_NO_FLUSH; do { strm.next_out = reinterpret_cast(outBuffer); strm.avail_out = sizeof(outBuffer); ret = deflate(&strm, flush); if ( ret == Z_STREAM_ERROR ) { qWarning() << "deflate error"; success = false; break; } qint64 have = sizeof(outBuffer) - strm.avail_out; if ( dest.write(outBuffer, have) != have ) { qWarning() << "Write error"; success = false; break; } } while ( strm.avail_out == 0 && success ); bytesProcessed += bytesRead; if ( progress && !progress(bytesProcessed, totalSize) ) { qCDebug(runtime) << "Compression cancelled by user"; success = false; break; } if ( source.atEnd() ) break; } deflateEnd(&strm); if ( !success || ret != Z_STREAM_END ) { dest.close(); QFile::remove(destFile); return false; } qCDebug(runtime) << "File compressed successfully"; return true; } bool FileCompressor::gunzipFile(const QString &sourceFile, const QString &destFile, const ProgressCallback &progress) { FCT_IDENTIFICATION; qCDebug(function_parameters) << sourceFile << "->" << destFile; QFile source(sourceFile); if ( !source.open(QIODevice::ReadOnly) ) { qWarning() << "Cannot open source file:" << sourceFile; return false; } QFile dest(destFile); if ( !dest.open(QIODevice::WriteOnly) ) { qWarning() << "Cannot create dest file:" << destFile; return false; } const qint64 totalSize = source.size(); // Initialize zlib for gzip decompression z_stream strm{}; // 16 + MAX_WBITS tells zlib to parse gzip header/footer if ( inflateInit2(&strm, 16 + MAX_WBITS) != Z_OK ) { qWarning() << "inflateInit2 failed"; return false; } char inBuffer[65536]; char outBuffer[65536]; qint64 bytesProcessed = 0; bool success = true; int ret = Z_OK; while ( ret != Z_STREAM_END && success ) { qint64 bytesRead = source.read(inBuffer, sizeof(inBuffer)); if ( bytesRead < 0 ) { qWarning() << "Read error"; success = false; break; } if ( bytesRead == 0 ) break; strm.next_in = reinterpret_cast(inBuffer); strm.avail_in = static_cast(bytesRead); do { strm.next_out = reinterpret_cast(outBuffer); strm.avail_out = sizeof(outBuffer); ret = inflate(&strm, Z_NO_FLUSH); if ( ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR ) { qWarning() << "inflate error:" << ret; success = false; break; } qint64 have = sizeof(outBuffer) - strm.avail_out; if ( dest.write(outBuffer, have) != have ) { qWarning() << "Write error"; success = false; break; } } while ( strm.avail_out == 0 && success ); bytesProcessed += bytesRead; if ( progress && !progress(bytesProcessed, totalSize) ) { qCDebug(runtime) << "Decompression cancelled by user"; success = false; break; } } inflateEnd(&strm); if ( !success ) { dest.close(); QFile::remove(destFile); return false; } qCDebug(runtime) << "File decompressed successfully"; return true; } bool FileCompressor::gzipFileWithProgress(const QString &sourceFile, const QString &destFile, QWidget *parent, const QString &title) { FCT_IDENTIFICATION; QProgressDialog progressDialog(title, QString(), 0, 100, parent); progressDialog.setWindowModality(Qt::WindowModal); progressDialog.setMinimumDuration(500); // Show after 500ms progressDialog.setValue(0); FileCompressor::ProgressCallback progressCallback = [&progressDialog](qint64 processed, qint64 total) { if ( total > 0 ) progressDialog.setValue(static_cast(processed * 100 / total)); QCoreApplication::processEvents(); return !progressDialog.wasCanceled(); }; bool result = gzipFile(sourceFile, destFile, progressCallback); progressDialog.setValue(100); return result; } bool FileCompressor::gunzipFileWithProgress(const QString &sourceFile, const QString &destFile, QWidget *parent, const QString &title) { FCT_IDENTIFICATION; QProgressDialog progressDialog(title, QString(), 0, 100, parent); progressDialog.setWindowModality(Qt::WindowModal); progressDialog.setMinimumDuration(500); // Show after 500ms progressDialog.setValue(0); FileCompressor::ProgressCallback progressCallback = [&progressDialog](qint64 processed, qint64 total) { if ( total > 0 ) progressDialog.setValue(static_cast(processed * 100 / total)); QCoreApplication::processEvents(); return !progressDialog.wasCanceled(); }; bool result = gunzipFile(sourceFile, destFile, progressCallback); progressDialog.setValue(100); return result; } foldynl-QLog-3252ff9/core/FileCompressor.h000066400000000000000000000024701517334601000204230ustar00rootroot00000000000000#ifndef QLOG_CORE_FILECOMPRESSOR_H #define QLOG_CORE_FILECOMPRESSOR_H #include #include #include class QWidget; class FileCompressor { public: // Progress callback: (bytesProcessed, totalBytes); return false to cancel using ProgressCallback = std::function; // Compress data using gzip (in-memory) static QByteArray gzip(const QByteArray &in); // Decompress gzip data (in-memory) static QByteArray gunzip(const QByteArray &in); // Compress file using gzip (streaming) static bool gzipFile(const QString &sourceFile, const QString &destFile, const ProgressCallback &progress = nullptr); // Decompress gzip file (streaming) static bool gunzipFile(const QString &sourceFile, const QString &destFile, const ProgressCallback &progress = nullptr); // File compression/decompression with progress dialog static bool gzipFileWithProgress(const QString &sourceFile, const QString &destFile, QWidget *parent, const QString &title); static bool gunzipFileWithProgress(const QString &sourceFile, const QString &destFile, QWidget *parent, const QString &title); }; #endif // QLOG_CORE_FILECOMPRESSOR_H foldynl-QLog-3252ff9/core/FldigiTCPServer.cpp000066400000000000000000000106211517334601000207530ustar00rootroot00000000000000#include #include #include #include #include #include "FldigiTCPServer.h" #include "logformat/AdiFormat.h" #include "debug.h" MODULE_IDENTIFICATION("qlog.core.fldigi"); FldigiTCPServer::FldigiTCPServer(QObject *parent) : QTcpServer(parent) { FCT_IDENTIFICATION; listen(QHostAddress::Any, 8421); } void FldigiTCPServer::incomingConnection(qintptr socket) { FCT_IDENTIFICATION; QTcpSocket* sock = new QTcpSocket(this); connect(sock, &QTcpSocket::readyRead, this, &FldigiTCPServer::readClient); connect(sock, &QTcpSocket::disconnected, this, &FldigiTCPServer::discardClient); sock->setSocketDescriptor(socket); } void FldigiTCPServer::readClient() { FCT_IDENTIFICATION; QTcpSocket* socket = qobject_cast(sender()); if ( !socket ) { qCWarning(runtime) << "socket is null"; return; } QString data = QString(socket->readAll()); qCDebug(runtime) << data; int split = data.indexOf("\r\n\r\n", 0); data.remove(0, split+4); /* WORKAROUND - FLDIGI has probably an issue. It seems that XML * that is generated by FLDIGI contains Processing Instruction (clientid) * without mandatory space */ data.replace("close(); if (socket->state() == QTcpSocket::UnconnectedState) socket->deleteLater(); } void FldigiTCPServer::discardClient() { FCT_IDENTIFICATION; QTcpSocket* socket = qobject_cast(sender()); if ( socket ) socket->deleteLater(); } void FldigiTCPServer::processMethodCall(QTcpSocket* sock, QXmlStreamReader& xml) { FCT_IDENTIFICATION; QByteArray response; while (!xml.atEnd() && !xml.hasError()) { xml.readNextStartElement(); if (xml.name() == QString("methodCall")) { qCDebug(runtime) << "method call"; } if (xml.name() == QString("methodName")) { qCDebug(runtime) << "methodName"; QString method = xml.readElementText(); if (method == "log.add_record") { qCDebug(runtime) << "log.add_record"; QString param = parseParam(xml); if (!param.isEmpty()) { response = addRecord(param); } } else if (method == "system.listMethods") { qCDebug(runtime) << "system.listMethods"; response = listMethods(); } } } qCDebug(runtime) << response; QTextStream out(sock); if (!response.isEmpty()) { out << "HTTP/1.1 200 OK\r\n"; out << "Content-Type: text/xml; charset=utf-8\r\n"; out << "Content-Length: " << response.length() << "\r\n"; out << "\r\n"; out << response; } else { out << "HTTP/1.1 400 Internal Error\r\n"; } } QString FldigiTCPServer::parseParam(QXmlStreamReader& xml) { FCT_IDENTIFICATION; while (!xml.atEnd() && !xml.hasError()) { xml.readNextStartElement(); if (xml.name() == QString("value")) { return xml.readElementText(); } } return QString(); } QByteArray FldigiTCPServer::listMethods() { FCT_IDENTIFICATION; QByteArray out; QXmlStreamWriter xml(&out); xml.writeStartDocument(); xml.writeStartElement("methodResponse"); xml.writeStartElement("params"); xml.writeStartElement("param"); xml.writeStartElement("value"); xml.writeStartElement("array"); xml.writeStartElement("data"); xml.writeTextElement("value", "log.add_record"); xml.writeTextElement("value", "system.listMethods"); xml.writeEndDocument(); return out; } QByteArray FldigiTCPServer::addRecord(QString data) { FCT_IDENTIFICATION; qCDebug(function_parameters) << data; QByteArray out; QXmlStreamWriter xml(&out); xml.writeStartDocument(); xml.writeStartElement("methodResponse"); xml.writeStartElement("params"); xml.writeStartElement("param"); xml.writeStartElement("value"); xml.writeEndDocument(); QSqlTableModel model; model.setTable("contacts"); model.removeColumn(model.fieldIndex("id")); QSqlRecord record = model.record(0); QTextStream in(&data); AdiFormat adif(in); adif.importNext(record); emit addContact(record); return out; } foldynl-QLog-3252ff9/core/FldigiTCPServer.h000066400000000000000000000011771517334601000204260ustar00rootroot00000000000000#ifndef QLOG_CORE_FLDIGI_H #define QLOG_CORE_FLDIGI_H #include #include class QXmlStreamReader; class FldigiTCPServer : public QTcpServer { Q_OBJECT public: explicit FldigiTCPServer(QObject *parent = nullptr); signals: void addContact(QSqlRecord); public slots: void readClient(); void discardClient(); private: void processMethodCall(QTcpSocket* sock, QXmlStreamReader& xml); QString parseParam(QXmlStreamReader& xml); QByteArray listMethods(); QByteArray addRecord(QString data); void incomingConnection(qintptr socket) override; }; #endif // QLOG_CORE_FLDIGI_H foldynl-QLog-3252ff9/core/LOVDownloader.cpp000066400000000000000000001072461517334601000205100ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "LogParam.h" #include "LOVDownloader.h" #include "FileCompressor.h" #include "debug.h" #include "data/Data.h" #include "core/csv.hpp" #include "core/FileCompressor.h" MODULE_IDENTIFICATION("qlog.core.lovdownloader"); LOVDownloader::LOVDownloader(QObject *parent) : QObject(parent), currentReply(nullptr), abortRequested(false), CTYPrefixSeperatorRe("[\\s;]"), CTYPrefixFormatRe("(=?)([A-Z0-9/]+)(?:\\((\\d+)\\))?(?:\\[(\\d+)\\])?$") { FCT_IDENTIFICATION; nam = new QNetworkAccessManager(this); connect(nam, &QNetworkAccessManager::finished, this, &LOVDownloader::processReply); } LOVDownloader::~LOVDownloader() { FCT_IDENTIFICATION; } void LOVDownloader::update(const SourceType & sourceType, bool force) { FCT_IDENTIFICATION; abortRequested = false; const SourceDefinition &sourceDef = sourceMapping[sourceType]; Q_ASSERT(sourceDef.type == sourceType); QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); const QDate &last_update = LogParam::getLOVaParam(sourceDef.lastTimeConfigName); if ( !force && dir.exists(sourceDef.fileName) && last_update.isValid() && last_update.daysTo(QDate::currentDate()) < sourceDef.ageTime ) { if ( isTableFilled(sourceDef.tableName) ) { // nothing to do. qCDebug(runtime) << "Not needed to update " << sourceDef.fileName; emit noUpdate(); return; } qCDebug(runtime) << "using cached " << sourceDef.fileName << " at" << dir.path(); QTimer::singleShot(0, this, [this, sourceDef]() {loadData(sourceDef);}); } else { qCDebug(runtime) << sourceDef.fileName << " is too old or not exist - downloading"; download(sourceDef); } } void LOVDownloader::abortRequest() { FCT_IDENTIFICATION; if ( currentReply ) { currentReply->abort(); currentReply = nullptr; } abortRequested = true; } void LOVDownloader::loadData(const LOVDownloader::SourceDefinition &sourceDef) { FCT_IDENTIFICATION; const QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); QFile file(dir.filePath(sourceDef.fileName)); if ( ! file.open(QIODevice::ReadOnly) ) { qWarning() << "Cannot open" << dir.filePath(sourceDef.fileName); return; } QByteArray data = file.readAll(); file.close(); if (sourceDef.fileName.endsWith(".gz", Qt::CaseInsensitive)) data = FileCompressor::gunzip(data); emit processingSize(data.size()); QTextStream stream(data); parseData(sourceDef, stream); emit finished(true); } bool LOVDownloader::isTableFilled(const QString &tableName) { FCT_IDENTIFICATION; qCDebug(function_parameters) << tableName; QSqlQuery query(QString("select exists( select 1 from %1)").arg(tableName)); int i = query.first() ? query.value(0).toInt() : 0; qCDebug(runtime) << i; return i==1; } bool LOVDownloader::deleteTable(const QString &tableName) { FCT_IDENTIFICATION; qCDebug(function_parameters) << tableName; QSqlQuery query; QString queryStatement("delete from %1"); if ( ! query.exec(queryStatement.arg(tableName)) ) { qWarning() << "Cannot delete " << tableName << query.lastError(); return false; } return true; } void LOVDownloader::download(const LOVDownloader::SourceDefinition &sourceDef) { FCT_IDENTIFICATION; QUrl url(sourceDef.URL); QNetworkRequest request(url); QString rheader = QString("QLog/%1").arg(VERSION); request.setRawHeader("User-Agent", rheader.toUtf8()); if ( currentReply ) { qCWarning(runtime) << "processing a new request but the previous one hasn't been completed yet !!!"; } currentReply = nam->get(request); currentReply->setProperty("sourceType", sourceDef.type); qCDebug(runtime) << "Downloading " << sourceDef.fileName << "from " << url.toString(); } void LOVDownloader::parseData(const SourceDefinition &sourceDef, QTextStream &data) { FCT_IDENTIFICATION; qCDebug(runtime) << "Parsing file " << sourceDef.fileName; switch ( sourceDef.type ) { case CTY: parseCTY(sourceDef, data); break; case SATLIST: parseSATLIST(sourceDef, data); break; case SOTASUMMITS: parseSOTASummits(sourceDef, data); break; case WWFFDIRECTORY: parseWWFFDirectory(sourceDef, data); break; case IOTALIST: parseIOTA(sourceDef, data); break; case POTADIRECTORY: parsePOTA(sourceDef, data); break; case MEMBERSHIPCONTENTLIST: parseMembershipContent(sourceDef, data); break; case CLUBLOGCTY: parseClubLogCTY(sourceDef, data); break; default: qWarning() << "Unssorted type to download" << sourceDef.type << sourceDef.fileName; } } void LOVDownloader::parseCTY(const SourceDefinition &sourceDef, QTextStream &data) { FCT_IDENTIFICATION; QRegularExpressionMatch matchExp; QSqlDatabase::database().transaction(); if ( ! deleteTable("dxcc_prefixes_ad1c") ) { qCWarning(runtime) << "dxcc_prefixes_ad1c delete failed - rollback"; QSqlDatabase::database().rollback(); return; } if ( ! deleteTable(sourceDef.tableName) ) { qCWarning(runtime) << sourceDef.tableName << " delete failed - rollback"; QSqlDatabase::database().rollback(); return; } QSqlQuery insertEntityQuery; if ( ! insertEntityQuery.prepare("INSERT INTO dxcc_entities_ad1c (id," " name," " prefix," " cont," " cqz," " ituz," " lat," " lon," " tz) " " VALUES ( :id," " :name," " :prefix," " :cont," " :cqz," " :ituz," " :lat," " :lon," " :tz)") ) { qWarning() << "cannot prepare Insert statement - Entity"; abortRequested = true; } QSqlQuery insertPrefixesQuery; if ( ! insertPrefixesQuery.prepare("INSERT INTO dxcc_prefixes_ad1c (" " prefix," " exact," " dxcc," " cqz," " ituz) " " VALUES ( :prefix," " :exact," " :dxcc," " :cqz," " :ituz)") ) { qWarning() << "cannot prepare Insert statement - Prefixes"; abortRequested = true; } unsigned int count = 0; while ( !data.atEnd() && !abortRequested ) { const QString &line = data.readLine(); const QStringList &fields = line.split(','); if ( fields.count() != 10 ) { qCDebug(runtime) << "Invalid line in the input file " << line; continue; } else if ( fields.at(0).startsWith("*") ) continue; qCDebug(runtime) << fields; int dxcc_id = fields.at(2).toInt(); insertEntityQuery.bindValue(":id", dxcc_id); insertEntityQuery.bindValue(":prefix", fields.at(0)); insertEntityQuery.bindValue(":name", fields.at(1)); insertEntityQuery.bindValue(":cont", fields.at(3)); insertEntityQuery.bindValue(":cqz", fields.at(4)); insertEntityQuery.bindValue(":ituz", fields.at(5)); insertEntityQuery.bindValue(":lat", fields.at(6).toFloat()); insertEntityQuery.bindValue(":lon", -fields.at(7).toFloat()); insertEntityQuery.bindValue(":tz", fields.at(8).toFloat()); if ( ! insertEntityQuery.exec() ) { qWarning() << "DXCC Entity insert error " << insertEntityQuery.lastError().text() << insertEntityQuery.lastQuery(); qCDebug(runtime) << fields; abortRequested = true; continue; } else count++; #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) const QStringList &prefixList = fields.at(9).split(CTYPrefixSeperatorRe, Qt::SkipEmptyParts); #else /* Due to ubuntu 20.04 where qt5.12 is present */ const QStringList &prefixList = fields.at(9).split(CTYPrefixSeperatorRe, QString::SkipEmptyParts); #endif qCDebug(runtime) << prefixList; QStringList dup; for ( auto &prefix : prefixList ) { matchExp = CTYPrefixFormatRe.match(prefix); if ( matchExp.hasMatch() ) { // removing duplicities in CTY file. const QString &pfx = matchExp.captured(2); if ( !dup.contains(pfx) ) { dup << pfx; insertPrefixesQuery.bindValue(":prefix", pfx); insertPrefixesQuery.bindValue(":exact", !matchExp.captured(1).isEmpty()); insertPrefixesQuery.bindValue(":dxcc", dxcc_id); insertPrefixesQuery.bindValue(":cqz", matchExp.captured(3).toInt()); insertPrefixesQuery.bindValue(":ituz", matchExp.captured(4).toInt()); if ( ! insertPrefixesQuery.exec() ) { qWarning() << "DXCC Prefix insert error " << insertPrefixesQuery.lastError().text() << insertPrefixesQuery.lastQuery(); qCDebug(runtime) << prefix << prefixList; abortRequested = true; } } else qCDebug(runtime) << "Removing non-unique prefix" << pfx; } else qCDebug(runtime) << "Failed to match " << prefix; } if ( count% 20 == 0 ) { emit progress(data.pos()); QCoreApplication::processEvents(); } emit progress(data.pos()); QCoreApplication::processEvents(); } if ( !abortRequested ) { qCDebug(runtime) << "DXCC update finished:" << count << "entities loaded."; QSqlDatabase::database().commit(); } else { //can be a result of abort qCWarning(runtime) << "DXCC update failed - rollback"; QSqlDatabase::database().rollback(); } } void LOVDownloader::parseSATLIST(const SourceDefinition &sourceDef, QTextStream &data) { FCT_IDENTIFICATION; QSqlDatabase::database().transaction(); if ( ! deleteTable(sourceDef.tableName) ) { qCWarning(runtime) << "Satlist delete failed - rollback"; QSqlDatabase::database().rollback(); return; } QSqlTableModel entityTableModel; entityTableModel.setTable(sourceDef.tableName); entityTableModel.setEditStrategy(QSqlTableModel::OnManualSubmit); QSqlRecord entityRecord = entityTableModel.record(); int count = 0; while ( !data.atEnd() && !abortRequested ) { QString line = data.readLine(); QStringList fields = line.split(';'); if ( fields.count() != 8 ) { qCDebug(runtime) << "Invalid line in the input file " << line; continue; } qCDebug(runtime) << fields; entityRecord.clearValues(); entityRecord.setValue("name", fields.at(0)); entityRecord.setValue("number", fields.at(1)); entityRecord.setValue("uplink", fields.at(2)); entityRecord.setValue("downlink", fields.at(3)); entityRecord.setValue("beacon", fields.at(4)); entityRecord.setValue("mode", fields.at(5)); entityRecord.setValue("callsign", fields.at(6)); entityRecord.setValue("status", fields.at(7)); if ( !entityTableModel.insertRecord(-1, entityRecord) ) { qWarning() << "Cannot insert a record to SATList Table - " << entityTableModel.lastError(); qCDebug(runtime) << entityRecord; } else { count++; } emit progress(data.pos()); QCoreApplication::processEvents(); } if ( entityTableModel.submitAll() && !abortRequested ) { QSqlDatabase::database().commit(); qCDebug(runtime) << "Satlist update finished:" << count << "entities loaded."; } else { //can be a result of abort qCWarning(runtime) << "Satlist update failed - rollback" << entityTableModel.lastError(); QSqlDatabase::database().rollback(); } } bool LOVDownloader::parseCSVGeneric(const SourceDefinition &sourceDef, QTextStream &data, const QString &insertSQL, const QStringList &csvColumns, csv::CSVFormat format, const QString &preValidateContains) { FCT_IDENTIFICATION; const std::string csvData = data.readAll().toStdString(); const qint64 totalBytes = static_cast(csvData.size()); const int totalRows = qMax(1, static_cast( std::count(csvData.begin(), csvData.end(), '\n'))); if ( !preValidateContains.isEmpty() && csvData.find(preValidateContains.toStdString()) == std::string::npos ) { qWarning() << "Unexpected file header for" << sourceDef.tableName; return false; } QSqlDatabase::database().transaction(); if ( !deleteTable(sourceDef.tableName) ) { qCWarning(runtime) << "Delete failed - rollback:" << sourceDef.tableName; QSqlDatabase::database().rollback(); return false; } QSqlQuery insertQuery; if ( !insertQuery.prepare(insertSQL) ) { qWarning() << "Cannot prepare insert statement for" << sourceDef.tableName; QSqlDatabase::database().rollback(); return false; } csv::CSVReader reader = csv::parse(csvData, format); const std::vector colNames = reader.get_col_names(); for ( const QString &col : csvColumns ) { if ( std::find(colNames.begin(), colNames.end(), col.toStdString()) == colNames.end() ) { qWarning() << "Missing column:" << col << "in" << sourceDef.tableName; QSqlDatabase::database().rollback(); return false; } } const int CHUNK = 5000; const int colCount = csvColumns.size(); std::vector stdCols; stdCols.reserve(colCount); for ( const QString &col : csvColumns ) stdCols.push_back(col.toStdString()); QVector columns(colCount); auto reserveAll = [&]() { for ( auto &col : columns ) col.reserve(CHUNK); }; auto flushChunk = [&]() -> bool { for ( const QVariantList &col : columns ) insertQuery.addBindValue(col); if ( !insertQuery.execBatch() ) { qWarning() << "Insert error for" << sourceDef.tableName << ":" << insertQuery.lastError().text(); return false; } for ( QVariantList &col : columns ) col.clear(); reserveAll(); return true; }; reserveAll(); int count = 0; for ( csv::CSVRow &row : reader ) { if ( abortRequested ) break; for ( int i = 0; i < colCount; ++i ) columns[i] << QString::fromStdString(row[stdCols[i]].get()); ++count; if ( count % CHUNK == 0 ) { if ( !flushChunk() ) { abortRequested = true; break; } emit progress(static_cast(count) * totalBytes / totalRows); QCoreApplication::processEvents(); } } if ( !abortRequested && !columns[0].isEmpty() ) { if ( !flushChunk() ) abortRequested = true; } if ( !abortRequested ) { QSqlDatabase::database().commit(); qCDebug(runtime) << sourceDef.tableName << "update finished:" << count << "entities loaded."; return true; } qCWarning(runtime) << sourceDef.tableName << "update failed - rollback"; QSqlDatabase::database().rollback(); return false; } void LOVDownloader::parseSOTASummits(const SourceDefinition &sourceDef, QTextStream &data) { FCT_IDENTIFICATION; csv::CSVFormat format; format.delimiter(',').quote('"').header_row(1); parseCSVGeneric(sourceDef, data, "INSERT INTO sota_summits(summit_code, association_name, region_name, summit_name," " altm, altft, gridref1, gridref2, longitude, latitude, points, bonus_points," " valid_from, valid_to) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", {"SummitCode", "AssociationName", "RegionName", "SummitName", "AltM", "AltFt", "GridRef1", "GridRef2", "Longitude", "Latitude", "Points", "BonusPoints", "ValidFrom", "ValidTo"}, format, "SOTA Summits List"); // preValidateContains } void LOVDownloader::parseWWFFDirectory(const SourceDefinition &sourceDef, QTextStream &data) { FCT_IDENTIFICATION; csv::CSVFormat format; format.delimiter(',').quote('"').trim({' '}); parseCSVGeneric(sourceDef, data, "INSERT INTO wwff_directory(reference, status, name, program, dxcc, state," " county, continent, iota, iaruLocator, latitude, longitude, iucncat," " valid_from, valid_to) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", {"reference", "status", "name", "program", "dxcc", "state", "county", "continent", "iota", "iaruLocator", "latitude", "longitude", "IUCNcat", "validFrom", "validTo"}, format); } void LOVDownloader::parseIOTA(const SourceDefinition &sourceDef, QTextStream &data) { FCT_IDENTIFICATION; QSqlQuery insertQuery; if ( ! insertQuery.prepare("INSERT INTO IOTA(iotaid," " islandname)" " VALUES (?, ?)") ) { qWarning() << "cannot prepare Insert statement"; abortRequested = true; return; } QSqlDatabase::database().transaction(); if ( ! deleteTable(sourceDef.tableName) ) { qCWarning(runtime) << "IOTA List delete failed - rollback"; abortRequested = true; QSqlDatabase::database().rollback(); return; } unsigned int count = 0; QJsonDocument jsonDoc = QJsonDocument::fromJson(data.readAll().toUtf8()); if ( !jsonDoc.isArray() ) { qCDebug(runtime) << jsonDoc; qWarning() << "Unexpected IOTA JSON - aborting"; abortRequested = true; } else { QVariantList iota_id; QVariantList iota_islandname; const QJsonArray &jsonArray = jsonDoc.array(); for ( const QJsonValue &value : jsonArray ) { if ( !value.isObject() ) continue; const QJsonObject &obj = value.toObject(); const QJsonValue &refno = obj.value("refno"); const QJsonValue &name = obj.value("name"); qCDebug(runtime) << "IOTA Record" << refno << name; iota_id << refno; iota_islandname << name; if ( count%500 == 0 ) { emit progress(data.pos()); QCoreApplication::processEvents(); } count++; } insertQuery.addBindValue(iota_id); insertQuery.addBindValue(iota_islandname); if ( ! insertQuery.execBatch() ) { qInfo() << "IOTA Directory insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); abortRequested = true; } } if ( !abortRequested ) { QSqlDatabase::database().commit(); qCDebug(runtime) << "IOTA update finished:" << count << "entities loaded."; } else { qCWarning(runtime) << "IOTA update failed - rollback"; QSqlDatabase::database().rollback(); } } void LOVDownloader::parsePOTA(const SourceDefinition &sourceDef, QTextStream &data) { FCT_IDENTIFICATION; csv::CSVFormat format; format.delimiter(',').quote('"'); parseCSVGeneric(sourceDef, data, "INSERT INTO POTA_DIRECTORY(reference, name, active, entityID," " locationDesc, latitude, longitude, grid) VALUES (?,?,?,?,?,?,?,?)", {"reference", "name", "active", "entityId", "locationDesc", "latitude", "longitude", "grid"}, format); } void LOVDownloader::parseMembershipContent(const SourceDefinition &sourceDef, QTextStream &data) { FCT_IDENTIFICATION; QSqlDatabase::database().transaction(); if ( ! deleteTable(sourceDef.tableName) ) { qCWarning(runtime) << "Membership Directory delete failed - rollback"; QSqlDatabase::database().rollback(); return; } QSqlTableModel entityTableModel; entityTableModel.setTable(sourceDef.tableName); entityTableModel.setEditStrategy(QSqlTableModel::OnManualSubmit); QSqlRecord entityRecord = entityTableModel.record(); int count = 0; while ( !data.atEnd() && !abortRequested ) { QString line = data.readLine(); QStringList fields = line.split(','); if ( fields.count() != 5 ) { qCDebug(runtime) << "Invalid line in the input file " << line; continue; } qCDebug(runtime) << fields; entityRecord.clearValues(); entityRecord.setValue("short_desc", fields.at(0)); entityRecord.setValue("long_desc", fields.at(1)); entityRecord.setValue("filename", fields.at(2)); entityRecord.setValue("last_update", fields.at(3)); entityRecord.setValue("num_records", fields.at(4)); if ( !entityTableModel.insertRecord(-1, entityRecord) ) { qWarning() << "Cannot insert a record to Membership Directory Table - " << entityTableModel.lastError(); qCDebug(runtime) << entityRecord; } else { count++; } emit progress(data.pos()); QCoreApplication::processEvents(); } if ( entityTableModel.submitAll() && !abortRequested ) { QSqlDatabase::database().commit(); qCDebug(runtime) << "Membership Directory update finished:" << count << "entities loaded."; } else { //can be a result of abort qCWarning(runtime) << "Membership Directory update failed - rollback" << entityTableModel.lastError(); QSqlDatabase::database().rollback(); } } void LOVDownloader::parseClubLogCTY(const SourceDefinition &sourceDef, QTextStream &data) { FCT_IDENTIFICATION; if (sourceDef.type != CLUBLOGCTY) return; // Read whole text (it’s XML); QXmlStreamReader can also take QIODevice, but we // already have a QTextStream here. QXmlStreamReader xml(data.readAll()); // Clean all five tables inside one transaction QSqlDatabase::database().transaction(); auto rollback = [&]() { qCWarning(runtime) << "ClubLog CTY import failed - rollback"; QSqlDatabase::database().rollback(); }; if ( !deleteTable("dxcc_zone_exceptions_clublog") || !deleteTable("dxcc_prefixes_clublog") || !deleteTable("dxcc_entities_clublog")) { rollback(); return; } QSqlQuery insEntity, insPrefix,insZone; // prepared statements if (!insEntity.prepare( "INSERT INTO dxcc_entities_clublog(id, name, prefix, deleted, cqz, ituz, cont, lon, lat, start, \"end\")" "VALUES(:id, :name, :prefix, :deleted, :cqz, :ituz, :cont, :lon, :lat, :start, :end)")) { qWarning() << insEntity.lastError(); rollback(); return; } if (!insPrefix.prepare( "INSERT INTO dxcc_prefixes_clublog(prefix, exact, dxcc, cqz, cont, lon, lat, start, \"end\")" "VALUES(:prefix, :exact, :dxcc, :cqz, :cont, :lon, :lat, :start, :end)")) { qWarning() << insPrefix.lastError(); rollback(); return; } if (!insZone.prepare( "INSERT INTO dxcc_zone_exceptions_clublog(record, call, cqz, start, \"end\")" "VALUES(:record, :call, :cqz, :start, :end)")) { qWarning() << insZone.lastError(); rollback(); return; } auto readText = [&](QXmlStreamReader &x)->QString { return x.readElementText().trimmed(); }; auto readDate = [&](const QString &s)->QString { return s; }; // store ISO8601 text as-is // Cursor down to while (!xml.atEnd() && !(xml.isStartElement() && xml.name() == QStringLiteral("clublog"))) xml.readNext(); if (xml.atEnd()) { qWarning() << "ClubLog: not found"; rollback(); return; } quint32 readOp = 0; auto updateReadProgress = [&]() { readOp++; if ( readOp % 200 == 0 ) { emit progress(xml.characterOffset()); QCoreApplication::processEvents(); } }; // Iterate children of while (!xml.atEnd()) { xml.readNext(); if ( !xml.isStartElement() ) continue; const QString &top = xml.name().toString(); if ( top == "entities" ) { // ...... while (!(xml.isEndElement() && xml.name() == QStringLiteral("entities"))) { xml.readNext(); updateReadProgress(); if ( xml.isStartElement() && xml.name() == QStringLiteral("entity") ) { // parse one entity int adif = 0; QString name, prefix, cont; bool deleted=false; int cqz = 0; QString start, end; double lon=0.0, lat=0.0; while ( !(xml.isEndElement() && xml.name() == QStringLiteral("entity"))) { xml.readNext(); updateReadProgress(); if ( !xml.isStartElement() ) continue; const QString &tag = xml.name().toString(); if ( tag=="adif" ) adif = readText(xml).toInt(); else if ( tag=="name" ) name = readText(xml); else if ( tag=="prefix" ) prefix = readText(xml); else if ( tag=="deleted" ) deleted = (readText(xml).compare("true", Qt::CaseInsensitive) == 0); else if ( tag=="cqz" ) cqz = readText(xml).toInt(); else if ( tag=="cont" ) cont = readText(xml); else if ( tag=="long" ) lon = readText(xml).toDouble(); else if ( tag=="lat" ) lat = readText(xml).toDouble(); else if ( tag=="start" ) start = readDate(readText(xml)); else if ( tag=="end" ) end = readDate(readText(xml)); else xml.skipCurrentElement(); } insEntity.bindValue(":id", adif); const QString &nameModified = Data::instance()->dxccName(adif); insEntity.bindValue(":name", nameModified.isEmpty() ? name : nameModified); insEntity.bindValue(":prefix", prefix); insEntity.bindValue(":deleted", deleted ? 1 : 0); insEntity.bindValue(":cqz", cqz ? cqz : 0); insEntity.bindValue(":ituz", Data::instance()->dxccITUZ(adif)); insEntity.bindValue(":cont", cont.isEmpty()? QVariant(): cont); insEntity.bindValue(":lon", lon); insEntity.bindValue(":lat", lat); insEntity.bindValue(":start", start.isEmpty()? QVariant() : start); insEntity.bindValue(":end", end.isEmpty()? QVariant() : end); if (!insEntity.exec()) { qWarning() << insEntity.lastError(); rollback(); return; } } } } else if (top == "prefixes" || top == "exceptions") { // these two share the same internal structure: ... bool isPrefix = (top=="prefixes"); while (!(xml.isEndElement() && xml.name() == top)) { xml.readNext(); updateReadProgress(); if ( xml.isStartElement() && (xml.name() == QStringLiteral("prefix") || xml.name()==QStringLiteral("exception"))) { QString call, cont, start, end; int adif=0, cqz=0; double lon=0.0, lat=0.0; while ( !(xml.isEndElement() && (xml.name()==QStringLiteral("prefix") || xml.name()==QStringLiteral("exception")))) { xml.readNext(); updateReadProgress(); if ( !xml.isStartElement() ) continue; const QString tag = xml.name().toString(); if ( tag=="call" ) call = readText(xml); else if ( tag=="adif" ) adif = readText(xml).toInt(); else if ( tag=="cqz" ) cqz = readText(xml).toInt(); else if ( tag=="cont" ) cont = readText(xml); else if ( tag=="long" ) lon = readText(xml).toDouble(); else if ( tag=="lat" ) lat = readText(xml).toDouble(); else if ( tag=="start" ) start = readDate(readText(xml)); else if ( tag=="end" ) end = readDate(readText(xml)); else xml.skipCurrentElement(); } insPrefix.bindValue(":prefix", call); insPrefix.bindValue(":exact", !isPrefix); insPrefix.bindValue(":dxcc", adif); insPrefix.bindValue(":cqz", cqz ? cqz : 0); insPrefix.bindValue(":ituz", 0); insPrefix.bindValue(":cont", cont.isEmpty()? QVariant() : cont); insPrefix.bindValue(":lon", lon); insPrefix.bindValue(":lat", lat); insPrefix.bindValue(":start", start.isEmpty()? QVariant() : start); insPrefix.bindValue(":end", end.isEmpty()? QVariant() : end); if (!insPrefix.exec()) { qWarning() << insPrefix.lastError(); rollback(); return; } } } } else if ( top == "zone_exceptions" ) { while ( !(xml.isEndElement() && xml.name() == QStringLiteral("zone_exceptions")) ) { xml.readNext(); updateReadProgress(); if ( xml.isStartElement() && xml.name()==QStringLiteral("zone_exception") ) { bool ok=false; quint32 rec = xml.attributes().value("record").toUInt(&ok); QString call, start, end; int zone=0; while ( !(xml.isEndElement() && xml.name()==QStringLiteral("zone_exception")) ) { xml.readNext(); updateReadProgress(); if (!xml.isStartElement()) continue; const QString &tag = xml.name().toString(); if ( tag=="call" ) call = readText(xml); else if ( tag=="zone" ) zone = readText(xml).toInt(); else if ( tag=="start" ) start = readDate(readText(xml)); else if ( tag=="end" ) end = readDate(readText(xml)); else xml.skipCurrentElement(); } insZone.bindValue(":record", rec); insZone.bindValue(":call", call); insZone.bindValue(":cqz", zone); insZone.bindValue(":start", start); insZone.bindValue(":end", end); if (!insZone.exec()) { qWarning() << insZone.lastError(); rollback(); return; } } } } else xml.skipCurrentElement(); updateReadProgress(); } if ( xml.hasError() ) { qWarning() << "ClubLog XML error:" << xml.errorString(); rollback(); return; } QSqlDatabase::database().commit(); qCDebug(runtime) << "ClubLog CTY import finished."; } void LOVDownloader::processReply(QNetworkReply *reply) { FCT_IDENTIFICATION; currentReply = nullptr; QByteArray data = reply->readAll(); uint sourceTypeNum = reply->property("sourceType").toUInt(); qCDebug(runtime) << "Received Source type " << sourceTypeNum; SourceType sourceType = static_cast(sourceTypeNum); SourceDefinition sourceDef = sourceMapping[sourceType]; Q_ASSERT(sourceDef.type == sourceType); int replyStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if ( reply->isFinished() && reply->error() == QNetworkReply::NoError && replyStatusCode >= 200 && replyStatusCode < 300) { qCDebug(runtime) << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); qCDebug(runtime) << reply->header(QNetworkRequest::KnownHeaders::LocationHeader); QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); QFile file(dir.filePath(sourceDef.fileName)); file.open(QIODevice::WriteOnly); if (sourceType == CLUBLOGCTY) { QByteArray maybeXml = FileCompressor::gunzip(data); if ( !maybeXml.isEmpty() ) data = maybeXml; } file.write(data); file.flush(); file.close(); reply->deleteLater(); LogParam::setLOVParam(sourceDef.lastTimeConfigName, QDateTime::currentDateTimeUtc().date()); loadData(sourceDef); } else { qCDebug(runtime) << "HTTP Status Code" << replyStatusCode; qCDebug(runtime) << "Failed to download " << sourceDef.fileName; reply->deleteLater(); emit finished(false); } } foldynl-QLog-3252ff9/core/LOVDownloader.h000066400000000000000000000143451517334601000201520ustar00rootroot00000000000000#ifndef QLOG_CORE_LOVDOWNLOADER_H #define QLOG_CORE_LOVDOWNLOADER_H #include #include #include #include "service/clublog/ClubLog.h" namespace csv { class CSVFormat; } class LOVDownloader : public QObject { Q_OBJECT public: enum SourceType { CTY = 0, SATLIST = 1, SOTASUMMITS = 2, WWFFDIRECTORY = 3, IOTALIST = 4, POTADIRECTORY = 5, MEMBERSHIPCONTENTLIST = 6, CLUBLOGCTY = 7, UNDEF = 8 }; public: LOVDownloader(QObject *parent = nullptr); ~LOVDownloader(); void update(const SourceType &, bool force = false); public slots: void abortRequest(); signals: void processingSize(qint64); void progress(qint64 count); void finished(bool result); void noUpdate(); private: class SourceDefinition { public: SourceDefinition(const SourceType type, const QString &URL, const QString &fileName, const QString &lastTimeConfigName, const QString &tableName, int ageTime) : type(type), URL(URL), fileName(fileName), lastTimeConfigName(lastTimeConfigName), tableName(tableName), ageTime(ageTime) {}; SourceDefinition() : type(LOVDownloader::UNDEF), ageTime(0){}; SourceType type; QString URL; QString fileName; QString lastTimeConfigName; QString tableName; int ageTime; }; QMap sourceMapping = { {CTY, SourceDefinition(CTY, "https://www.country-files.com/bigcty/cty.csv", "cty.csv", "LOV/last_cty_update", "dxcc_entities_ad1c", 7)}, {CLUBLOGCTY, SourceDefinition(CLUBLOGCTY, ClubLogBase::getCTYUrl(), "clublog_cty.xml", "LOV/last_clublogcty_update", "dxcc_entities_clublog", 7)}, {SATLIST, SourceDefinition(SATLIST, "https://raw.githubusercontent.com/foldynl/hamradio-value-lists/main/lists/satellites/satslist.csv", "satslist.csv", "LOV/last_sat_update", "sat_info", 10)}, {SOTASUMMITS, SourceDefinition(SOTASUMMITS, "https://raw.githubusercontent.com/foldynl/hamradio-value-lists/main/lists/SOTA/summitslist.csv.gz", "summitslist.csv.gz", "LOV/last_sotasummits_update", "sota_summits", 30)}, {WWFFDIRECTORY, SourceDefinition(WWFFDIRECTORY, "https://raw.githubusercontent.com/foldynl/hamradio-value-lists/main/lists/WWFF/wwff_directory.csv.gz", "wwff_directory.csv.gz", "LOV/last_wwffdirectory_update", "wwff_directory", 21)}, {IOTALIST, SourceDefinition(IOTALIST, "https://www.iota-world.org/islands-on-the-air/downloads/download-file.html?path=groups.json", "groups.json", "LOV/last_iota_update", "iota", 30)}, {POTADIRECTORY, SourceDefinition(POTADIRECTORY, "https://raw.githubusercontent.com/foldynl/hamradio-value-lists/main/lists/POTA/all_parks_ext.csv.gz", "all_parks_ext.csv.gz", "LOV/last_pota_update", "pota_directory", 30)}, {MEMBERSHIPCONTENTLIST, SourceDefinition(MEMBERSHIPCONTENTLIST, "https://raw.githubusercontent.com/foldynl/hamradio-membeship-lists/main/lists/content.csv", "content.csv", "LOV/last_membershipcontent_update", "membership_directory", 7)} }; QNetworkAccessManager* nam; QNetworkReply *currentReply; bool abortRequested; QRegularExpression CTYPrefixSeperatorRe; QRegularExpression CTYPrefixFormatRe; private: bool isTableFilled(const QString &); bool deleteTable(const QString &); void download(const SourceDefinition &); void parseData(const LOVDownloader::SourceDefinition &, QTextStream &); void parseCTY(const SourceDefinition &sourceDef, QTextStream& data); void parseSATLIST(const SourceDefinition &sourceDef, QTextStream& data); void parseSOTASummits(const SourceDefinition &sourceDef, QTextStream& data); void parseWWFFDirectory(const SourceDefinition &sourceDef, QTextStream& data); void parseIOTA(const SourceDefinition &sourceDef, QTextStream& data); void parsePOTA(const SourceDefinition &sourceDef, QTextStream& data); void parseMembershipContent(const SourceDefinition &sourceDef, QTextStream& data); void parseClubLogCTY(const SourceDefinition &sourceDef, QTextStream &data); bool parseCSVGeneric(const SourceDefinition &sourceDef, QTextStream &data, const QString &insertSQL, const QStringList &csvColumns, csv::CSVFormat format, const QString &preValidateContains = QString()); private slots: void processReply(QNetworkReply*); void loadData(const LOVDownloader::SourceDefinition &); }; #endif // QLOG_CORE_LOVDOWNLOADER_H foldynl-QLog-3252ff9/core/LogDatabase.cpp000066400000000000000000000330201517334601000201630ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include "LogDatabase.h" #include "core/debug.h" #include "core/Migration.h" #include "core/LogParam.h" #include "core/CredentialStore.h" #include "core/PlatformParameterManager.h" MODULE_IDENTIFICATION("qlog.core.logdatabase"); QString LogDatabase::PLATFORM_WINDOWS = "Windows"; QString LogDatabase::PLATFORM_MACOS = "MacOS"; QString LogDatabase::PLATFORM_LINUX = "Linux"; QString LogDatabase::PLATFORM_LINUXFLATPAK = "LinuxFlatpak"; QDir LogDatabase::dbDirectory() { return QDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); } QString LogDatabase::dbFilename() { return dbDirectory().filePath("qlog.db"); } QString LogDatabase::currentPlatformId() { #if defined(Q_OS_WIN) return LogDatabase::PLATFORM_WINDOWS; #elif defined(Q_OS_MACOS) return LogDatabase::PLATFORM_MACOS; #elif defined(QLOG_FLATPAK) return LogDatabase::PLATFORM_LINUXFLATPAK; #else return LogDatabase::PLATFORM_LINUX; #endif } LogDatabase::LogDatabase() { FCT_IDENTIFICATION; } bool LogDatabase::hadPasswordImportWarning() const { return passwordImportWarning; } bool LogDatabase::createSQLFunctions() { FCT_IDENTIFICATION; QVariant v = QSqlDatabase::database().driver()->handle(); if ( !v.isValid() || qstrcmp(v.typeName(), "sqlite3*") != 0 ) { qCritical() << "Cannot get SQLite driver handle"; return false; } sqlite3 *db_handle = *static_cast(v.data()); if ( db_handle == 0 ) { qCritical() << "Cannot define new SQLite functions"; return false; } sqlite3_initialize(); sqlite3_create_function(db_handle, "translate_to_locale", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr, [](sqlite3_context *ctx, int argc, sqlite3_value **argv) { if ( argc != 1 ) { sqlite3_result_error(ctx, "Invalid arguments", -1); return; } switch ( sqlite3_value_type(argv[0]) ) { case SQLITE_TEXT: { const char *text = reinterpret_cast(sqlite3_value_text(argv[0])); const QString &translatedText = QCoreApplication::translate("DBStrings", text); sqlite3_result_text(ctx, translatedText.toUtf8().constData(), -1, SQLITE_TRANSIENT); } break; case SQLITE_NULL: sqlite3_result_null(ctx); break; case SQLITE_INTEGER: sqlite3_result_int(ctx, sqlite3_value_int(argv[0])); break; case SQLITE_FLOAT: sqlite3_result_double(ctx, sqlite3_value_double(argv[0])); break; default: sqlite3_result_error(ctx, "Invalid arguments", -1); } }, nullptr, nullptr); sqlite3_create_collation(db_handle, "LOCALEAWARE", SQLITE_UTF16, nullptr, [](void *, int ll, const void * l, int rl, const void * r) { const QString &left = QString::fromUtf16(reinterpret_cast(l), ll/2); const QString &right = QString::fromUtf16(reinterpret_cast(r), rl/2); return QString::localeAwareCompare(left, right); // controlled by LC_COLLATE }); return true; } bool LogDatabase::atomicCopy(const QString &filename) { FCT_IDENTIFICATION; QSqlDatabase db = QSqlDatabase::database(); if ( !db.isOpen() ) { qWarning() << "Database is not opened"; return false; } // Validate filename — must be a plain filename, no path separators if ( filename.isEmpty() ) { qWarning() << "Invalid filename:" << filename; return false; } QVariant v = db.driver()->handle(); if ( !v.isValid() || qstrcmp(v.typeName(), "sqlite3*") != 0) { qWarning() << "Cannot get Database Driver Handler"; return false; } sqlite3 *srcHandle = *static_cast(v.data()); sqlite3 *dstHandle = nullptr; sqlite3_backup *backup = nullptr; bool ok = false; int stepSize = 5000; const QString newDBFilename = dbDirectory().filePath(filename); if (sqlite3_open_v2(newDBFilename.toUtf8().constData(), &dstHandle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) { qWarning() << "Cannot open a new database file:" << sqlite3_errmsg(dstHandle); goto cleanup; } backup = sqlite3_backup_init(dstHandle, "main", srcHandle, "main"); if ( !backup ) { qWarning() << "Cannot Init a backup" << sqlite3_errmsg(dstHandle); goto cleanup; } while (true) { int rc = sqlite3_backup_step(backup, stepSize); int total = sqlite3_backup_pagecount(backup); int remaining = sqlite3_backup_remaining(backup); int done = total - remaining; int percent = total > 0 ? (done * 100 / total) : 0; qCDebug(runtime) << percent; if (rc == SQLITE_DONE) { ok = true; break; } else if (rc == SQLITE_BUSY || rc == SQLITE_LOCKED) { sqlite3_sleep(50); continue; } else if (rc == SQLITE_OK) { continue; } else { qWarning() << "Backup Error" << sqlite3_errmsg(dstHandle); break; } } // sqlite3_backup_finish always releases the backup handle, // even on error — never call it twice if ( sqlite3_backup_finish(backup) != SQLITE_OK ) { qWarning() << "Cannot finalize the database copy" << sqlite3_errmsg(dstHandle); ok = false; } backup = nullptr; cleanup: if ( backup ) sqlite3_backup_finish(backup); if ( dstHandle ) sqlite3_close(dstHandle); if ( !ok ) QFile::remove(newDBFilename); return ok; } bool LogDatabase::openDatabase() { FCT_IDENTIFICATION; QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(dbFilename()); db.setConnectOptions("QSQLITE_ENABLE_REGEXP"); if ( !db.open() ) { qCritical() << db.lastError(); return false; } QSqlQuery query; if ( !query.exec("PRAGMA foreign_keys = ON") ) { qCritical() << "Cannot set PRAGMA foreign_keys"; return false; } if ( !query.exec("PRAGMA journal_mode = WAL") ) { qCritical() << "Cannot set PRAGMA journal_mode"; return false; } while ( query.next() ) { QString pragma = query.value(0).toString(); qCDebug(runtime) << "Pragma result:" << pragma; } return createSQLFunctions(); } bool LogDatabase::schemaVersionUpgrade(bool force) { FCT_IDENTIFICATION; DBSchemaMigration m; return m.run(force); } DatabaseInfo LogDatabase::inspectDatabase(const QString &filename) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filename; DatabaseInfo info; const QString connectionName = QStringLiteral("InspectDB"); // Use do-while(false) pattern to ensure removeDatabase is called after db/query are out of scope do { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connectionName); db.setDatabaseName(filename); if ( !db.open() ) { info.errorMessage = db.lastError().text(); qWarning() << "Cannot open database for inspection:" << info.errorMessage; break; } // Check if it's a valid QLog database by looking for schema_versions table QSqlQuery query(db); if ( !query.exec("SELECT version FROM schema_versions ORDER BY version DESC LIMIT 1") ) { info.errorMessage = QObject::tr("Not a valid QLog database"); db.close(); break; } info.schemaVersion = ( query.first() ) ? query.value(0).toInt() : 0; // Check if schema version is too new if ( info.schemaVersion > DBSchemaMigration::latestVersion ) { info.errorMessage = QObject::tr("Database version too new (requires newer QLog version)"); db.close(); break; } // Read source platform and encrypted passwords from log_param if ( query.exec("SELECT value FROM log_param WHERE name = 'sourceplatform'") ) { if ( query.first() ) info.sourcePlatform = query.value(0).toString(); if ( info.sourcePlatform.isEmpty() ) { info.errorMessage = QObject::tr("Database is not QLog Export file"); db.close(); break; } } if ( query.exec("SELECT value FROM log_param WHERE name = 'security/encryptedpasswords'") ) { if ( query.first() && !query.value(0).toString().isEmpty() ) info.hasEncryptedPasswords = true; } info.valid = true; db.close(); } while (false); QSqlDatabase::removeDatabase(connectionName); qCDebug(runtime) << "Database info - valid:" << info.valid << "version:" << info.schemaVersion << "platform:" << info.sourcePlatform << "hasPasswords:" << info.hasEncryptedPasswords; return info; } QString LogDatabase::pendingImportPath() { return dbDirectory().filePath("qlog.db.pending"); } bool LogDatabase::hasPendingImport() { FCT_IDENTIFICATION; bool exists = QFile::exists(pendingImportPath()); qCDebug(runtime) << "Pending import exists:" << exists; return exists; } bool LogDatabase::processPendingImport() { FCT_IDENTIFICATION; const QString pendingPath = pendingImportPath(); if ( !QFile::exists(pendingPath) ) { qCDebug(runtime) << "No pending import"; return true; } qCDebug(runtime) << "Processing pending database import"; const QString currentDbPath = dbFilename(); const QString walPath = currentDbPath + "-wal"; // remove also support files const QString shmPath = currentDbPath + "-shm"; // remove also support files if ( QFile::exists(currentDbPath) ) { if ( !QFile::remove(currentDbPath) ) { qWarning() << "Cannot remove current database:" << currentDbPath; return false; } } if ( QFile::exists(walPath) ) QFile::remove(walPath); if ( QFile::exists(shmPath) ) QFile::remove(shmPath); // Rename pending to current if ( !QFile::rename(pendingPath, currentDbPath) ) { qWarning() << "Cannot rename pending database to current"; return false; } qCDebug(runtime) << "Pending database moved to current"; if ( !openDatabase() ) { qCritical() << "Cannot open imported database"; return false; } if ( !schemaVersionUpgrade() ) { qCritical() << "Schema migration failed"; return false; } const QString passphrase = CredentialStore::instance()->getImportPassphrase(); if ( !passphrase.isEmpty() ) { qCDebug(runtime) << "Importing passwords from encrypted store"; CredentialStore::instance()->deleteAllPasswords(); if ( !CredentialStore::instance()->importPasswords(passphrase) ) { qCWarning(runtime) << "Password import failed"; passwordImportWarning = true; } CredentialStore::instance()->deleteImportPassphrase(); } const QString paramsPath = PlatformParameterManager::pendingParametersPath(); if ( QFile::exists(paramsPath) ) { qCDebug(runtime) << "Applying platform-specific parameters"; QList params = PlatformParameterManager::loadParametersFromFile(paramsPath); PlatformParameterManager::applyParameters(params); QList profileParams = PlatformParameterManager::loadProfileParametersFromFile(paramsPath); PlatformParameterManager::applyProfileParameters(profileParams); QFile::remove(paramsPath); } // For Flatpak target: apply fixed paths (TQSL, rigctld_path) // This overrides any imported values with Flatpak-specific paths PlatformParameterManager::applyFlatpakFixedPaths(); LogParam::removeEncryptedPasswords(); LogParam::removeSourcePlatform(); // Generate new LogID because we want to uniquie identified every log QString newLogId = QUuid::createUuid().toString(QUuid::WithoutBraces); LogParam::setLogID(newLogId); qCDebug(runtime) << "New LogID generated:" << newLogId; qCDebug(runtime) << "Database import completed successfully"; return true; } foldynl-QLog-3252ff9/core/LogDatabase.h000066400000000000000000000032311517334601000176310ustar00rootroot00000000000000#ifndef QLOG_CORE_LOGDATABASE_H #define QLOG_CORE_LOGDATABASE_H #include #include struct DatabaseInfo { bool valid = false; int schemaVersion = 0; QString sourcePlatform; bool hasEncryptedPasswords = false; QString errorMessage; }; class LogDatabase { public: static LogDatabase* instance() { static LogDatabase instance; return &instance; }; static QString PLATFORM_WINDOWS; static QString PLATFORM_MACOS; static QString PLATFORM_LINUX; static QString PLATFORM_LINUXFLATPAK; static QDir dbDirectory(); static QString dbFilename(); static QString currentPlatformId(); // Inspect a database file without opening it as main connection // Returns information about the database (schema version, platform, etc.) static DatabaseInfo inspectDatabase(const QString &filename); // Path where pending import database is stored static QString pendingImportPath(); // Check if there is a pending import to process static bool hasPendingImport(); // Process pending import (called at startup) // Returns true if import was successful or no import was pending bool processPendingImport(); // Returns true if the last processPendingImport() failed to import passwords // (passwords were deleted but could not be restored from the encrypted store) bool hadPasswordImportWarning() const; bool atomicCopy(const QString &filename); bool openDatabase(); bool schemaVersionUpgrade(bool force = false); bool createSQLFunctions(); private: LogDatabase(); bool passwordImportWarning = false; }; #endif // QLOG_CORE_LOGDATABASE_H foldynl-QLog-3252ff9/core/LogLocale.cpp000066400000000000000000000063441517334601000176670ustar00rootroot00000000000000#include "LogLocale.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.loglocale"); LogLocale::LogLocale() : regexp(QRegularExpression(R"(, tttt|\(t\)|\(tttt\)|\[tttt\]|\btttt\b|\btt\b|\bt\b)")), is24hUsed(!timeFormat(QLocale::ShortFormat).contains("ap", Qt::CaseInsensitive)), isMetricUnitUsed(measurementSystem() == QLocale::MetricSystem) { FCT_IDENTIFICATION; systemDateFormat = dateFormat(QLocale::ShortFormat); qCDebug(runtime) << systemDateFormat; if ( systemDateFormat.contains("yy") && !systemDateFormat.contains("yyyy") ) systemDateFormat.replace("yy", "yyyy"); } void LogLocale::changeTime12_24Format(QString &formatString) const { if ( getSettingUse24hformat() ) formatString.remove("ap", Qt::CaseInsensitive).remove("a", Qt::CaseInsensitive); else if ( is24hUsed ) { formatString += " AP"; formatString = formatString.toLower(); } } const QString LogLocale::formatTimeLongWithoutTZ() const { FCT_IDENTIFICATION; qCDebug(runtime) << timeFormat(QLocale::LongFormat); QString ret = timeFormat(QLocale::LongFormat).remove(regexp).trimmed(); changeTime12_24Format(ret); qCDebug(runtime) << "format:" << ret; return ret; } const QString LogLocale::formatTimeShort() const { FCT_IDENTIFICATION; qCDebug(runtime) << timeFormat(QLocale::ShortFormat); QString ret = timeFormat(QLocale::ShortFormat); changeTime12_24Format(ret); qCDebug(runtime) << "format:" << ret; return ret; } const QString LogLocale::formatTimeLong() const { FCT_IDENTIFICATION; QString ret = formatTimeLongWithoutTZ(); ret #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) .append(" t"); #else .append(" ttt"); #endif qCDebug(runtime) << "format:" << ret; return ret; } const QString LogLocale::formatDateShortWithYYYY() const { FCT_IDENTIFICATION; QString ret = (getSettingUseSystemDateFormat()) ? systemDateFormat : getSettingDateFormat(); qCDebug(runtime) << "format:" << ret; return ret; } const QString LogLocale::formatDateTimeShortWithYYYY() const { FCT_IDENTIFICATION; QString ret = formatDateShortWithYYYY() + " " + formatTimeShort(); qCDebug(runtime) << "format:" << ret; return ret; } bool LogLocale::getSettingUse24hformat() const { return settings.value("use24hformat", is24hUsed).toBool(); } void LogLocale::setSettingUse24hformat(bool value) { settings.setValue("use24hformat", value); } bool LogLocale::getSettingUseMetric() const { return settings.value("usemetricformat", isMetricUnitUsed).toBool(); } void LogLocale::setSettingUseMetric(bool value) { settings.setValue("usemetricformat", value); } bool LogLocale::getSettingUseSystemDateFormat() const { return settings.value("usesystemdateformat", true).toBool(); } void LogLocale::setSettingUseSystemDateFormat(bool value) { settings.setValue("usesystemdateformat", value); } const QString LogLocale::getSettingDateFormat() const { return settings.value("customdateformatstring", systemDateFormat).toString(); } void LogLocale::setSettingDateFormat(const QString &value) { settings.setValue("customdateformatstring", value); } foldynl-QLog-3252ff9/core/LogLocale.h000066400000000000000000000020321517334601000173220ustar00rootroot00000000000000#ifndef QLOG_CORE_LOGLOCALE_H #define QLOG_CORE_LOGLOCALE_H #include #include #include class LogLocale : public QLocale { public: LogLocale(); const QString formatTimeLongWithoutTZ() const; const QString formatTimeShort() const; const QString formatTimeLong() const; const QString formatDateShortWithYYYY() const; const QString formatDateTimeShortWithYYYY() const; bool getSettingUse24hformat() const; void setSettingUse24hformat(bool value); bool getSettingUseSystemDateFormat() const; void setSettingUseSystemDateFormat(bool value); const QString getSettingDateFormat() const; void setSettingDateFormat(const QString &value); bool getSettingUseMetric() const; void setSettingUseMetric(bool value); private: const QRegularExpression regexp; bool is24hUsed; bool isMetricUnitUsed; QSettings settings; QString systemDateFormat; void changeTime12_24Format(QString &formatString) const; }; #endif // QLOG_CORE_LOGLOCALE_H foldynl-QLog-3252ff9/core/LogParam.cpp000066400000000000000000001236411517334601000175300ustar00rootroot00000000000000#include #include #include #include "LogParam.h" #include "debug.h" #include "data/Data.h" #include "models/LogbookModel.h" #include "data/BandPlan.h" MODULE_IDENTIFICATION("qlog.core.logparam"); #define PARAMMUTEXLOCKER qCDebug(runtime) << "Waiting for mutex"; \ QMutexLocker locker(&cacheMutex); \ qCDebug(runtime) << "Using logparam" LogParam::LogParam(QObject *parent) : QObject(parent) { FCT_IDENTIFICATION; } bool LogParam::setLOVParam(const QString &LOVName, const QVariant &value) { return setParam(LOVName, value); } QDate LogParam::getLOVaParam(const QString &LOVName) { return getParam(LOVName).toDate(); } bool LogParam::setLastBackupDate(const QDate date) { return setParam("last_backup", date); } QDate LogParam::getLastBackupDate() { return getParam("last_backup").toDate(); } bool LogParam::setLogID(const QString &id) { return setParam("logid", id); } QString LogParam::getLogID() { return getParam("logid").toString(); } bool LogParam::setContestSeqnoType(const QVariant &data) { return setParam("contest/seqnotype", data); } int LogParam::getContestSeqnoType() { return getParam("contest/seqnotype", Data::SeqType::SINGLE).toInt(); } bool LogParam::setContestManuDupeType(const QVariant &data) { return setParam("contest/dupetype", data); } int LogParam::getContestDupeType() { return getParam("contest/dupetype", Data::DupeType::ALL_BANDS).toInt(); } bool LogParam::setContestLinkExchange(const QVariant &data) { return setParam("contest/linkexchangetype", data); } int LogParam::getContestLinkExchange() { return getParam("contest/linkexchangetype", LogbookModel::COLUMN_INVALID).toInt(); } bool LogParam::setContestFilter(const QString &filterName) { return setParam("contest/filter", filterName); } QString LogParam::getContestFilter() { return getParam("contest/filter").toString(); } bool LogParam::setContestID(const QString &contestID) { return setParam("contest/contestid", contestID); } QString LogParam::getContestID() { return getParam("contest/contestid", QString()).toString(); } bool LogParam::setContestDupeDate(const QDateTime date) { return setParam("contest/dupeDate", date); } QDateTime LogParam::getContestDupeDate() { return getParam("contest/dupeDate").toDateTime(); } void LogParam::removeConetstDupeDate() { removeParamGroup("contest/dupeDate"); } bool LogParam::getDxccConfirmedByLotwState() { return getParam("others/dxccconfirmedbylotw", true).toBool(); } bool LogParam::setDxccConfirmedByLotwState(bool state) { return setParam("others/dxccconfirmedbylotw", state); } bool LogParam::setDxccConfirmedByPaperState(bool state) { return setParam("others/dxccconfirmedbypaper", state); } bool LogParam::getDxccConfirmedByPaperState() { return getParam("others/dxccconfirmedbypaper", true).toBool(); } bool LogParam::setDxccConfirmedByEqslState(bool state) { return setParam("others/dxccconfirmedbyeqsl", state); } bool LogParam::getDxccConfirmedByEqslState() { return getParam("others/dxccconfirmedbyeqsl", false).toBool(); } int LogParam::getContestSeqno(const QString &band) { return getParam(( band.isEmpty() ) ? "contest/seqnos/single" : QString("contest/seqnos/%1").arg(band), 1).toInt(); } bool LogParam::setContestSeqno(int value, const QString &band) { return setParam(( band.isEmpty() ) ? "contest/seqnos/single" : QString("contest/seqnos/%1").arg(band), value); } void LogParam::removeContestSeqno() { removeParamGroup("contest/seqnos/"); } bool LogParam::setDXCTrendContinent(const QString &cont) { return setParam("dxc/trendContinent", cont); } QString LogParam::getDXCTrendContinent(const QString &def) { return getParam("dxc/trendContinent", def).toString(); } void LogParam::removeDXCTrendContinent() { removeParamGroup("dxc/trendContinent"); } QStringList LogParam::bandmapsWidgets() { return getKeys("bandmap/"); } void LogParam::removeBandmapWidgetGroup(const QString &group) { removeParamGroup("bandmap/" + group); } double LogParam::getBandmapScrollFreq(const QString &widgetID, const QString &bandName) { return getParam("bandmap/" + widgetID + "/" + bandName + "/scrollfreq" , 0.0).toDouble(); } bool LogParam::setBandmapScrollFreq(const QString &widgetID, const QString &bandName, double scroll) { return setParam("bandmap/" + widgetID + "/" + bandName + "/scrollfreq", scroll); } QVariant LogParam::getBandmapZoom(const QString &widgetID, const QString &bandName, const QVariant &defaultValue) { return getParam("bandmap/" + widgetID + "/" + bandName + "/zoom", defaultValue); } bool LogParam::setBandmapZoom(const QString &widgetID, const QString &bandName, const QVariant &zoom) { return setParam("bandmap/" + widgetID + "/" + bandName + "/zoom", zoom); } bool LogParam::setBandmapAging(const QString &widgetID, int aging) { return setParam("bandmap/" + widgetID + "/spotaging", aging); } int LogParam::getBandmapAging(const QString &widgetID) { return getParam("bandmap/" + widgetID + "/spotaging", 0).toInt(); } bool LogParam::setBandmapCenterRX(const QString &widgetID, bool centerRX) { return setParam("bandmap/" + widgetID + "/centerrx", centerRX); } bool LogParam::getBandmapCenterRX(const QString &widgetID) { return getParam("bandmap/" + widgetID + "/centerrx", true).toBool(); } bool LogParam::setBandmapShowEmergency(const QString &widgetID, bool show) { return setParam("bandmap/" + widgetID + "/showemergency", show); } bool LogParam::getBandmapShowEmergency(const QString &widgetID) { return getParam("bandmap/" + widgetID + "/showemergency", true).toBool(); } QString LogParam::getUploadQSOLastCall() { return getParam("uploadqso/lastcall").toString(); } void LogParam::setUploadQSOLastCall(const QString &call) { setParam("uploadqso/lastcall", call); } bool LogParam::getUploadeqslQSLComment() { return getParam("uploadqso/eqsl/last_checkcomment", false).toBool(); } void LogParam::setUploadeqslQSLComment(const bool state) { setParam("uploadqso/eqsl/last_checkcomment", state); } bool LogParam::getUploadeqslQSLMessage() { return getParam("uploadqso/eqsl/last_checkqslsmsg", false).toBool(); } QString LogParam::getUploadeqslQTHProfile() { return getParam("uploadqso/eqsl/last_QTHProfile").toString(); } void LogParam::setUploadeqslQTHProfile(const QString &qthProfile) { setParam("uploadqso/eqsl/last_QTHProfile", qthProfile); } void LogParam::setUploadeqslQSLMessage(const bool state) { setParam("uploadqso/eqsl/last_checkqslsmsg", state); } bool LogParam::getUploadServiceState(const QString &name) { return getParam("uploadqso/" + name + "/enabled", false).toBool(); } void LogParam::setUploadServiceState(const QString &name, bool state) { setParam("uploadqso/" + name + "/enabled", state); } int LogParam::getUploadQSOFilterType() { return getParam("uploadqso/filtertype").toInt(); } void LogParam::setUploadQSOFilterType(int filterID) { setParam("uploadqso/filtertype", filterID); } QString LogParam::getUploadLoTWLocation() { return getParam("uploadqso/lotw/last_location").toString(); } void LogParam::setUploadLoTWLocation(const QString &location) { setParam("uploadqso/lotw/last_location", location); } bool LogParam::getDownloadQSLServiceState(const QString &name) { return getParam("downloadqsl/" + name + "/enabled", false).toBool(); } void LogParam::setDownloadQSLServiceState(const QString &name, bool state) { setParam("downloadqsl/" + name + "/enabled", state); } QDate LogParam::getDownloadQSLServiceLastDate(const QString &name) { return getParam("downloadqsl/" + name + "/lastdate", QDate(1900, 1, 1)).toDate(); } void LogParam::setDownloadQSLServiceLastDate(const QString &name, const QDate &date) { setParam("downloadqsl/" + name + "/lastdate", date); } bool LogParam::getDownloadQSLServiceLastQSOQSL(const QString &name) { return getParam("downloadqsl/" + name + "/qsoqsl", true).toBool(); } void LogParam::setDownloadQSLServiceLastQSOQSL(const QString &name, bool state) { setParam("downloadqsl/" + name + "/qsoqsl", state); } QString LogParam::getDownloadQSLLoTWLastCall() { return getParam("downloadqsl/lotw/lastmycallsign").toString(); } void LogParam::setDownloadQSLLoTWLastCall(const QString &call) { setParam("downloadqsl/lotw/lastmycallsign", call); } QString LogParam::getDownloadQSLeQSLLastProfile() { return getParam("downloadqsl/eqsl/lastqthprofile").toString(); } void LogParam::setDownloadQSLeQSLLastProfile(const QString &profile) { setParam("downloadqsl/eqsl/lastqthprofile", profile); } QString LogParam::getQRZCOMCallbookUsername() { return getParam("services/qrzcom/callbook/username").toString().trimmed(); } void LogParam::setQRZCOMCallbookUsername(const QString &username) { setParam("services/qrzcom/callbook/username", username); } QStringList LogParam::getQRZCOMAPICallsignsList() { return getParamStringList("services/qrzcom/logbook/apicallsigns"); } void LogParam::setQRZCOMAPICallsignsList(const QStringList &list) { setParam("services/qrzcom/logbook/apicallsigns", list); } QString LogParam::getCloudlogAPIEndpoint() { return getParam("services/cloudlog/logbook/endpoint", "http://localhost").toString(); } void LogParam::setCloudlogAPIEndpoint(const QString &endpoint) { setParam("services/cloudlog/logbook/endpoint", endpoint); } uint LogParam::getCloudlogStationID() { return getParam("services/cloudlog/logbook/stationid").toUInt(); } void LogParam::setCloudlogStationID(uint stationID) { setParam("services/cloudlog/logbook/stationid", stationID); } QString LogParam::getClublogLogbookReqEmail() { return getParam("services/clublog/logbook/regemail").toString().trimmed(); } void LogParam::setClublogLogbookReqEmail(const QString &email) { setParam("services/clublog/logbook/regemail", email); } bool LogParam::getClublogUploadImmediatelyEnabled() { return getParam("services/clublog/logbook/uploadimmediately", false).toBool(); } void LogParam::setClublogUploadImmediatelyEnabled(bool state) { setParam("services/clublog/logbook/uploadimmediately", state); } QString LogParam::getEQSLLogbookUsername() { return getParam("services/eqsl/logbook/username").toString().trimmed(); } void LogParam::setEQSLLogbookUsername(const QString &username) { setParam("services/eqsl/logbook/username", username); } QString LogParam::getHamQTHCallbookUsername() { return getParam("services/hamqth/callbook/username").toString().trimmed(); } void LogParam::setHamQTHCallbookUsername(const QString &username) { setParam("services/hamqth/callbook/username", username); } QString LogParam::getHRDLogLogbookReqCallsign() { return getParam("services/hrdlog/logbook/regcallsign").toString().trimmed(); } void LogParam::setHRDLogLogbookReqCallsign(const QString &callsign) { setParam("services/hrdlog/logbook/regcallsign", callsign); } bool LogParam::getHRDLogOnAir() { return getParam("services/hrdlog/logbook/onair", false).toBool(); } void LogParam::setHRDLogOnAir(bool state) { setParam("services/hrdlog/logbook/onair", state); } QString LogParam::getKSTChatUsername() { return getParam("services/kst/chat/username").toString().trimmed(); } void LogParam::setKSTChatUsername(const QString &username) { setParam("services/kst/chat/username", username); } QString LogParam::getLoTWCallbookUsername() { return getParam("services/lotw/callbook/username").toString().trimmed(); } void LogParam::setLoTWCallbookUsername(const QString &username) { setParam("services/lotw/callbook/username", username); } QString LogParam::getLoTWTQSLPath(const QString &defaultPath) { return getParam("services/lotw/callbook/tqsl", defaultPath).toString().trimmed(); } void LogParam::setLoTWTQSLPath(const QString &path) { setParam("services/lotw/callbook/tqsl", path); } bool LogParam::isLoTWTQSLPathKey(const QString &key) { return key.compare("services/lotw/callbook/tqsl", Qt::CaseInsensitive) == 0; } QString LogParam::getPrimaryCallbook(const QString &defaultValue) { return getParam("callbook/primary", defaultValue).toString(); } void LogParam::setPrimaryCallbook(const QString &callbookName) { setParam("callbook/primary", callbookName); } QString LogParam::getSecondaryCallbook(const QString &defaultValue) { return getParam("callbook/secondary", defaultValue).toString(); } void LogParam::setSecondaryCallbook(const QString &callbookName) { setParam("callbook/secondary", callbookName); } QString LogParam::getCallbookWebLookupURL(const QString &defaultURL) { return getParam("callbook/weblookupurl", defaultURL).toString(); } void LogParam::setCallbookWebLookupURL(const QString &url) { setParam("callbook/weblookupurl", url); } QString LogParam::getNetworkNotifLogQSOAddrs() { return getParam("network/notif/log/qso/addrs").toString(); } void LogParam::setNetworkNotifLogQSOAddrs(const QString &addrs) { setParam("network/notif/log/qso/addrs", addrs); } QString LogParam::getNetworkNotifDXCSpotAddrs() { return getParam("network/notif/dxc/spot/addrs").toString(); } void LogParam::setNetworkNotifDXCSpotAddrs(const QString &addrs) { setParam("network/notif/dxc/spot/addrs", addrs); } QString LogParam::getNetworkNotifWSJTXCQSpotAddrs() { return getParam("network/notif/wsjtx/cqspot/addrs").toString(); } void LogParam::setNetworkNotifWSJTXCQSpotAddrs(const QString &addrs) { setParam("network/notif/wsjtx/cqspot/addrs", addrs); } QString LogParam::getNetworkNotifAlertsSpotAddrs() { return getParam("network/notif/alerts/spot/addrs").toString(); } void LogParam::setNetworkNotifAlertsSpotAddrs(const QString &addrs) { setParam("network/notif/alerts/spot/addrs", addrs); } QString LogParam::getNetworkNotifRigStateAddrs() { return getParam("network/notif/rig/state/addrs").toString(); } void LogParam::setNetworkNotifRigStateAddrs(const QString &addrs) { setParam("network/notif/rig/state/addrs", addrs); } int LogParam::getNetworkWsjtxListenerPort(int defaultPort) { return getParam("network/listener/wsjtx/port", defaultPort).toInt(); } void LogParam::setNetworkNotifRigStateAddrs(int port) { setParam("network/listener/wsjtx/port", port); } QString LogParam::getNetworkWsjtxForwardAddrs() { return getParam("network/forwarder/wsjtx/addrs").toString(); } void LogParam::setNetworkWsjtxForwardAddrs(const QString &addrs) { setParam("network/forwarder/wsjtx/addrs", addrs); } bool LogParam::getNetworkWsjtxListenerJoinMulticast() { return getParam("network/listener/wsjtx/multicast/join", false).toBool(); } void LogParam::setNetworkWsjtxListenerJoinMulticast(bool state) { setParam("network/listener/wsjtx/multicast/join", state); } QString LogParam::getNetworkWsjtxListenerMulticastAddr() { return getParam("network/listener/wsjtx/multicast/addr").toString(); } void LogParam::setNetworkWsjtxListenerMulticastAddr(const QString &addr) { setParam("network/listener/wsjtx/multicast/addr", addr); } int LogParam::getNetworkWsjtxListenerMulticastTTL() { return getParam("network/listener/wsjtx/multicast/ttl").toInt(); } void LogParam::setNetworkWsjtxListenerMulticastTTL(int ttl) { setParam("network/listener/wsjtx/multicast/ttl", ttl); } QStringList LogParam::getEnabledMemberlists() { return getParamStringList("memberlist/enabledlists"); } void LogParam::setEnabledMemberlists(const QStringList &list) { setParam("memberlist/enabledlists", list); } int LogParam::getAlertAging() { return getParam("alert/aging").toInt(); } void LogParam::setAlertAging(int aging) { setParam("alert/aging", aging); } QByteArray LogParam::getAlertWidgetState() { return QByteArray::fromBase64(getParam("alert/widgetstate").toByteArray()); } void LogParam::setAlertWidgetState(const QByteArray &state) { setParam("alert/widgetstate", state.toBase64()); } bool LogParam::getCWConsoleSendWord() { return getParam("cwconsole/sendword", false).toBool(); } void LogParam::setCWConsoleSendWord(bool state) { setParam("cwconsole/sendword", state); } bool LogParam::getChatSelectedRoom() { return getParam("chat/selectedroom", 0).toInt(); } void LogParam::setChatSelectedRoom(int room) { setParam("chat/selectedroom", room); } double LogParam::getNewContactFreq() { return getParam("newcontact/freq", 3.5).toDouble(); } void LogParam::setNewContactFreq(double freq) { setParam("newcontact/freq", freq); } QString LogParam::getNewContactMode() { return getParam("newcontact/mode", "CW").toString(); } void LogParam::setNewContactMode(const QString &mode) { setParam("newcontact/mode", mode); } QString LogParam::getNewContactSubMode() { return getParam("newcontact/submode").toString(); } void LogParam::setNewContactSubMode(const QString &submode) { setParam("newcontact/submode", submode); } double LogParam::getNewContactPower() { return getParam("newcontact/power", 100).toDouble(); } void LogParam::setNewContactPower(double power) { setParam("newcontact/power", power); } int LogParam::getNewContactTabIndex() { return getParam("newcontact/tabindex", 0).toInt(); } void LogParam::setNewContactTabIndex(int index) { setParam("newcontact/tabindex", index); } QString LogParam::getNewContactQSLSent() { return getParam("newcontact/sqlsent", "Q").toString(); } void LogParam::setNewContactQSLSent(const QString &qslsent) { setParam("newcontact/sqlsent", qslsent); } QString LogParam::getNewContactLoTWQSLSent() { return getParam("newcontact/lotwsqlsent", "Q").toString(); } void LogParam::setNewContactLoTWQSLSent(const QString &qslsent) { setParam("newcontact/lotwsqlsent", qslsent); } QString LogParam::getNewContactEQSLWQSLSent() { return getParam("newcontact/eqslsqlsent", "Q").toString(); } void LogParam::setNewContactEQSLQSLSent(const QString &qslsent) { setParam("newcontact/eqslsqlsent", qslsent); } QString LogParam::getNewContactQSLVia() { return getParam("newcontact/qslvia").toString(); } void LogParam::setNewContactQSLVia(const QString &qslvia) { setParam("newcontact/qslvia", qslvia); } QString LogParam::getNewContactPropMode() { return getParam("newcontact/propmode").toString(); } void LogParam::setNewContactPropMode(const QString &propmode) { setParam("newcontact/propmode", propmode); } bool LogParam::getNewContactTabsExpanded() { return getParam("newcontact/tabsexpand", true).toBool(); } void LogParam::setNewContactTabsExpanded(bool state) { setParam("newcontact/tabsexpand", state); } QString LogParam::getNewContactSatName() { return getParam("newcontact/satname").toString(); } void LogParam::setNewContactSatName(const QString &name) { setParam("newcontact/satname", name); } QStringList LogParam::getMapLayerStates(const QString &widgetID) { return getKeys(widgetID + "/layerstate/"); } bool LogParam::getMapLayerState(const QString &widgetID, const QString &layerName) { return getParam(widgetID + "/layerstate/" + layerName).toBool(); } void LogParam::setMapLayerState(const QString &widgetID, const QString &layerName, bool state) { setParam(widgetID + "/layerstate/" + layerName, state); } uint LogParam::getWsjtxFilterDxccStatus() { return getParam("wsjtx/filter/dxccstatus", (DxccStatus::NewEntity | DxccStatus::NewBand | DxccStatus::NewMode | DxccStatus::NewSlot | DxccStatus::Worked | DxccStatus::Confirmed)).toUInt(); } void LogParam::setWsjtxFilterDxccStatus(uint mask) { setParam("wsjtx/filter/dxccstatus", mask); } QString LogParam::getWsjtxFilterContRE() { return getParam("wsjtx/filter/contregexp", "NOTHING|AF|AN|AS|EU|NA|OC|SA").toString(); } void LogParam::setWsjtxFilterContRE(const QString &re) { setParam("wsjtx/filter/contregexp", re); } int LogParam::getWsjtxFilterDistance() { return getParam("wsjtx/filter/distance", 0).toInt(); } void LogParam::setWsjtxFilterDistance(int dist) { setParam("wsjtx/filter/distance", dist); } int LogParam::getWsjtxFilterSNR() { return getParam("wsjtx/filter/snr", -41).toInt(); } void LogParam::setWsjtxFilterSNR(int snr) { setParam("wsjtx/filter/snr", snr); } QStringList LogParam::getWsjtxMemberlists() { return getParamStringList("wsjtx/filter/memberlists"); } void LogParam::setWsjtxMemberlists(const QStringList &list) { setParam("wsjtx/filter/memberlists", list); } QByteArray LogParam::getWsjtxWidgetState() { return QByteArray::fromBase64(getParam("wsjtx/widgetstate").toByteArray()); } void LogParam::setWsjtxWidgetState(const QByteArray &state) { setParam("wsjtx/widgetstate", state.toBase64()); } bool LogParam::getWsjtxOutputColorCQSpot() { return getParam("wsjtx/output/colorcqspot", false).toBool(); } void LogParam::setWsjtxOutputColorCQSpot(bool state) { setParam("wsjtx/output/colorcqspot", state); } uint LogParam::getDXCFilterDxccStatus() { return getParam("dxc/filter/dx/dxccstatus", (DxccStatus::NewEntity | DxccStatus::NewBand | DxccStatus::NewMode | DxccStatus::NewSlot | DxccStatus::Worked | DxccStatus::Confirmed)).toUInt(); } void LogParam::setDXCFilterDxccStatus(uint mask) { setParam("dxc/filter/dx/dxccstatus", mask); } QString LogParam::getDXCFilterContRE() { return getParam("dxc/filter/dx/contregexp", "NOTHING|AF|AN|AS|EU|NA|OC|SA").toString(); } void LogParam::setDXCFilterContRE(const QString &re) { setParam("dxc/filter/dx/contregexp", re); } QString LogParam::getDXCFilterSpotterContRE() { return getParam("dxc/filter/spotter/contregexp", "NOTHING|AF|AN|AS|EU|NA|OC|SA").toString(); } void LogParam::setDXCFilterSpotterContRE(const QString &re) { setParam("dxc/filter/spotter/contregexp", re); } bool LogParam::getDXCFilterDedup() { return getParam("dxc/filter/dedup", false).toBool(); } void LogParam::setDXCFilterDedup(bool state) { setParam("dxc/filter/dedup", state); } int LogParam::getDXCFilterDedupTime(int defaultValue) { return getParam("dxc/filter/deduptime", defaultValue).toInt(); } void LogParam::setDXCFilterDedupTime(int value) { setParam("dxc/filter/deduptime", value); } int LogParam::getDXCFilterDedupFreq(int defaultValue) { return getParam("dxc/filter/dedupfreq", defaultValue).toInt(); } void LogParam::setDXCFilterDedupFreq(int value) { setParam("dxc/filter/dedupfreq", value); } QStringList LogParam::getDXCFilterMemberlists() { return getParamStringList("dxc/filter/dx/memberlists"); } void LogParam::setDXCFilterMemberlists(const QStringList &list) { setParam("dxc/filter/dx/memberlists", list); } bool LogParam::getDXCAutoconnectServer() { return getParam("dxc/autoconnect", false).toBool(); } void LogParam::setDXCAutoconnectServer(bool state) { setParam("dxc/autoconnect", state); } bool LogParam::getDXCKeepQSOs() { return getParam("dxc/keepqsos", false).toBool(); } void LogParam::setDXCKeepQSOs(bool state) { setParam("dxc/keepqsos", state); } QByteArray LogParam::getDXCDXTableState() { return QByteArray::fromBase64(getParam("dxc/dxtablestate").toByteArray()); } void LogParam::setDXCDXTableState(const QByteArray &state) { setParam("dxc/dxtablestate", state.toBase64()); } QByteArray LogParam::getDXCWCYTableState() { return QByteArray::fromBase64(getParam("dxc/wcytablestate").toByteArray()); } void LogParam::setDXCWCYTableState(const QByteArray &state) { setParam("dxc/wcytablestate", state.toBase64()); } QByteArray LogParam::getDXCWWVTableState() { return QByteArray::fromBase64(getParam("dxc/wwvtablestate").toByteArray()); } void LogParam::setDXCWWVTableState(const QByteArray &state) { setParam("dxc/wwvtablestate", state.toBase64()); } QByteArray LogParam::getDXCTOALLTableState() { return QByteArray::fromBase64(getParam("dxc/toalltablestate").toByteArray()); } void LogParam::setDXCTOALLTableState(const QByteArray &state) { setParam("dxc/toalltablestate", state.toBase64()); } int LogParam::getDXCConsoleFontSize() { return getParam("dxc/console/fontsize", -1).toInt(); } void LogParam::setDXCConsoleFontSize(int value) { setParam("dxc/console/fontsize", value); } QStringList LogParam::getDXCServerlist() { return getParamStringList("dxc/serverlist", {"hamqth.com:7300"}); } void LogParam::setDXCServerlist(const QStringList &list) { setParam("dxc/serverlist", list); } QString LogParam::getDXCLastServer() { return getParam("dxc/lastserver").toString(); } void LogParam::setDXCLastServer(const QString &server) { setParam("dxc/lastserver", server); } QString LogParam::getDXCFilterModeRE() { QString defaultValue = "NOTHING|" + BandPlan::MODE_GROUP_STRING_PHONE + "|" + BandPlan::MODE_GROUP_STRING_CW + "|" + BandPlan::MODE_GROUP_STRING_FTx + "|" + BandPlan::MODE_GROUP_STRING_DIGITAL; return getParam("dxc/filter/dx/moderegexp", defaultValue).toString(); } void LogParam::setDXCFilterModeRE(const QString &re) { setParam("dxc/filter/dx/moderegexp", re); } QStringList LogParam::getDXCExcludedBands() { return getParamStringList("dxc/filter/excludedbands"); } void LogParam::setDXCExcludedBands(const QStringList &excluded) { setParam("dxc/filter/excludedbands", excluded); } QSet LogParam::getExportColumnSet(const QString ¶mName, const QSet &defaultValue) { QSet set; QStringList defaultValueList; for (int val : defaultValue) defaultValueList << QString::number(val); const QStringList sourceList = getParamStringList("exportadi/" + paramName, defaultValueList); for (const QString &s : sourceList) set.insert(s.toInt()); return set; } void LogParam::setExportColumnSet(const QString ¶mName, const QSet &set) { QStringList valueList; for (int val : set) valueList << QString::number(val); setParam("exportadi/" + paramName, valueList); } QByteArray LogParam::getLogbookState() { return QByteArray::fromBase64(getParam("logbook/maintablestate").toByteArray()); } void LogParam::setLogbookState(const QByteArray &state) { setParam("logbook/maintablestate", state.toBase64()); } int LogParam::getLogbookFilterSearchType(int defaultValue) { return getParam("logbook/filter/searchtype", defaultValue).toInt(); } void LogParam::setLogbookFilterSearchType(int type) { setParam("logbook/filter/searchtype", type); } QString LogParam::getLogbookFilterBand() { return getParam("logbook/filter/band").toString(); } void LogParam::setLogbookFilterBand(const QString &name) { setParam("logbook/filter/band", name); } QString LogParam::getLogbookFilterMode() { return getParam("logbook/filter/mode").toString(); } void LogParam::setLogbookFilterMode(const QString &name) { setParam("logbook/filter/mode", name); } QString LogParam::getLogbookFilterCountry() { return getParam("logbook/filter/country").toString(); } void LogParam::setLogbookFilterCountry(const QString &name) { setParam("logbook/filter/country", name); } QString LogParam::getLogbookFilterUserFilter() { return getParam("logbook/filter/userfilter").toString(); } void LogParam::setLogbookFilterUserFilter(const QString &name) { setParam("logbook/filter/userfilter", name); } QString LogParam::getLogbookFilterClub() { return getParam("logbook/filter/club").toString(); } void LogParam::setLogbookFilterClub(const QString &name) { setParam("logbook/filter/club", name); } QByteArray LogParam::getEncryptedPasswords() { return QByteArray::fromBase64(getParam("security/encryptedpasswords").toByteArray()); } void LogParam::setEncryptedPasswords(const QByteArray &data) { setParam("security/encryptedpasswords", data.toBase64()); } void LogParam::removeEncryptedPasswords() { removeParamGroup("security/encryptedpasswords"); } QString LogParam::getSourcePlatform() { return getParam("sourceplatform").toString(); } void LogParam::setSourcePlatform(const QString &platform) { setParam("sourceplatform", platform); } void LogParam::removeSourcePlatform() { removeParamGroup("sourceplatform"); } bool LogParam::getMainWindowAlertBeep() { return getParam("mainwindow/alertbeep", false).toBool(); } void LogParam::setMainWindowAlertBeep(bool state) { setParam("mainwindow/alertbeep", state); } int LogParam::getMainWindowDarkMode() { return getParam("mainwindow/darkmode", 0).toInt(); } void LogParam::setMainWindowDarkMode(int state) { setParam("mainwindow/darkmode", state); } QByteArray LogParam::getMainWindowGeometry() { return QByteArray::fromBase64(getParam("mainwindow/geometry").toByteArray()); } void LogParam::setMainWindowGeometry(const QByteArray &state) { setParam("mainwindow/geometry", state.toBase64()); } QByteArray LogParam::getMainWindowState() { return QByteArray::fromBase64(getParam("mainwindow/state").toByteArray()); } void LogParam::setMainWindowState(const QByteArray &state) { setParam("mainwindow/state", state.toBase64()); } QString LogParam::getMainWindowBandmapWidgets() { return getParam("mainwindow/bandmapwidgets").toString(); } void LogParam::setMainWindowBandmapWidgets(const QString &value) { setParam("mainwindow/bandmapwidgets", value); } void LogParam::removeMainWindowBandmapWidgets() { removeParamGroup("mainwindow/bandmapwidgets"); } int LogParam::getQslLabelTemplate() { return getParam("qsllabel/template", 0).toInt(); } void LogParam::setQslLabelTemplate(int index) { setParam("qsllabel/template", index); } QString LogParam::getQslLabelFooterLeft() { return getParam("qsllabel/footerleft", "").toString(); } void LogParam::setQslLabelFooterLeft(const QString &text) { setParam("qsllabel/footerleft", text); } QString LogParam::getQslLabelFooterRight() { return getParam("qsllabel/footerright", "TNX & 73").toString(); } void LogParam::setQslLabelFooterRight(const QString &text) { setParam("qsllabel/footerright", text); } int LogParam::getQslLabelSkip() { return getParam("qsllabel/skip", 0).toInt(); } void LogParam::setQslLabelSkip(int count) { setParam("qsllabel/skip", count); } int LogParam::getQslLabelZoom() { return getParam("qsllabel/zoom", 100).toInt(); } void LogParam::setQslLabelZoom(int zoom) { setParam("qsllabel/zoom", zoom); } int LogParam::getQslLabelCustomPageSize() { return getParam("qsllabel/custom_pagesize", 0).toInt(); } void LogParam::setQslLabelCustomPageSize(int pageSizeIndex) { setParam("qsllabel/custom_pagesize", pageSizeIndex); } int LogParam::getQslLabelCustomCols() { return getParam("qsllabel/custom_cols", 3).toInt(); } void LogParam::setQslLabelCustomCols(int cols) { setParam("qsllabel/custom_cols", cols); } int LogParam::getQslLabelCustomRows() { return getParam("qsllabel/custom_rows", 8).toInt(); } void LogParam::setQslLabelCustomRows(int rows) { setParam("qsllabel/custom_rows", rows); } double LogParam::getQslLabelCustomLabelWidth() { return getParam("qsllabel/custom_labelwidth", 70.0).toDouble(); } void LogParam::setQslLabelCustomLabelWidth(double width) { setParam("qsllabel/custom_labelwidth", width); } double LogParam::getQslLabelCustomLabelHeight() { return getParam("qsllabel/custom_labelheight", 35.0).toDouble(); } void LogParam::setQslLabelCustomLabelHeight(double height) { setParam("qsllabel/custom_labelheight", height); } double LogParam::getQslLabelCustomLeftMargin() { return getParam("qsllabel/custom_leftmargin", 0.0).toDouble(); } void LogParam::setQslLabelCustomLeftMargin(double margin) { setParam("qsllabel/custom_leftmargin", margin); } double LogParam::getQslLabelCustomTopMargin() { return getParam("qsllabel/custom_topmargin", 0.0).toDouble(); } void LogParam::setQslLabelCustomTopMargin(double margin) { setParam("qsllabel/custom_topmargin", margin); } double LogParam::getQslLabelCustomHSpacing() { return getParam("qsllabel/custom_hspacing", 0.0).toDouble(); } void LogParam::setQslLabelCustomHSpacing(double spacing) { setParam("qsllabel/custom_hspacing", spacing); } double LogParam::getQslLabelCustomVSpacing() { return getParam("qsllabel/custom_vspacing", 0.0).toDouble(); } void LogParam::setQslLabelCustomVSpacing(double spacing) { setParam("qsllabel/custom_vspacing", spacing); } bool LogParam::getQslLabelPrintBorders() { return getParam("qsllabel/print_borders", false).toBool(); } void LogParam::setQslLabelPrintBorders(bool enabled) { setParam("qsllabel/print_borders", enabled); } QString LogParam::getQslLabelDateFormat() { return getParam("qsllabel/date_format", "yyyy-MM-dd").toString(); } void LogParam::setQslLabelDateFormat(const QString &format) { setParam("qsllabel/date_format", format); } QString LogParam::getQslLabelSansFont() { return getParam("qsllabel/sans_font", QString()).toString(); } void LogParam::setQslLabelSansFont(const QString &family) { setParam("qsllabel/sans_font", family); } QString LogParam::getQslLabelMonoFont() { return getParam("qsllabel/mono_font", QString()).toString(); } void LogParam::setQslLabelMonoFont(const QString &family) { setParam("qsllabel/mono_font", family); } QString LogParam::getQslLabelExtraColumn() { return getParam("qsllabel/extra_column", QString()).toString(); } void LogParam::setQslLabelExtraColumn(const QString &column) { setParam("qsllabel/extra_column", column); } QString LogParam::getQslLabelExtraColumnHeader() { return getParam("qsllabel/extra_column_header", QString()).toString(); } void LogParam::setQslLabelExtraColumnHeader(const QString &header) { setParam("qsllabel/extra_column_header", header); } QString LogParam::getQslLabelToRadioText() { return getParam("qsllabel/to_radio_text", QString()).toString(); } void LogParam::setQslLabelToRadioText(const QString &text) { setParam("qsllabel/to_radio_text", text); } QString LogParam::getQslLabelHdrDate() { return getParam("qsllabel/hdr_date", QString()).toString(); } void LogParam::setQslLabelHdrDate(const QString &text) { setParam("qsllabel/hdr_date", text); } QString LogParam::getQslLabelHdrTime() { return getParam("qsllabel/hdr_time", QString()).toString(); } void LogParam::setQslLabelHdrTime(const QString &text) { setParam("qsllabel/hdr_time", text); } QString LogParam::getQslLabelHdrBand() { return getParam("qsllabel/hdr_band", QString()).toString(); } void LogParam::setQslLabelHdrBand(const QString &text) { setParam("qsllabel/hdr_band", text); } QString LogParam::getQslLabelHdrMode() { return getParam("qsllabel/hdr_mode", QString()).toString(); } void LogParam::setQslLabelHdrMode(const QString &text) { setParam("qsllabel/hdr_mode", text); } QString LogParam::getQslLabelHdrQsl() { return getParam("qsllabel/hdr_qsl", QString()).toString(); } void LogParam::setQslLabelHdrQsl(const QString &text) { setParam("qsllabel/hdr_qsl", text); } int LogParam::getQslLabelMaxRows() { return getParam("qsllabel/max_rows", 4).toInt(); } void LogParam::setQslLabelMaxRows(int rows) { setParam("qsllabel/max_rows", rows); } double LogParam::getQslLabelFontSizeToRadio() { return getParam("qsllabel/font_size_to_radio", 7.5).toDouble(); } void LogParam::setQslLabelFontSizeToRadio(double size) { setParam("qsllabel/font_size_to_radio", size); } double LogParam::getQslLabelFontSizeCallsign() { return getParam("qsllabel/font_size_callsign", 14.0).toDouble(); } void LogParam::setQslLabelFontSizeCallsign(double size) { setParam("qsllabel/font_size_callsign", size); } double LogParam::getQslLabelFontSizeHeader() { return getParam("qsllabel/font_size_header", 7.0).toDouble(); } void LogParam::setQslLabelFontSizeHeader(double size) { setParam("qsllabel/font_size_header", size); } double LogParam::getQslLabelFontSizeData() { return getParam("qsllabel/font_size_data", 8.0).toDouble(); } void LogParam::setQslLabelFontSizeData(double size) { setParam("qsllabel/font_size_data", size); } bool LogParam::setParam(const QString &name, const QVariant &value) { FCT_IDENTIFICATION; qCDebug(function_parameters) << name << value; QSqlQuery query; if ( ! query.prepare("INSERT OR REPLACE INTO log_param (name, value) " "VALUES (:nam, :val)") ) { qWarning()<< "Cannot prepare insert parameter statement for parameter" << name; return false; } query.bindValue(":nam", name); query.bindValue(":val", value); PARAMMUTEXLOCKER; if ( !query.exec() ) { qWarning() << "SET - Cannot exec an insert parameter statement for" << name; return false; } localCache.remove(name); qCDebug(runtime) << "SET:" << name << "value" << value; return true; } QVariant LogParam::getParam(const QString &name, const QVariant &defaultValue) { FCT_IDENTIFICATION; qCDebug(function_parameters) << name; PARAMMUTEXLOCKER; const QVariant *valueCached = localCache.object(name); if ( valueCached ) { qCDebug(runtime) << "GET:" << name << "Cached value: " << *valueCached; return *valueCached; } QSqlQuery query; if ( ! query.prepare("SELECT value FROM log_param WHERE name = :nam") ) { qWarning()<< "GET - Cannot prepare select parameter statement for" << name; return defaultValue; } query.bindValue(":nam", name); if ( ! query.exec() ) { qWarning() << "GET - Cannot execute GetParam Select for" << name << "using default" << defaultValue; return defaultValue; } if ( query.first() ) { if ( !query.isNull(0) ) { QVariant dbValue = query.value(0); localCache.insert(name, new QVariant(dbValue)); qCDebug(runtime) << "GET:" << name << "DB value: " << dbValue; return dbValue; } qCDebug(runtime) << "GET:" << name << "NULL value in DB - using default " << defaultValue; } else qCDebug(runtime) << "GET:" << name << "Key not found in DB - using default " << defaultValue; //localCache.insert(name, new QVariant(defaultValue)); // Do not insert default value here because // in some use cases — for example, DXC and station_profile // the profile is not yet accessible during the first call, // and an empty value is incorrectly inserted into the cache. return defaultValue; } bool LogParam::setParam(const QString &name, const QStringList &value) { FCT_IDENTIFICATION; return setParam(name, serializeStringList(value)); } QStringList LogParam::getParamStringList(const QString &name, const QStringList &defaultValue) { FCT_IDENTIFICATION; return deserializeStringList(getParam(name, serializeStringList(defaultValue)).toString()); } void LogParam::removeParamGroup(const QString ¶mGroup) { FCT_IDENTIFICATION; qCDebug(function_parameters) << paramGroup; PARAMMUTEXLOCKER; const QStringList &keys = localCache.keys(); for ( const QString& key : keys ) if (key.startsWith(paramGroup)) localCache.remove(key); QSqlQuery query; if ( ! query.prepare("DELETE FROM log_param WHERE name LIKE :group ") ) { qWarning()<< "Cannot prepare delete parameter statement for" << paramGroup; return; } query.bindValue(":group", paramGroup + "%"); if ( ! query.exec() ) qWarning() << "Cannot execute removeParamGroup statement for" << paramGroup; return; } QStringList LogParam::getKeys(const QString &group) { FCT_IDENTIFICATION; qCDebug(function_parameters) << group; PARAMMUTEXLOCKER; QSet keys; // unique values; QSqlQuery query; if ( ! query.prepare("SELECT name FROM log_param WHERE name LIKE :group ") ) { qWarning()<< "Cannot prepare select parameter statement for" << group << query.lastError().text(); return QStringList(); } query.bindValue(":group", group + "%"); if ( ! query.exec() ) { qWarning() << "Cannot execute removeParamGroup statement for" << group; return QStringList(); } while ( query.next() ) { const QString ¶m = query.value(0).toString(); const QString &subKey = param.mid(group.length()).section("/", 0, 0); if ( !subKey.isEmpty() ) keys.insert(subKey); } #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) return QStringList(keys.begin(), keys.end()); #else return keys.toList(); #endif } QString LogParam::escapeString(const QString &input, QChar escapeChar, QChar delimiter) { QString result; for (QChar ch : input) { if (ch == escapeChar || ch == delimiter) result += escapeChar; result += ch; } return result; } QString LogParam::unescapeString(const QString &input, QChar escapeChar) { QString result; bool escaping = false; for ( QChar ch : input ) { if ( escaping ) { result += ch; escaping = false; } else if ( ch == escapeChar ) escaping = true; else result += ch; } return result; } QString LogParam::serializeStringList(const QStringList &list, QChar delimiter, QChar escapeChar) { QStringList escapedList; for ( const QString &item : list ) escapedList << escapeString(item, escapeChar, delimiter); return escapedList.join(delimiter); } QStringList LogParam::deserializeStringList(const QString &input, QChar delimiter, QChar escapeChar) { QStringList result; if ( !input.isEmpty() ) { QString current; bool escaping = false; for ( QChar ch : input ) { if ( escaping ) { current += ch; escaping = false; } else if ( ch == escapeChar ) escaping = true; else if ( ch == delimiter ) { result << current; current.clear(); } else current += ch; } result << current; } return result; } QCache LogParam::localCache(300); QMutex LogParam::cacheMutex; #undef PARAMMUTEXLOCKER foldynl-QLog-3252ff9/core/LogParam.h000066400000000000000000000457141517334601000172010ustar00rootroot00000000000000#ifndef QLOG_CORE_LOGPARAM_H #define QLOG_CORE_LOGPARAM_H #include #include #include #include class LogParam : public QObject { Q_OBJECT public: explicit LogParam(QObject *parent = nullptr); /********* * LOV ********/ static bool setLOVParam(const QString &LOVName, const QVariant &value); static QDate getLOVaParam(const QString &LOVName); /********* * Backup ********/ static bool setLastBackupDate(const QDate date); static QDate getLastBackupDate(); /********* * LogID ********/ static bool setLogID(const QString &id); static QString getLogID(); /********* * Contest ********/ static bool setContestSeqnoType(const QVariant &data); static int getContestSeqnoType(); static bool setContestManuDupeType(const QVariant &data); static int getContestDupeType(); static bool setContestLinkExchange(const QVariant &data); static int getContestLinkExchange(); static bool setContestFilter(const QString &filterName); static QString getContestFilter(); static bool setContestID(const QString &contestID); static QString getContestID(); static bool setContestDupeDate(const QDateTime date); static QDateTime getContestDupeDate(); static void removeConetstDupeDate(); /******************** * DXCC Confirmation ********************/ static bool getDxccConfirmedByLotwState(); static bool setDxccConfirmedByLotwState(bool state); static bool setDxccConfirmedByPaperState(bool state); static bool getDxccConfirmedByPaperState(); static bool setDxccConfirmedByEqslState(bool state); static bool getDxccConfirmedByEqslState(); static int getContestSeqno(const QString &band = QString()); static bool setContestSeqno(int value, const QString &band = QString()); static void removeContestSeqno(); /********* * Bandmap *********/ static QStringList bandmapsWidgets(); static void removeBandmapWidgetGroup(const QString &group); static double getBandmapScrollFreq(const QString& widgetID, const QString &bandName); static bool setBandmapScrollFreq(const QString& widgetID, const QString &bandName, double scroll); static QVariant getBandmapZoom(const QString& widgetID, const QString &bandName, const QVariant &defaultValue); static bool setBandmapZoom(const QString& widgetID, const QString &bandName, const QVariant &zoom); static bool setBandmapAging(const QString& widgetID, int aging); static int getBandmapAging(const QString& widgetID); static bool setBandmapCenterRX(const QString& widgetID, bool centerRX); static bool getBandmapCenterRX(const QString& widgetID); static bool setBandmapShowEmergency(const QString& widgetID, bool show); static bool getBandmapShowEmergency(const QString& widgetID); /******************* * UploadQSO Dialog *******************/ static QString getUploadQSOLastCall(); static void setUploadQSOLastCall(const QString &call); static bool getUploadeqslQSLComment(); static void setUploadeqslQSLComment(const bool state); static bool getUploadeqslQSLMessage(); static QString getUploadeqslQTHProfile(); static void setUploadeqslQTHProfile(const QString &qthProfile); static void setUploadeqslQSLMessage(const bool state); static bool getUploadServiceState(const QString& name); static void setUploadServiceState(const QString& name, bool state); static int getUploadQSOFilterType(); static void setUploadQSOFilterType(int filterID); static QString getUploadLoTWLocation(); static void setUploadLoTWLocation(const QString &location); /********************* * DownloadQSL Dialog *********************/ static bool getDownloadQSLServiceState(const QString& name); static void setDownloadQSLServiceState(const QString& name, bool state); static QDate getDownloadQSLServiceLastDate(const QString& name); static void setDownloadQSLServiceLastDate(const QString& name, const QDate &date); static bool getDownloadQSLServiceLastQSOQSL(const QString& name); static void setDownloadQSLServiceLastQSOQSL(const QString& name, bool state); static QString getDownloadQSLLoTWLastCall(); static void setDownloadQSLLoTWLastCall(const QString &call); static QString getDownloadQSLeQSLLastProfile(); static void setDownloadQSLeQSLLastProfile(const QString &profile); /********* * QRZ ********/ static QString getQRZCOMCallbookUsername(); static void setQRZCOMCallbookUsername(const QString& username); static QStringList getQRZCOMAPICallsignsList(); static void setQRZCOMAPICallsignsList(const QStringList &list); /********** * Cloudlog **********/ static QString getCloudlogAPIEndpoint(); static void setCloudlogAPIEndpoint(const QString &endpoint); static uint getCloudlogStationID(); static void setCloudlogStationID(uint stationID); /********* * Clublog ********/ static QString getClublogLogbookReqEmail(); static void setClublogLogbookReqEmail(const QString& email); static bool getClublogUploadImmediatelyEnabled(); static void setClublogUploadImmediatelyEnabled(bool state); /********* * eQSL ********/ static QString getEQSLLogbookUsername(); static void setEQSLLogbookUsername(const QString& username); /********* * HamQTH ********/ static QString getHamQTHCallbookUsername(); static void setHamQTHCallbookUsername(const QString& username); /********* * HRDLog ********/ static QString getHRDLogLogbookReqCallsign(); static void setHRDLogLogbookReqCallsign(const QString& callsign); static bool getHRDLogOnAir(); static void setHRDLogOnAir(bool state); /********* * KSTChat ********/ static QString getKSTChatUsername(); static void setKSTChatUsername(const QString& username); /********* * LoTW ********/ static QString getLoTWCallbookUsername(); static void setLoTWCallbookUsername(const QString& username); static QString getLoTWTQSLPath(const QString &defaultPath); static void setLoTWTQSLPath(const QString& path); static bool isLoTWTQSLPathKey(const QString &key); /******************* * Callbook setting *******************/ static QString getPrimaryCallbook(const QString &defaultValue); static void setPrimaryCallbook(const QString& callbookName); static QString getSecondaryCallbook(const QString &defaultValue); static void setSecondaryCallbook(const QString& callbookName); static QString getCallbookWebLookupURL(const QString &defaultURL); static void setCallbookWebLookupURL(const QString& url); /************************ * Network Notifications ************************/ static QString getNetworkNotifLogQSOAddrs(); static void setNetworkNotifLogQSOAddrs(const QString &addrs); static QString getNetworkNotifDXCSpotAddrs(); static void setNetworkNotifDXCSpotAddrs(const QString &addrs); static QString getNetworkNotifWSJTXCQSpotAddrs(); static void setNetworkNotifWSJTXCQSpotAddrs(const QString &addrs); static QString getNetworkNotifAlertsSpotAddrs(); static void setNetworkNotifAlertsSpotAddrs(const QString &addrs); static QString getNetworkNotifRigStateAddrs(); static void setNetworkNotifRigStateAddrs(const QString &addrs); static int getNetworkWsjtxListenerPort(int defaultPort); static void setNetworkNotifRigStateAddrs(int port); static QString getNetworkWsjtxForwardAddrs(); static void setNetworkWsjtxForwardAddrs(const QString &addrs); static bool getNetworkWsjtxListenerJoinMulticast(); static void setNetworkWsjtxListenerJoinMulticast(bool state); static QString getNetworkWsjtxListenerMulticastAddr(); static void setNetworkWsjtxListenerMulticastAddr(const QString &addr); static int getNetworkWsjtxListenerMulticastTTL(); static void setNetworkWsjtxListenerMulticastTTL(int ttl); /******************** * Club Member Lists ********************/ static QStringList getEnabledMemberlists(); static void setEnabledMemberlists(const QStringList &list); static int getAlertAging(); static void setAlertAging(int aging); static QByteArray getAlertWidgetState(); /*************** * Alert Dialog ***************/ static void setAlertWidgetState(const QByteArray &state); /************* * CW Console *************/ static bool getCWConsoleSendWord(); static void setCWConsoleSendWord(bool state); /********* * Chat ********/ static bool getChatSelectedRoom(); static void setChatSelectedRoom(int room); /************* * NewContact *************/ static double getNewContactFreq(); static void setNewContactFreq(double freq); static QString getNewContactMode(); static void setNewContactMode(const QString &mode); static QString getNewContactSubMode(); static void setNewContactSubMode(const QString &submode); static double getNewContactPower(); static void setNewContactPower(double power); static int getNewContactTabIndex(); static void setNewContactTabIndex(int index); static QString getNewContactQSLSent(); static void setNewContactQSLSent(const QString &qslsent); static QString getNewContactLoTWQSLSent(); static void setNewContactLoTWQSLSent(const QString &qslsent); static QString getNewContactEQSLWQSLSent(); static void setNewContactEQSLQSLSent(const QString &qslsent); static QString getNewContactQSLVia(); static void setNewContactQSLVia(const QString &qslvia); static QString getNewContactPropMode(); static void setNewContactPropMode(const QString &propmode); static bool getNewContactTabsExpanded(); static void setNewContactTabsExpanded(bool state); static QString getNewContactSatName(); static void setNewContactSatName(const QString &name); /************* * Online Map *************/ static QStringList getMapLayerStates(const QString &widgetID); static bool getMapLayerState(const QString &widgetID, const QString &layerName); static void setMapLayerState(const QString &widgetID, const QString &layerName, bool state); /*************** * WSJTX Dialog ***************/ static uint getWsjtxFilterDxccStatus(); static void setWsjtxFilterDxccStatus(uint mask); static QString getWsjtxFilterContRE(); static void setWsjtxFilterContRE(const QString &re); static int getWsjtxFilterDistance(); static void setWsjtxFilterDistance(int dist); static int getWsjtxFilterSNR(); static void setWsjtxFilterSNR(int snr); static QStringList getWsjtxMemberlists(); static void setWsjtxMemberlists(const QStringList &list); static QByteArray getWsjtxWidgetState(); static void setWsjtxWidgetState(const QByteArray &state); static bool getWsjtxOutputColorCQSpot(); static void setWsjtxOutputColorCQSpot(bool state); /****************** * DXCluster Dialog ******************/ static uint getDXCFilterDxccStatus(); static void setDXCFilterDxccStatus(uint mask); static QString getDXCFilterContRE(); static void setDXCFilterContRE(const QString &re); static QString getDXCFilterSpotterContRE(); static void setDXCFilterSpotterContRE(const QString &re); static bool getDXCFilterDedup(); static void setDXCFilterDedup(bool state); static int getDXCFilterDedupTime(int defaultValue); static void setDXCFilterDedupTime(int value); static int getDXCFilterDedupFreq(int defaultValue); static void setDXCFilterDedupFreq(int value); static QStringList getDXCFilterMemberlists(); static void setDXCFilterMemberlists(const QStringList &list); static bool getDXCAutoconnectServer(); static void setDXCAutoconnectServer(bool state); static bool getDXCKeepQSOs(); static void setDXCKeepQSOs(bool state); static QByteArray getDXCDXTableState(); static void setDXCDXTableState(const QByteArray &state); static QByteArray getDXCWCYTableState(); static void setDXCWCYTableState(const QByteArray &state); static QByteArray getDXCWWVTableState(); static void setDXCWWVTableState(const QByteArray &state); static QByteArray getDXCTOALLTableState(); static void setDXCTOALLTableState(const QByteArray &state); static int getDXCConsoleFontSize(); static void setDXCConsoleFontSize(int value); static QStringList getDXCServerlist(); static void setDXCServerlist(const QStringList &list); static QString getDXCLastServer(); static void setDXCLastServer(const QString &server); static QString getDXCFilterModeRE(); static void setDXCFilterModeRE(const QString &re); static QStringList getDXCExcludedBands(); static void setDXCExcludedBands(const QStringList &excluded); static bool setDXCTrendContinent(const QString &cont); static QString getDXCTrendContinent(const QString &def); static void removeDXCTrendContinent(); /************** * Export ADIF **************/ static QSet getExportColumnSet(const QString ¶mName, const QSet &defaultValue); static void setExportColumnSet(const QString ¶mName, const QSet &set); /***************** * Logbook dialog *****************/ static QByteArray getLogbookState(); static void setLogbookState(const QByteArray &state); static int getLogbookFilterSearchType(int defaultValue); static void setLogbookFilterSearchType(int type); static QString getLogbookFilterBand(); static void setLogbookFilterBand(const QString &name); static QString getLogbookFilterMode(); static void setLogbookFilterMode(const QString &name); static QString getLogbookFilterCountry(); static void setLogbookFilterCountry(const QString &name); static QString getLogbookFilterUserFilter(); static void setLogbookFilterUserFilter(const QString &name); static QString getLogbookFilterClub(); static void setLogbookFilterClub(const QString &name); /************************ * Encrypted Passwords ************************/ static QByteArray getEncryptedPasswords(); static void setEncryptedPasswords(const QByteArray &data); static void removeEncryptedPasswords(); static QString getSourcePlatform(); static void setSourcePlatform(const QString &platform); static void removeSourcePlatform(); /************** * Main Window *************/ static bool getMainWindowAlertBeep(); static void setMainWindowAlertBeep(bool state); static int getMainWindowDarkMode(); static void setMainWindowDarkMode(int state); static QByteArray getMainWindowGeometry(); static void setMainWindowGeometry(const QByteArray &state); static QByteArray getMainWindowState(); static void setMainWindowState(const QByteArray &state); static QString getMainWindowBandmapWidgets(); static void setMainWindowBandmapWidgets(const QString &value); static void removeMainWindowBandmapWidgets(); /********************* * QSL Print Labels *********************/ static int getQslLabelTemplate(); static void setQslLabelTemplate(int index); static QString getQslLabelFooterLeft(); static void setQslLabelFooterLeft(const QString &text); static QString getQslLabelFooterRight(); static void setQslLabelFooterRight(const QString &text); static int getQslLabelSkip(); static void setQslLabelSkip(int count); static int getQslLabelZoom(); static void setQslLabelZoom(int zoom); static int getQslLabelCustomPageSize(); static void setQslLabelCustomPageSize(int pageSizeIndex); static int getQslLabelCustomCols(); static void setQslLabelCustomCols(int cols); static int getQslLabelCustomRows(); static void setQslLabelCustomRows(int rows); static double getQslLabelCustomLabelWidth(); static void setQslLabelCustomLabelWidth(double width); static double getQslLabelCustomLabelHeight(); static void setQslLabelCustomLabelHeight(double height); static double getQslLabelCustomLeftMargin(); static void setQslLabelCustomLeftMargin(double margin); static double getQslLabelCustomTopMargin(); static void setQslLabelCustomTopMargin(double margin); static double getQslLabelCustomHSpacing(); static void setQslLabelCustomHSpacing(double spacing); static double getQslLabelCustomVSpacing(); static void setQslLabelCustomVSpacing(double spacing); static bool getQslLabelPrintBorders(); static void setQslLabelPrintBorders(bool enabled); static QString getQslLabelDateFormat(); static void setQslLabelDateFormat(const QString &format); static QString getQslLabelSansFont(); static void setQslLabelSansFont(const QString &family); static QString getQslLabelMonoFont(); static void setQslLabelMonoFont(const QString &family); static QString getQslLabelExtraColumn(); static void setQslLabelExtraColumn(const QString &column); static QString getQslLabelExtraColumnHeader(); static void setQslLabelExtraColumnHeader(const QString &header); static QString getQslLabelToRadioText(); static void setQslLabelToRadioText(const QString &text); static QString getQslLabelHdrDate(); static void setQslLabelHdrDate(const QString &text); static QString getQslLabelHdrTime(); static void setQslLabelHdrTime(const QString &text); static QString getQslLabelHdrBand(); static void setQslLabelHdrBand(const QString &text); static QString getQslLabelHdrMode(); static void setQslLabelHdrMode(const QString &text); static QString getQslLabelHdrQsl(); static void setQslLabelHdrQsl(const QString &text); static int getQslLabelMaxRows(); static void setQslLabelMaxRows(int rows); static double getQslLabelFontSizeToRadio(); static void setQslLabelFontSizeToRadio(double size); static double getQslLabelFontSizeCallsign(); static void setQslLabelFontSizeCallsign(double size); static double getQslLabelFontSizeHeader(); static void setQslLabelFontSizeHeader(double size); static double getQslLabelFontSizeData(); static void setQslLabelFontSizeData(double size); private: static QCache localCache; static QMutex cacheMutex; static bool setParam(const QString&, const QVariant &); static bool setParam(const QString&, const QStringList &); static QVariant getParam(const QString&, const QVariant &defaultValue = QVariant()); static QStringList getParamStringList(const QString&, const QStringList &defaultValue = QStringList()); static void removeParamGroup(const QString&); static QStringList getKeys(const QString &); static QString escapeString(const QString &input, QChar escapeChar = '\\', QChar delimiter = ','); static QString unescapeString(const QString &input, QChar escapeChar = '\\'); static QString serializeStringList(const QStringList &list, QChar delimiter = ',', QChar escapeChar = '\\'); static QStringList deserializeStringList(const QString &input, QChar delimiter = ',', QChar escapeChar = '\\'); }; #endif // QLOG_CORE_LOGPARAM_H foldynl-QLog-3252ff9/core/MembershipQE.cpp000066400000000000000000000560341517334601000203500ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include "MembershipQE.h" #include "core/debug.h" #include "core/LogDatabase.h" #include "data/Callsign.h" #include "LogParam.h" MODULE_IDENTIFICATION("qlog.core.membershipqe"); #define MEMBERLIST_BASE_URL "https://raw.githubusercontent.com/foldynl/hamradio-membeship-lists/main/lists" ClubInfo::ClubInfo(const QString &callsign, const QString &ID, const QDate &validFrom, const QDate &validTo, const QString &club): callsign(callsign), id(ID), validFrom(validFrom), validTo(validTo), club(club) { FCT_IDENTIFICATION; } const QString& ClubInfo::getCallsign() const { return callsign; } const QString& ClubInfo::getID() const { return id; } const QDate& ClubInfo::getValidFrom() const { return validFrom; } const QDate& ClubInfo::getValidTo() const { return validTo; } const QString& ClubInfo::getClubInfo() const { return club; } MembershipQE::MembershipQE(QObject *parent) : QObject{parent}, idClubQueryValid(false), nam(new QNetworkAccessManager(this)) { FCT_IDENTIFICATION; // this thead will help to obtain club status statusQuery.moveToThread(&statusQueryThread); statusQueryThread.start(); connect(&statusQuery, &ClubStatusQuery::status, this, &MembershipQE::statusQueryFinished); connect(nam.data(), &QNetworkAccessManager::finished, this, &MembershipQE::onFinishedListDownload); // prepare SQL query to increase Club query function performance idClubQueryValid = clubQuery.prepare("SELECT DISTINCT callsign, member_id, valid_from, valid_to, clubid FROM membership WHERE callsign = :callsign ORDER BY clubid"); } MembershipQE::~MembershipQE() { FCT_IDENTIFICATION; statusQueryThread.quit(); statusQueryThread.wait(); } // this function is called when async club status returns a result void MembershipQE::statusQueryFinished(const QString &callsign, QMap statuses) { FCT_IDENTIFICATION; emit clubStatusResult(callsign, statuses); } void MembershipQE::saveEnabledClubLists(const QStringList &enabledLists) { FCT_IDENTIFICATION; LogParam::setEnabledMemberlists(enabledLists); } QStringList MembershipQE::getEnabledClubLists() { FCT_IDENTIFICATION; return LogParam::getEnabledMemberlists(); } void MembershipQE::removeClubsFromEnabledClubLists(const QList> &toRemove) { FCT_IDENTIFICATION; qCDebug(runtime) << toRemove; QStringList current = getEnabledClubLists(); for ( const QPair& toRemoveClub : toRemove ) { current.removeAll(toRemoveClub.first); } saveEnabledClubLists(current); } // it is a sync in-thread function to obtain all clubs for an input callsign // it must be as fast as possible QList MembershipQE::query(const QString &in_callsign) { FCT_IDENTIFICATION; qCDebug(function_parameters) << in_callsign; QList ret; if ( !idClubQueryValid ) { qCDebug(runtime) << "Query is not prepared"; return ret; } Callsign qCall(in_callsign); clubQuery.bindValue(":callsign",( qCall.isValid() ) ? qCall.getBase() : in_callsign.toUpper()); if ( ! clubQuery.exec() ) { qCDebug(runtime) << "Cannot query callsign clubs "<< clubQuery.lastError().text(); return ret; } while ( clubQuery.next() ) { QString callsign = clubQuery.value(0).toString(); QString memberid = clubQuery.value(1).toString(); QDate validFrom = QDate::fromString(clubQuery.value(2).toString(), "yyyyMMdd"); QDate validTo = QDate::fromString(clubQuery.value(3).toString(), "yyyyMMdd"); QString clubid = clubQuery.value(4).toString(); qCDebug(runtime) << "Found membership record" << callsign << memberid << validFrom << validTo << clubid; ret << ClubInfo(in_callsign, memberid, validTo, validTo, clubid); } qCDebug(runtime) << "Done"; return ret; } // it is a async query function to obtain club statuses for an input callsign. // the result is returned via signal MembershipStatusQuery::status // it can take some time to obtain a result therefore it is solved in an isolated thread void MembershipQE::asyncQueryDetails(const QString &callsign, const QString &band, const QString &mode) { FCT_IDENTIFICATION; qCDebug(function_parameters) << callsign << band << mode; QMetaObject::invokeMethod(&statusQuery, "getClubStatus", Qt::QueuedConnection, Q_ARG(QString, callsign.toUpper()), Q_ARG(QString, band), Q_ARG(QString, mode), Q_ARG(bool, LogParam::getDxccConfirmedByLotwState()), Q_ARG(bool, LogParam::getDxccConfirmedByPaperState()), Q_ARG(bool, LogParam::getDxccConfirmedByEqslState()) ); } void MembershipQE::updateLists() { FCT_IDENTIFICATION; if ( updatePlan.size() > 0 ) { qWarning() << "Member Club lists are still downloaded. Aborting this update request."; } QStringList enabledLists = getEnabledClubLists(); if ( !removeDisabled(enabledLists) ) { QMessageBox::warning(nullptr, QMessageBox::tr("QLog Warning"), QMessageBox::tr("Club List Update failed. Cannot remove old records")); return; } if ( !planDownloads(enabledLists) ) { QMessageBox::warning(nullptr, QMessageBox::tr("QLog Warning"), QMessageBox::tr("Club List Update failed. Cannot plan new downloads")); return; } startPlannedDownload(); } bool MembershipQE::removeDisabled(const QStringList &enabledLists) { FCT_IDENTIFICATION; QSqlQuery query; if ( ! query.exec(QString("DELETE FROM membership WHERE clubid NOT IN ('%1');").arg(enabledLists.join("','")))) { qWarning() << "Cannot delete records "<< query.lastError().text(); Q_UNUSED(QSqlDatabase::database().rollback()); return false; } if ( ! query.exec(QString("DELETE FROM membership_versions WHERE clubid NOT IN (SELECT DISTINCT clubid FROM membership);"))) { qWarning() << "Cannot delete records from versioning"<< query.lastError().text(); Q_UNUSED(QSqlDatabase::database().rollback()); return false; } qCDebug(runtime) << "DONE"; Q_UNUSED(QSqlDatabase::database().commit()); return true; } bool MembershipQE::planDownloads(const QStringList &enabledLists) { FCT_IDENTIFICATION; QSqlQuery query; if ( ! query.exec(QString("WITH split(word, csv) AS ( SELECT '', '%1'||',' " " UNION ALL " " SELECT substr(csv, 0, instr(csv, ',')), substr(csv, instr(csv, ',') + 1) " " FROM split " " WHERE csv != '' ) " "SELECT clubid, filename " "FROM membership_directory d, " " (SELECT word clubid FROM split " " WHERE word!='' " " EXCEPT " " SELECT clubid " " FROM membership_versions l , " " membership_directory m " " WHERE (l.clubid = m.short_desc) " " AND (version >= m.last_update or m.last_update IS NULL)) a " "WHERE a.clubid = d.short_desc;").arg(enabledLists.join(",")))) { qCWarning(runtime) << "Cannot plan download" << query.lastError().text(); return false; } while ( query.next() ) { updatePlan << QPair(query.value(0).toString(),QString(MEMBERLIST_BASE_URL) + "/" + query.value(1).toString()); } qCDebug(runtime) << "DONE"; return true; } void MembershipQE::startPlannedDownload() { FCT_IDENTIFICATION; if ( updatePlan.size() == 0 ) return; qCDebug(runtime) << "Remaining downloads" << updatePlan.size() << updatePlan; // to prevent network overload, qlog will donwload files one-by-one QPair nextDownload = updatePlan.at(0); QNetworkRequest request(nextDownload.second); QString rheader = QString("QLog/%1").arg(VERSION); request.setRawHeader("User-Agent", rheader.toUtf8()); QNetworkReply *reply = nam->get(request); reply->setProperty("clubid", nextDownload.first); } void MembershipQE::onFinishedListDownload(QNetworkReply *reply) { FCT_IDENTIFICATION; QString clubid = reply->property("clubid").toString(); qCDebug(runtime) << "Received data for Club ID" << clubid << "from" << reply->url().toString(); if ( updatePlan.size() == 0 ) { // Update plan was canceled qCDebug(runtime) << "Download finished for already canceled download - ignore it"; return; } if ( updatePlan.at(0).first != clubid) { qCDebug(runtime) << "Received" << clubid << "but expected" << updatePlan.at(0).first; qCDebug(runtime) << "Canceling all downloads"; removeClubsFromEnabledClubLists(updatePlan); updatePlan.clear(); QMessageBox::critical(nullptr, QMessageBox::tr("QLog Critical"), QMessageBox::tr("Unexpected Club List download. Canceling next downloads")); } int replyStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); bool error = false; if ( reply->isFinished() && reply->error() == QNetworkReply::NoError && replyStatusCode >= 200 && replyStatusCode < 300) { QByteArray data = reply->readAll(); if ( ! importData(clubid, data) ) { QMessageBox::warning(nullptr, QMessageBox::tr("QLog Warning"), QMessageBox::tr("Unexpected Club List content for") + " " + clubid); error = true; } } else { QMessageBox::warning(nullptr, QMessageBox::tr("QLog Warning"), QMessageBox::tr("Network error. Cannot download Club List for") + " " + clubid); qCDebug(runtime) << "Network Error for club" << clubid << replyStatusCode << reply->error(); error = true; } if ( error ) { QList> tmp; tmp << QPair(clubid, ""); removeClubsFromEnabledClubLists(tmp); } if ( updatePlan.size() > 0 ) updatePlan.removeFirst(); reply->deleteLater(); startPlannedDownload(); } bool MembershipQE::importData(const QString &clubid, const QByteArray &data) { FCT_IDENTIFICATION; qCDebug(function_parameters) << clubid; QTextStream stream(data); Q_UNUSED(QSqlDatabase::database().transaction()); QSqlQuery query; QSqlQuery versionQuery; qCDebug(runtime) << "Delete Records for a club" << clubid; if ( ! query.exec(QString("DELETE FROM membership WHERE clubid = '%1';").arg(clubid))) { qWarning() << "Cannot delete records for " << clubid << query.lastError().text(); Q_UNUSED(QSqlDatabase::database().rollback()); return false; } QCoreApplication::processEvents(); qCDebug(runtime) << "Insert data into" << clubid; if ( ! query.prepare(QString("INSERT INTO membership(callsign," " member_id," " valid_from," " valid_to," " clubid" ")" " VALUES (:callsign," " :member_id," " :valid_from," " :valid_to," " '%1'" ")").arg(clubid)) ) { qWarning() << "Cannot prepare Insert statement for membership table" << query.lastError().text(); Q_UNUSED(QSqlDatabase::database().rollback()); return false; } if ( ! versionQuery.prepare(QString("REPLACE INTO membership_versions(clubid, version) " " VALUES (:clubid, :version)") ) ) { qWarning() << "Cannot prepare Insert statement for membership_version table" << versionQuery.lastError().text(); Q_UNUSED(QSqlDatabase::database().rollback()); return false; } QCoreApplication::processEvents(); QString line = stream.readLine(); QStringList fields = line.split(" "); int version; if ( fields.size() == 2 && fields.at(0).at(0) == QChar('#') && (version = fields.at(1).toInt()) != 0) { versionQuery.bindValue(":clubid", clubid); versionQuery.bindValue(":version", version); if ( ! versionQuery.exec() ) { qWarning() << "Membership version insert error " << versionQuery.lastError().text(); Q_UNUSED(QSqlDatabase::database().rollback()); return false; } } else { qCDebug(runtime) << "Unexpected header" << line; Q_UNUSED(QSqlDatabase::database().rollback()); return false; } // skip CSV header stream.readLine(); while ( !stream.atEnd() ) { line = stream.readLine(); fields = line.split(','); if ( fields.count() < 4 ) { qInfo(runtime) << "Invalid line in the input file " << line << clubid; continue; } query.bindValue(":callsign", fields.at(0).toUpper().simplified()); query.bindValue(":member_id", fields.at(1).simplified()); query.bindValue(":valid_from", fields.at(2)); query.bindValue(":valid_to", fields.at(3)); if ( ! query.exec() ) { qWarning() << "membership insert error " << query.lastError().text(); continue; } } qCDebug(runtime) << "DONE"; Q_UNUSED(QSqlDatabase::database().commit()); return true; } ClubStatusQuery::ClubStatusQuery(QObject *parent) : QObject(parent), dbConnectionName("queryThread"), dbConnected(false) { FCT_IDENTIFICATION; } ClubStatusQuery::~ClubStatusQuery() { FCT_IDENTIFICATION; } void ClubStatusQuery::getClubStatus(const QString &in_callsign, const QString &in_band, const QString &in_mode, bool lowtConfirmed, bool paperConfirmed, bool eqslConfirmed) { FCT_IDENTIFICATION; qCDebug(function_parameters) << in_callsign << in_band << in_mode; qCDebug(runtime) << "Waiting for lock"; QMutexLocker locker(&dbLock); qCDebug(runtime) << "Processing getClubStatus"; if ( !dbConnected ) { qCDebug(runtime) << "Opening connection to DB"; QSqlDatabase db1 = QSqlDatabase::addDatabase("QSQLITE", dbConnectionName); db1.setDatabaseName(LogDatabase::dbFilename()); dbConnected = db1.open(); if ( ! dbConnected) { qWarning() << "Cannot open DB Connection for Update"; emit status(in_callsign, QMap()); return; } } QSqlDatabase db1 = QSqlDatabase::database(dbConnectionName); QSqlQuery query(db1); const Callsign qCall(in_callsign); const QString &callModified = ( qCall.isValid() ) ? qCall.getBase() : in_callsign; QStringList dxccConfirmedByCond(QLatin1String("0=1")); // if no option is selected then always false if ( lowtConfirmed ) dxccConfirmedByCond << QLatin1String("c.lotw_qsl_rcvd = 'Y'"); if ( paperConfirmed ) dxccConfirmedByCond << QLatin1String("c.qsl_rcvd = 'Y'"); if ( eqslConfirmed ) dxccConfirmedByCond << QLatin1String("c.eqsl_qsl_rcvd = 'Y'"); if ( ! query.exec(QString("SELECT DISTINCT clubid, NULL band, NULL mode, " " NULL confirmed, NULL current_mode, member_id " "FROM membership WHERE callsign = '%1' " "UNION ALL " "SELECT DISTINCT clubid, c.band, o.dxcc mode, " " CASE WHEN (%2) THEN 1 ELSE 0 END confirmed, " " (SELECT modes.dxcc FROM modes WHERE modes.name = '%3' LIMIT 1) current_mode, " " NULL member_id " "FROM contacts c, " " contact_clubs_view con2club, " " modes o " "WHERE con2club.contactid = c.id " "AND o.name = c.mode " "AND con2club.clubid in (SELECT clubid FROM membership a WHERE a.callsign = '%4') order by 1, 3, 2, 4").arg(callModified, dxccConfirmedByCond.join(" OR "), in_mode, callModified))) { qCWarning(runtime) << "Cannot Get club status" << query.lastError().text(); emit status(in_callsign, QMap()); return; } QMap retMap; QString currentProcessedClub; QString currentMemberID; bool bandMatched = false; bool bandModeMatched = false; bool bandModeConfirmedMatched = false; bool modeMatched = false; unsigned long records = 0L; while ( ++records && query.next() ) { const QString &clubid = query.value(0).toString(); const QString &band = query.value(1).toString(); const QString &mode = query.value(2).toString(); const QVariant &confirmed = query.value(3); const QString ¤t_mode = query.value(4).toString(); const QString &memberID = query.value(5).toString(); qCDebug(runtime) << "Processing" << currentProcessedClub << clubid << band.isEmpty() << band << mode.isEmpty() << mode << confirmed.toString().isEmpty() << confirmed << current_mode.isEmpty(); // the select generates starting line for a new club // Changing the club if ( currentProcessedClub != clubid && band.isEmpty() && mode.isEmpty() && confirmed.toString().isEmpty() && current_mode.isEmpty() ) { if ( !currentProcessedClub.isEmpty() ) { retMap[currentProcessedClub] = ClubInfo(determineClubStatus(bandMatched, bandModeMatched, bandModeConfirmedMatched, modeMatched, records), currentMemberID); } currentProcessedClub = clubid; currentMemberID = memberID; bandMatched = bandModeMatched = bandModeConfirmedMatched = modeMatched = false; records = 0L; continue; } if ( currentProcessedClub == clubid ) { if ( band == in_band ) { bandMatched = true; if ( mode == current_mode ) { bandModeMatched = true; if ( confirmed.toInt() == 1 ) { bandModeConfirmedMatched = true; } } } if ( mode == current_mode ) { modeMatched = true; } } else { qCWarning(runtime) << "Unexpected branch" << currentProcessedClub << clubid; } } if ( !currentProcessedClub.isEmpty() ) { qCDebug(runtime) << "Last Club processing" << currentProcessedClub; retMap[currentProcessedClub] = ClubInfo(determineClubStatus(bandMatched, bandModeMatched, bandModeConfirmedMatched, modeMatched, records), currentMemberID); } qCDebug(runtime) << "DONE"; emit status(in_callsign, retMap); return; } ClubStatusQuery::ClubStatus ClubStatusQuery::determineClubStatus(bool bandMatched, bool bandModeMatched, bool bandModeConfirmedMatched, bool modeMatched, unsigned long records) { FCT_IDENTIFICATION; qCDebug(function_parameters) << bandMatched << bandModeMatched << bandModeConfirmedMatched << modeMatched << records; if ( !bandMatched && !bandModeMatched && !bandModeConfirmedMatched && !modeMatched && records == 1) // records == 1 means that there is only technical row in table { qCDebug(runtime) << "NewClub"; return ClubStatus::NewClub; } if ( !bandMatched ) { if ( !bandModeMatched ) { qCDebug(runtime) << "NewBandModeClub"; return ClubStatus::NewBandModeClub; } else { qCDebug(runtime) << "NewBandClub"; return ClubStatus::NewBandClub; } } if ( !modeMatched ) { qCDebug(runtime) << "NewModeClub"; return ClubStatus::NewModeClub; } if ( ! bandModeMatched ) { qCDebug(runtime) << "NewSlotClub"; return ClubStatus::NewSlotClub; } if ( ! bandModeConfirmedMatched ) { qCDebug(runtime) << "WorkedClub"; return ClubStatus::WorkedClub; } else { qCDebug(runtime) << "ConfirmedClub"; return ClubStatus::ConfirmedClub; } qCWarning(runtime) << "!!!!!!!! Unknown Status - never !!!!!!!!!!"; return ClubStatus::UnknownStatusClub; } foldynl-QLog-3252ff9/core/MembershipQE.h000066400000000000000000000074601517334601000200140ustar00rootroot00000000000000#ifndef QLOG_CORE_MEMBERSHIPQE_H #define QLOG_CORE_MEMBERSHIPQE_H #include #include #include #include #include #include #include class ClubInfo { public: explicit ClubInfo(const QString &callsign, const QString &ID, const QDate &validFrom, const QDate &validTo, const QString &club); const QString& getCallsign() const; const QString& getID() const; const QDate& getValidFrom() const; const QDate& getValidTo() const; const QString& getClubInfo() const; private: QString callsign; QString id; QDate validFrom; QDate validTo; QString club; }; class ClubStatusQuery : public QObject { Q_OBJECT public: explicit ClubStatusQuery(QObject *parent = nullptr); ~ClubStatusQuery(); enum ClubStatus { NewClub = 0b1, NewBandClub = 0b10, NewModeClub = 0b100, NewBandModeClub = 0b110, NewSlotClub = 0b1000, WorkedClub = 0b10000, ConfirmedClub = 0b100000, UnknownStatusClub = 0b1000000, AllClub = 0b1111111 }; Q_ENUM(ClubStatus); struct ClubInfo { ClubInfo(){status = UnknownStatusClub;}; ClubInfo(const ClubStatus status, const QString &memberID) : status(status), membershipID(memberID) {}; ClubStatus status; QString membershipID; }; public slots: void getClubStatus(const QString &in_callsign, const QString &in_band, const QString &in_mode, bool lowtConfirmed, bool paperConfirmed, bool eqslConfirmed); signals: void status(QString, QMap); private: const QString dbConnectionName; bool dbConnected; QMutex dbLock; ClubStatus determineClubStatus(bool, bool, bool, bool, unsigned long); }; Q_DECLARE_METATYPE(ClubStatusQuery::ClubInfo) class MembershipQE : public QObject { Q_OBJECT public: static MembershipQE *instance() { static MembershipQE instance; return &instance; }; static void saveEnabledClubLists(const QStringList &enabledLists); static QStringList getEnabledClubLists(); // return only list of clubs where callsign is a member. QList query(const QString &in_callsign); // return Status for each club // Membership status details can take a long time (depend on the number of records in the log and membership lists) // therefore qlog runs this query in an isolated thread (do not block the main thread). The result is returned via clubStatusResult signal - if exists void asyncQueryDetails(const QString &callsign, const QString &band, const QString &mode); void updateLists(); signals: void clubStatusResult(QString, QMap); private: MembershipQE(QObject *parent = nullptr); ~MembershipQE(); private slots: void statusQueryFinished(const QString &, QMap); void onFinishedListDownload(QNetworkReply *); private: ClubStatusQuery statusQuery; QThread statusQueryThread; bool removeDisabled(const QStringList &enabledLists); bool planDownloads(const QStringList &enabledLists); void startPlannedDownload(); bool importData(const QString &clubid, const QByteArray &data); void removeClubsFromEnabledClubLists(const QList> &toRemove); QSqlQuery clubQuery; bool idClubQueryValid; QList> updatePlan; QScopedPointer nam; }; #endif // QLOG_CORE_MEMBERSHIPQE_H foldynl-QLog-3252ff9/core/Migration.cpp000066400000000000000000001443561517334601000177650ustar00rootroot00000000000000#include #include #include #include #include #include "core/Migration.h" #include "debug.h" #include "data/Data.h" #include "LogParam.h" #include "LOVDownloader.h" #include "service/clublog/ClubLog.h" #include "service/hrdlog/HRDLog.h" #include "logformat/AdxFormat.h" #include "ui/DxWidget.h" #include "core/LogDatabase.h" MODULE_IDENTIFICATION("qlog.core.migration"); /** * Migrate the database to the latest schema version. * Returns true on success. */ bool DBSchemaMigration::run(bool force) { FCT_IDENTIFICATION; int currentVersion = getVersion(); if (currentVersion == latestVersion) { qCDebug(runtime) << "Database schema already up to date"; updateExternalResource(force); // temporarily added to create a trigger without calling db migration //refreshUploadStatusTrigger(); return true; } else if ( currentVersion > latestVersion ) { qCritical() << "Database from the future" << currentVersion; return false; } qCDebug(runtime) << "Backup before migration"; backupAllQSOsToADX(true); qCDebug(runtime) << "Starting database migration"; QProgressDialog progress("Migrating the database...", nullptr, currentVersion, latestVersion); progress.show(); while ((currentVersion = getVersion()) < latestVersion) { bool res = migrate(currentVersion+1); if ( !res || getVersion() == currentVersion ) { progress.close(); return false; } // sometimes (especially when DROP INDEX is called), it is needed to // reopen database. (issue occurs between DB versions 15 and 16) QSqlDatabase::database().close(); if ( !QSqlDatabase::database().open() ) { progress.close(); qCritical() << QSqlDatabase::database().lastError(); return false; } // Re-register custom SQL functions after connection reopen // (sqlite3_create_function bindings are lost on close/open) LogDatabase::instance()->createSQLFunctions(); progress.setValue(currentVersion); } if ( !refreshUploadStatusTrigger() ) { qCritical() << "Cannot refresh Upload Status Trigger"; progress.close(); return false; } progress.close(); updateExternalResource(force); qCDebug(runtime) << "Database migration successful"; return true; } bool DBSchemaMigration::backupAllQSOsToADX(bool force) { FCT_IDENTIFICATION; const int backupCount = 10; const int backupIntervalDays = 7; const QDate &lastBackupDate = LogParam::getLastBackupDate(); const QDate &now = QDate::currentDate(); qCDebug(runtime) << "The last backup date" << lastBackupDate << "Force" << force; if ( !force && lastBackupDate.isValid() && lastBackupDate.addDays(backupIntervalDays) > now ) { qCDebug(runtime) << "Backup skipped"; return true; } const QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); const QString todayBackupName = "qlog_backup_" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".adx"; const QString todayBackupPath = dir.filePath(todayBackupName); // old backup file had a timestamp YYYYMMDDHHmmSS // new backup file has only YYYYMMDD // to be able to clean new and old backup files, following regexp is needed const QRegularExpression regex("^qlog_backup_\\d{8}(\\d{6})?\\.adx$"); const QFileInfoList &fileList = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot); QFileInfoList filteredList; for ( const QFileInfo &fileInfo : fileList ) { if ( regex.match(fileInfo.fileName()).hasMatch() ) // clazy:exclude=use-static-qregularexpression { filteredList.append(fileInfo); } } qCDebug(runtime) << filteredList; // does today backup exists ? if ( !force ) { for ( const QFileInfo &fileInfo : filteredList ) { if ( fileInfo.fileName() == todayBackupName ) { qCDebug(runtime) << "Backup for today already exists: " << todayBackupName; return true; } } } /* Keep the minimum number of backups */ /* If a number of backups is greater than backupCount, remove oldest files */ if ( filteredList.size() >= backupCount ) { std::sort(filteredList.begin(), filteredList.end(), [](const QFileInfo &a, const QFileInfo &b) { return a.fileName() < b.fileName(); }); // remove old files while ( filteredList.size() > backupCount ) { QFileInfo oldestFile = filteredList.takeFirst(); const QString &filepath = oldestFile.absoluteFilePath(); if ( QFile::remove(filepath) ) qCDebug(runtime) << "Removing old backup file: " << filepath; else qWarning() << "Failed to remove old backup file: " << filepath; } } /* Make a backup file */ QFile backupFile(todayBackupPath); if ( !backupFile.open(QFile::ReadWrite | QIODevice::Text) ) { qWarning() << "Cannot open backup file " << todayBackupPath << " for writing"; return false; } qCDebug(runtime) << "Exporting a Database backup to " << todayBackupPath; QTextStream stream(&backupFile); AdxFormat adx(stream); adx.runExport(); stream.flush(); backupFile.close(); LogParam::setLastBackupDate(now); qCDebug(runtime) << "Database backup finished"; return true; } /** * Returns the current user_version of the database. */ int DBSchemaMigration::getVersion() { FCT_IDENTIFICATION; QSqlQuery query("SELECT version FROM schema_versions " "ORDER BY version DESC LIMIT 1"); int i = query.first() ? query.value(0).toInt() : 0; qCDebug(runtime) << i; return i; } /** * Changes the user_version of the database to version. * Returns true of the operation was successful. */ bool DBSchemaMigration::setVersion(int version) { FCT_IDENTIFICATION; qCDebug(function_parameters) << version; QSqlQuery query; if ( ! query.prepare("INSERT INTO schema_versions (version, updated) " "VALUES (:version, datetime('now'))") ) { qWarning() << "Cannot prepare Insert statement"; } query.bindValue(":version", version); if (!query.exec()) { qWarning() << "setting schema version failed" << query.lastError(); return false; } else { return true; } } /** * Migrate the database to the given version. * Returns true if the operation was successful. */ bool DBSchemaMigration::migrate(int toVersion) { FCT_IDENTIFICATION; qCDebug(runtime) << "migrate to" << toVersion; QSqlDatabase db = QSqlDatabase::database(); if (!db.transaction()) { qCritical() << "transaction failed"; return false; } QString migration_file = QString(":/res/sql/migration_%1.sql").arg(toVersion, 3, 10, QChar('0')); bool result = runSqlFile(migration_file); result = result && functionMigration(toVersion); if (result && setVersion(toVersion) && db.commit()) { return true; } else { if (!db.rollback()) { qCritical() << "rollback failed"; } return false; } } bool DBSchemaMigration::runSqlFile(QString filename) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filename; QFile sqlFile(filename); sqlFile.open(QIODevice::ReadOnly | QIODevice::Text); const QStringList &sqlQueries = QTextStream(&sqlFile).readAll().split('\n').join(" ").split(';'); qCDebug(runtime) << sqlQueries; for (const QString &sqlQuery : sqlQueries) { if (sqlQuery.trimmed().isEmpty()) continue; qCDebug(runtime) << sqlQuery; QSqlQuery query; if (!query.exec(sqlQuery)) { qCDebug(runtime) << query.lastError(); return false; } query.finish(); } return true; } bool DBSchemaMigration::functionMigration(int version) { FCT_IDENTIFICATION; bool ret = false; switch ( version ) { case 4: ret = fixIntlFields(); break; case 6: ret = insertUUID(); break; case 15: ret = fillMyDXCC(); break; case 17: ret = createTriggers(); break; case 23: ret = importQSLCards2DB(); break; case 26: ret = fillCQITUZStationProfiles(); break; case 28: ret = resetConfigs(); break; case 29: ret = profiles2DB(); break; case 34: ret = settings2DB(); break; case 35: ret = removeSettings2DB(); break; default: ret = true; } return ret; } int DBSchemaMigration::tableRows(const QString &name) { FCT_IDENTIFICATION; int i = 0; QSqlQuery query(QString("SELECT count(*) FROM %1").arg(name)); i = query.first() ? query.value(0).toInt() : 0; qCDebug(runtime) << i; return i; } bool DBSchemaMigration::updateExternalResource(bool force) { FCT_IDENTIFICATION; LOVDownloader downloader; QProgressDialog progress; connect(&downloader, &LOVDownloader::processingSize, &progress, &QProgressDialog::setMaximum); connect(&downloader, &LOVDownloader::progress, &progress, &QProgressDialog::setValue); connect(&downloader, &LOVDownloader::finished, &progress, &QProgressDialog::done); connect(&downloader, &LOVDownloader::noUpdate, &progress, &QProgressDialog::cancel); connect(&progress, &QProgressDialog::canceled, &downloader, &LOVDownloader::abortRequest); updateExternalResourceProgress(progress, downloader, LOVDownloader::CTY, "(1/8)", force); updateExternalResourceProgress(progress, downloader, LOVDownloader::CLUBLOGCTY, "2/8", force); updateExternalResourceProgress(progress, downloader, LOVDownloader::SATLIST, "(3/8)", force); updateExternalResourceProgress(progress, downloader, LOVDownloader::SOTASUMMITS, "(4/8)", force); updateExternalResourceProgress(progress, downloader, LOVDownloader::WWFFDIRECTORY, "(5/8)", force); updateExternalResourceProgress(progress, downloader, LOVDownloader::IOTALIST, "(6/8)", force); updateExternalResourceProgress(progress, downloader, LOVDownloader::POTADIRECTORY, "(7/8)", force); updateExternalResourceProgress(progress, downloader, LOVDownloader::MEMBERSHIPCONTENTLIST, "(8/8)", force); return true; } void DBSchemaMigration::updateExternalResourceProgress(QProgressDialog& progress, LOVDownloader& downloader, const LOVDownloader::SourceType & sourceType, const QString &counter, bool force) { FCT_IDENTIFICATION; QString stringInfo; progress.reset(); switch ( sourceType ) { case LOVDownloader::SourceType::CTY: stringInfo = tr("DXCC Entities"); break; case LOVDownloader::SourceType::SATLIST: stringInfo = tr("Sats Info"); break; case LOVDownloader::SourceType::SOTASUMMITS: stringInfo = tr("SOTA Summits"); break; case LOVDownloader::SourceType::WWFFDIRECTORY: stringInfo = tr("WWFF Records"); break; case LOVDownloader::SourceType::IOTALIST: stringInfo = tr("IOTA Records"); break; case LOVDownloader::SourceType::POTADIRECTORY: stringInfo = tr("POTA Records"); break; case LOVDownloader::SourceType::MEMBERSHIPCONTENTLIST: stringInfo = tr("Membership Directory Records"); break; case LOVDownloader::SourceType::CLUBLOGCTY: stringInfo = tr("Clublog CTY.XML"); break; default: stringInfo = tr("List of Values"); } progress.setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint); progress.setLabelText(tr("Updating ") + stringInfo + " " + counter +" ..."); progress.setMinimum(0); progress.setModal(true); progress.show(); downloader.update(sourceType, force); if ( progress.wasCanceled() ) qCDebug(runtime) << "Update was canceled"; else { if ( !progress.exec() ) QMessageBox::warning(nullptr, QMessageBox::tr("QLog Warning"), stringInfo + tr(" Update Failed")); } } /* Fixing error when QLog stored UTF characters to non-Intl field of ADIF (contact) table */ /* The fix has two steps * 1) Update contact to move all non-intl to intl fields * 2) transform intl field to non-intl field by calloni removeAccents */ bool DBSchemaMigration::fixIntlFields() { FCT_IDENTIFICATION; QSqlQuery query; QSqlQuery update; if ( !query.prepare( "SELECT id, name, name_intl, " " qth, qth_intl, " " comment, comment_intl, " " my_antenna, my_antenna_intl," " my_city, my_city_intl," " my_rig, my_rig_intl," " my_sig, my_sig_intl," " my_sig_info, my_sig_info_intl," " sig, sig_intl," " sig_info, sig_info_intl " " FROM contacts" ) ) { qWarning()<< " Cannot prepare a migration script - fixIntlField 1"; return false; } if( !query.exec() ) { qWarning()<< "Cannot exec a migration script - fixIntlFields 1"; return false; } if ( !update.prepare("UPDATE contacts SET name = :name," " qth = :qth, " " comment = :comment," " my_antenna = :my_antenna," " my_city = :my_city," " my_rig = :my_rig," " my_sig = :my_sig," " my_sig_info = :my_sig_info," " sig = :sig," " sig_info = :sig_info " "WHERE id = :id") ) { qWarning()<< " Cannot prepare a migration script - fixIntlField 2"; return false; } while( query.next() ) { update.bindValue(":id", query.value("id").toInt()); update.bindValue(":name", fixIntlField(query, "name", "name_intl")); update.bindValue(":qth", fixIntlField(query, "qth", "qth_intl")); update.bindValue(":comment", fixIntlField(query, "comment", "comment_intl")); update.bindValue(":my_antenna", fixIntlField(query, "my_antenna", "my_antenna_intl")); update.bindValue(":my_city", fixIntlField(query, "my_city", "my_city_intl")); update.bindValue(":my_rig", fixIntlField(query, "my_rig", "my_rig_intl")); update.bindValue(":my_sig", fixIntlField(query, "my_sig", "my_sig_intl")); update.bindValue(":my_sig_info",fixIntlField(query, "my_sig_info", "my_sig_info_intl")); update.bindValue(":sig", fixIntlField(query, "sig", "sig_intl")); update.bindValue(":sig_info", fixIntlField(query, "sig_info", "sig_info_intl")); if ( !update.exec()) { qWarning() << "Cannot exec a migration script - fixIntlFields 2"; return false; } } return true; } bool DBSchemaMigration::insertUUID() { FCT_IDENTIFICATION; return LogParam::setLogID(QUuid::createUuid().toString()); } bool DBSchemaMigration::fillMyDXCC() { FCT_IDENTIFICATION; QSqlQuery query; QSqlQuery update; if ( !query.prepare( "SELECT DISTINCT station_callsign FROM contacts" ) ) { qWarning()<< " Cannot prepare a migration script - fillMyDXCC 1" << query.lastError(); return false; } if( !query.exec() ) { qWarning()<< "Cannot exec a migration script - fillMyDXCC 1" << query.lastError(); return false; } if ( !update.prepare("UPDATE contacts " "SET my_dxcc = CASE WHEN my_dxcc IS NULL THEN :my_dxcc ELSE my_dxcc END, " " my_itu_zone = CASE WHEN my_itu_zone IS NULL THEN :my_itu_zone ELSE my_itu_zone END, " " my_cq_zone = CASE WHEN my_cq_zone IS NULL THEN :my_cq_zone ELSE my_cq_zone END, " " my_country = CASE WHEN my_country IS NULL THEN :my_country ELSE my_country END, " " my_country_intl = CASE WHEN my_country_intl IS NULL THEN :my_country_intl ELSE my_country_intl END " "WHERE station_callsign = :station_callsign") ) { qWarning()<< " Cannot prepare a migration script - fillMyDXCC 2" << update.lastError(); return false; } // it is a hack because the migration is running before migration (start/stop database). // It caused that SQL prepared in contructor are incorrectly created. // Therefore, Data are create temporary here Data tmp; while( query.next() ) { QString myCallsign = query.value("station_callsign").toString(); DxccEntity dxccEntity = tmp.lookupDxcc(myCallsign); if ( dxccEntity.dxcc ) { update.bindValue(":my_dxcc", dxccEntity.dxcc); update.bindValue(":my_itu_zone", dxccEntity.ituz); update.bindValue(":my_cq_zone", dxccEntity.cqz); update.bindValue(":my_country_intl", dxccEntity.country); update.bindValue(":my_country", Data::removeAccents(dxccEntity.country)); update.bindValue(":station_callsign", myCallsign); if ( !update.exec()) { qWarning() << "Cannot exec a migration script - fillMyDXCC 2" << update.lastError(); return false; } } } return true; } bool DBSchemaMigration::createTriggers() { FCT_IDENTIFICATION; // Migration procedure does not support to execute SQL code with Triggers. // It will be safer to create triggers here than to fix the migration procedure QSqlQuery query; if ( ! query.exec(QString("CREATE TRIGGER update_callsign_contacts_autovalue " "AFTER UPDATE ON contacts " "FOR EACH ROW " "WHEN OLD.callsign <> NEW.callsign " "BEGIN " " INSERT OR REPLACE INTO contacts_autovalue (contactid, base_callsign) " " VALUES (NEW.id, (WITH tokenizedCallsign(word, csv) AS ( SELECT '', NEW.callsign||'/' " " UNION ALL " " SELECT substr(csv, 0, instr(csv, '/')), substr(csv, instr(csv, '/') + 1) " " FROM tokenizedCallsign " " WHERE csv != '' ) " " SELECT word FROM tokenizedCallsign " " WHERE word != '' AND word REGEXP '^([A-Z][0-9]|[A-Z]{1,2}|[0-9][A-Z])([0-9]|[0-9]+)([A-Z]+)$' LIMIT 1));" "END;"))) { qWarning() << "Cannot create trigger update_callsign_contacts_autovalue " << query.lastError().text(); return false; } if ( ! query.exec(QString("CREATE TRIGGER insert_contacts_autovalue " "AFTER INSERT ON contacts " "FOR EACH ROW " "BEGIN " " INSERT OR REPLACE INTO contacts_autovalue (contactid, base_callsign) " " VALUES (NEW.id, (WITH tokenizedCallsign(word, csv) AS ( SELECT '', NEW.callsign||'/' " " UNION ALL " " SELECT substr(csv, 0, instr(csv, '/')), substr(csv, instr(csv, '/') + 1) " " FROM tokenizedCallsign " " WHERE csv != '' ) " " SELECT word FROM tokenizedCallsign " " WHERE word != '' and word REGEXP '^([A-Z][0-9]|[A-Z]{1,2}|[0-9][A-Z])([0-9]|[0-9]+)([A-Z]+)$' LIMIT 1)); " "END;"))) { qWarning() << "Cannot create trigger update_callsign_contacts_autovalue " << query.lastError().text(); return false; } return true; } bool DBSchemaMigration::importQSLCards2DB() { FCT_IDENTIFICATION; QSettings settings; QSqlQuery insert; // don't migrate eqsl imagge because it is only a local cache. If the image is missing then // QLog will download it again static QRegularExpression re("^[0-9]{8}_([0-9]+)_.*_qsl_(.*)", QRegularExpression::CaseInsensitiveOption); QString qslFolder = settings.value("paperqsl/qslfolder", QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).toString(); QDir dir(qslFolder); const QFileInfoList &file_list = dir.entryInfoList(QStringList("????????_*_*_qsl_*.*"), QDir::Files, QDir::Name); if ( !insert.prepare("INSERT INTO contacts_qsl_cards (contactid, source, name, data) " " VALUES (:contactid, 0, :name, :data)" ) ) { qWarning()<< " Cannot prepare a migration script - importQSLCards2DB 2" << insert.lastError(); return false; } for ( auto &file : file_list ) { qCDebug(runtime) << "Processing file" << file.fileName(); QRegularExpressionMatch match = re.match(file.fileName()); if ( match.hasMatch() ) { qCDebug(runtime) << "File matched - importing"; QFile f(file.absoluteFilePath()); if ( !f.open(QFile::ReadOnly)) { qWarning() << "Cannot open file" << file.fileName(); continue; } QByteArray blob = f.readAll(); f.close(); //do not remove the file - the file may be used by another application //do not use PaperQSL Class here for saving. // this is a migration sequence for filesystem to DB migration with specific properties insert.bindValue(":contactid", match.captured(1)); insert.bindValue(":name", match.captured(2)); insert.bindValue(":data", blob.toBase64()); if ( !insert.exec() ) { qWarning() << "Cannot import QSL file" << file.absoluteFilePath(); continue; } qCDebug(runtime) << "File matched - imported"; } } settings.remove("paperqsl/qslfolder"); settings.remove("eqsl/qslfolder"); return true; } bool DBSchemaMigration::fillCQITUZStationProfiles() { FCT_IDENTIFICATION; QSqlQuery query; QSqlQuery update; if ( !query.prepare( "SELECT DISTINCT callsign FROM station_profiles" ) ) { qWarning()<< " Cannot prepare a migration script - fillCQITUZStationProfiles 1" << query.lastError(); return false; } if( !query.exec() ) { qWarning()<< "Cannot exec a migration script - fillCQITUZStationProfiles 1" << query.lastError(); return false; } if ( !update.prepare("UPDATE station_profiles " "SET ituz = :ituz, cqz = :cqz, dxcc = :dxcc, country = :country " "WHERE upper(callsign) = :callsign") ) { qWarning()<< " Cannot prepare a migration script - fillCQITUZStationProfiles 2" << update.lastError(); return false; } // it is a hack because the migration is running before migration (start/stop database). // It caused that SQL prepared in contructor are incorrectly created. // Therefore, Data are create temporary here Data tmp; while( query.next() ) { const QString &myCallsign = query.value("callsign").toString().toUpper(); const DxccEntity &dxccEntity = tmp.lookupDxcc(myCallsign); if ( dxccEntity.dxcc ) { update.bindValue(":ituz", dxccEntity.ituz); update.bindValue(":cqz", dxccEntity.cqz); update.bindValue(":dxcc", dxccEntity.dxcc); update.bindValue(":country", dxccEntity.country); update.bindValue(":callsign", myCallsign); if ( !update.exec()) { qWarning() << "Cannot exec a migration script - fillCQITUZStationProfiles 2" << update.lastError(); return false; } } } return true; } bool DBSchemaMigration::resetConfigs() { FCT_IDENTIFICATION; // to force redownload CTY file QSettings settings; settings.remove("last_cty_update"); // it changes to sortable view. // I don't know why, but when the layout is saved, the sort indicator // is not displayed when the sortable view is turned on. So I rather remove the view state settings.remove("wsjtx/state"); return true; } bool DBSchemaMigration::profiles2DB() { FCT_IDENTIFICATION; QSettings settings; setSelectedProfile("ant_profiles", settings.value("equipment/ant/profile1", QString()).toString()); settings.remove("equipment/ant/profile1"); setSelectedProfile("cwkey_profiles", settings.value("equipment/cwkey/profile1", QString()).toString()); settings.remove("equipment/cwkey/profile1"); setSelectedProfile("cwshortcut_profiles", settings.value("equipment/cwshortcut/profile1", QString()).toString()); settings.remove("equipment/cwshortcut/profile1"); setSelectedProfile("rig_profiles", settings.value("equipment/rig/profile1", QString()).toString()); settings.remove("equipment/rig/profile1"); setSelectedProfile("rot_profiles", settings.value("equipment/rot/profile1", QString()).toString()); settings.remove("equipment/rot/profile1"); setSelectedProfile("rot_user_buttons_profiles", settings.value("equipment/rotusrbuttons/profile1", QString()).toString()); settings.remove("equipment/rotusrbuttons/profile1"); setSelectedProfile("station_profiles", settings.value("station/profile1", QString()).toString()); settings.remove("station/profile1"); setSelectedProfile("main_layout_profiles", settings.value("newcontact/layoutprofile/profile1", QString()).toString()); settings.remove("newcontact/layoutprofile/profile1"); // LOVs to DB settings.remove("last_cty_update"); settings.remove("last_sat_update"); settings.remove("last_sotasummits_update"); settings.remove("last_wwffdirectory_update"); settings.remove("last_iota_update"); settings.remove("last_pota_update"); settings.remove("last_membershipcontent_update"); settings.remove("dxcc/start"); return true; } bool DBSchemaMigration::removeSettings2DB() { // all platform-independent settings are already in the DB, // no unusual errors occur. It's time to delete old values // ​​from the config. // Only platform-dependent settings remain in the config now. QSettings settings; settings.remove("qrzcom/username"); settings.remove("qrzcom/usernameapi"); settings.remove("clublog/email"); settings.remove("clublog/callsign"); settings.remove("clublog/upload_immediately"); settings.remove("eqsl/username"); settings.remove("eqsl/last_update"); settings.remove("eqsl/last_qsoqsl"); settings.remove("eqsl/last_QTHProfile"); settings.remove("hamqth/username"); settings.remove("hrdlog/callsign"); settings.remove("hrdlog/onair"); settings.remove("kst/username"); settings.remove("lotw/username"); settings.remove("lotw/tqsl"); settings.remove("lotw/last_update"); settings.remove("lotw/last_qsoqsl"); settings.remove("callbook/primary"); settings.remove("callbook/secondary"); settings.remove("callbook/weblookupurl"); settings.remove("network/notification/qso/adi_addrs"); settings.remove("network/notification/dxspot/addrs"); settings.remove("network/notification/wsjtx/cqspot/addrs"); settings.remove("network/notification/alerts/spot/addrs"); settings.remove("network/notification/rig/state/addrs"); settings.remove("network/wsjtx_port"); settings.remove("network/wsjtx_forward"); settings.remove("network/wsjtx_multicast"); settings.remove("network/wsjtx_multicast_addr"); settings.remove("network/wsjtx_multicast_ttl"); settings.remove("memberlists/enabled"); settings.remove("alert/alert_aging"); settings.remove("alert/state"); settings.remove("cwconsole/sendWord"); settings.remove("chat/last_selected_room"); settings.remove("newcontact/frequency"); settings.remove("newcontact/mode"); settings.remove("newcontact/submode"); settings.remove("newcontact/power"); settings.remove("newcontact/tabindex"); settings.remove("newcontact/qslsent"); settings.remove("newcontact/lotwqslsent"); settings.remove("newcontact/eqslqslsent"); settings.remove("newcontact/qslsentvia"); settings.remove("newcontact/propmode"); settings.remove("newcontact/tabsexpanded"); settings.remove("newcontact/satname"); settings.beginGroup("onlinemap"); settings.remove(""); settings.endGroup(); settings.beginGroup("qsodetail"); settings.remove(""); settings.endGroup(); settings.remove("wsjtx/filter_dxcc_status"); settings.remove("wsjtx/filter_cont_regexp"); settings.remove("wsjtx/filter_distance"); settings.remove("wsjtx/filter_snr"); settings.remove("wsjtx/filter_dx_member_list"); settings.remove("wsjtx/state"); settings.remove("dxc/filter_dxcc_status"); settings.remove("dxc/filter_cont_regexp"); settings.remove("dxc/filter_spotter_cont_regexp"); settings.remove("dxc/filter_deduplication"); settings.remove("dxc/filter_duplicationtime"); settings.remove("dxc/filter_deduplicationfreq"); settings.remove("dxc/filter_dx_member_list"); settings.remove("dxc/autoconnect"); settings.remove("dxc/keepqsos"); settings.remove("dxc/dxtablestate"); settings.remove("dxc/wcytablestate"); settings.remove("dxc/wwvtablestate"); settings.remove("dxc/toalltablestate"); settings.remove("dxc/consolefontsize"); settings.remove("dxc/servers"); settings.remove("dxc/last_server"); settings.remove("dxc/filter_mode_cw"); settings.remove("dxc/filter_mode_phone"); settings.remove("dxc/filter_mode_digital"); settings.remove("dxc/filter_mode_ft8"); settings.remove("equipment/rigconnected"); settings.remove("equipment/rotconnected"); settings.remove("equipment/cwkeyconnected"); settings.remove("equipment/keepoptions"); settings.remove("export/min"); settings.remove("export/qsl"); settings.remove("export/c1"); settings.remove("export/c2"); settings.remove("export/c3"); settings.remove("logbook/state"); settings.remove("logbook/filters/band"); settings.remove("logbook/filters/mode"); settings.remove("logbook/filters/country"); settings.remove("logbook/filters/user"); settings.remove("logbook/filters/member"); settings.remove("alertbeep"); settings.remove("darkmode"); settings.remove("geometry"); settings.remove("windowState"); settings.remove("bandmapwidgets"); return true; } bool DBSchemaMigration::settings2DB() { FCT_IDENTIFICATION; QSettings settings; if (settings.contains("qrzcom/username")) LogParam::setQRZCOMCallbookUsername(settings.value("qrzcom/username").toString().trimmed()); if (settings.contains("clublog/email")) LogParam::setClublogLogbookReqEmail(settings.value("clublog/email").toString().trimmed()); if (settings.contains("clublog/upload_immediately")) LogParam::setClublogUploadImmediatelyEnabled(settings.value("clublog/upload_immediately").toBool()); if (settings.contains("eqsl/username")) LogParam::setEQSLLogbookUsername(settings.value("eqsl/username").toString()); if (settings.contains("eqsl/last_update")) LogParam::setDownloadQSLServiceLastDate("eqsl", settings.value("eqsl/last_update").toDate()); if (settings.contains("eqsl/last_qsoqsl")) LogParam::setDownloadQSLServiceLastQSOQSL("eqsl", settings.value("eqsl/last_qsoqsl").toBool()); if (settings.contains("eqsl/last_QTHProfile")) { LogParam::setDownloadQSLeQSLLastProfile(settings.value("eqsl/last_QTHProfile").toString()); LogParam::setUploadeqslQTHProfile(settings.value("eqsl/last_QTHProfile").toString()); } if (settings.contains("hamqth/username")) LogParam::setHamQTHCallbookUsername(settings.value("hamqth/username").toString()); if (settings.contains("hrdlog/callsign")) LogParam::setHRDLogLogbookReqCallsign(settings.value("hrdlog/callsign").toString()); if (settings.contains("hrdlog/onair")) LogParam::setHRDLogOnAir(settings.value("hrdlog/onair").toBool()); if (settings.contains("kst/username")) LogParam::setKSTChatUsername(settings.value("kst/username").toString()); if (settings.contains("lotw/username")) LogParam::setLoTWCallbookUsername(settings.value("lotw/username").toString()); if (settings.contains("lotw/tqsl")) LogParam::setLoTWTQSLPath(settings.value("lotw/tqsl").toString()); if (settings.contains("lotw/last_update")) LogParam::setDownloadQSLServiceLastDate("lotw", settings.value("lotw/last_update").toDate()); if (settings.contains("lotw/last_qsoqsl")) LogParam::setDownloadQSLServiceLastQSOQSL("lotw", settings.value("lotw/last_qsoqsl").toBool()); if (settings.contains("callbook/primary")) LogParam::setPrimaryCallbook(settings.value("callbook/primary").toString()); if (settings.contains("callbook/secondary")) LogParam::setSecondaryCallbook(settings.value("callbook/secondary").toString()); if (settings.contains("callbook/weblookupurl")) LogParam::setCallbookWebLookupURL(settings.value("callbook/weblookupurl").toString()); if (settings.contains("network/notification/qso/adi_addrs")) LogParam::setNetworkNotifLogQSOAddrs(settings.value("network/notification/qso/adi_addrs").toString()); if (settings.contains("network/notification/dxspot/addrs")) LogParam::setNetworkNotifDXCSpotAddrs(settings.value("network/notification/dxspot/addrs").toString()); if (settings.contains("network/notification/wsjtx/cqspot/addrs")) LogParam::setNetworkNotifWSJTXCQSpotAddrs(settings.value("network/notification/wsjtx/cqspot/addrs").toString()); if (settings.contains("network/notification/alerts/spot/addrs")) LogParam::setNetworkNotifAlertsSpotAddrs(settings.value("network/notification/alerts/spot/addrs").toString()); if (settings.contains("network/notification/rig/state/addrs")) LogParam::setNetworkNotifRigStateAddrs(settings.value("network/notification/rig/state/addrs").toString()); if (settings.contains("network/wsjtx_port")) LogParam::setNetworkNotifRigStateAddrs(settings.value("network/wsjtx_port").toInt()); if (settings.contains("network/wsjtx_forward")) LogParam::setNetworkWsjtxForwardAddrs(settings.value("network/wsjtx_forward").toString()); if (settings.contains("network/wsjtx_multicast")) LogParam::setNetworkWsjtxListenerJoinMulticast(settings.value("network/wsjtx_multicast").toBool()); if (settings.contains("network/wsjtx_multicast_addr")) LogParam::setNetworkWsjtxListenerMulticastAddr(settings.value("network/wsjtx_multicast_addr").toString()); if (settings.contains("network/wsjtx_multicast_ttl")) LogParam::setNetworkWsjtxListenerMulticastTTL(settings.value("network/wsjtx_multicast_ttl").toInt()); if (settings.contains("memberlists/enabled")) LogParam::setEnabledMemberlists(settings.value("memberlists/enabled").toStringList()); if (settings.contains("alert/alert_aging")) LogParam::setAlertAging(settings.value("alert/alert_aging").toInt()); if (settings.contains("alert/state")) LogParam::setAlertWidgetState(settings.value("alert/state").toByteArray()); if (settings.contains("cwconsole/sendWord")) LogParam::setCWConsoleSendWord(settings.value("cwconsole/sendWord", false).toBool()); if (settings.contains("chat/last_selected_room")) LogParam::setChatSelectedRoom(settings.value("chat/last_selected_room", 0).toInt()); if (settings.contains("newcontact/frequency")) LogParam::setNewContactFreq(settings.value("newcontact/frequency").toDouble()); if (settings.contains("newcontact/mode")) LogParam::setNewContactMode(settings.value("newcontact/mode").toString()); if (settings.contains("newcontact/submode")) LogParam::setNewContactSubMode(settings.value("newcontact/submode").toString()); if (settings.contains("newcontact/power")) LogParam::setNewContactPower(settings.value("newcontact/power").toDouble()); if (settings.contains("newcontact/tabindex")) LogParam::setNewContactTabIndex(settings.value("newcontact/tabindex", 0).toInt()); if (settings.contains("newcontact/qslsent")) LogParam::setNewContactQSLSent(settings.value("newcontact/qslsent").toString()); if (settings.contains("newcontact/lotwqslsent")) LogParam::setNewContactLoTWQSLSent(settings.value("newcontact/lotwqslsent").toString()); if (settings.contains("newcontact/eqslqslsent")) LogParam::setNewContactEQSLQSLSent(settings.value("newcontact/eqslqslsent").toString()); if (settings.contains("newcontact/qslsentvia")) LogParam::setNewContactQSLVia(settings.value("newcontact/qslsentvia").toString()); if (settings.contains("newcontact/propmode")) LogParam::setNewContactPropMode(settings.value("newcontact/propmode").toString()); if (settings.contains("newcontact/tabsexpanded")) LogParam::setNewContactTabsExpanded(settings.value("newcontact/tabsexpanded").toBool()); if (settings.contains("newcontact/satname")) LogParam::setNewContactSatName(settings.value("newcontact/satname").toString()); settings.beginGroup("onlinemap/layerstate"); const QStringList &onlineLayerKeys = settings.allKeys(); for ( const QString &key : onlineLayerKeys) LogParam::setMapLayerState("onlinemap", key, settings.value(key).toBool()); settings.endGroup(); settings.beginGroup("qsodetail/layerstate"); const QStringList &qsoDetailLayerKeys = settings.allKeys(); for ( const QString &key : qsoDetailLayerKeys) LogParam::setMapLayerState("qsodetail", key, settings.value(key).toBool()); settings.endGroup(); if (settings.contains("wsjtx/filter_dxcc_status")) LogParam::setWsjtxFilterDxccStatus(settings.value("wsjtx/filter_dxcc_status").toUInt()); if (settings.contains("wsjtx/filter_cont_regexp")) LogParam::setWsjtxFilterContRE(settings.value("wsjtx/filter_cont_regexp").toString()); if (settings.contains("wsjtx/filter_distance")) LogParam::setWsjtxFilterDistance(settings.value("wsjtx/filter_distance").toInt()); if (settings.contains("wsjtx/filter_snr")) LogParam::setWsjtxFilterDistance(settings.value("wsjtx/filter_snr").toInt()); if (settings.contains("wsjtx/filter_dx_member_list")) LogParam::setWsjtxMemberlists(settings.value("wsjtx/filter_dx_member_list").toStringList()); if (settings.contains("wsjtx/state")) LogParam::setWsjtxWidgetState(settings.value("wsjtx/state").toByteArray()); if (settings.contains("dxc/filter_dxcc_status")) LogParam::setDXCFilterDxccStatus(settings.value("dxc/filter_dxcc_status").toUInt()); if (settings.contains("dxc/filter_cont_regexp")) LogParam::setDXCFilterContRE(settings.value("dxc/filter_cont_regexp").toString()); if (settings.contains("dxc/filter_spotter_cont_regexp")) LogParam::setDXCFilterSpotterContRE(settings.value("dxc/filter_spotter_cont_regexp").toString()); if (settings.contains("dxc/filter_deduplication")) LogParam::setDXCFilterDedup(settings.value("dxc/filter_deduplication").toBool()); if (settings.contains("dxc/filter_duplicationtime")) LogParam::setDXCFilterDedupTime(settings.value("dxc/filter_duplicationtime").toInt()); if (settings.contains("dxc/filter_deduplicationfreq")) LogParam::setDXCFilterDedupFreq(settings.value("dxc/filter_deduplicationfreq", DEDUPLICATION_FREQ_TOLERANCE).toInt()); if (settings.contains("dxc/filter_dx_member_list")) LogParam::setDXCFilterMemberlists(settings.value("dxc/filter_dx_member_list").toStringList()); if (settings.contains("dxc/autoconnect")) LogParam::setDXCAutoconnectServer(settings.value("dxc/autoconnect").toBool()); if (settings.contains("dxc/keepqsos")) LogParam::setDXCKeepQSOs(settings.value("dxc/keepqsos").toBool()); if (settings.contains("dxc/dxtablestate")) LogParam::setDXCDXTableState(settings.value("dxc/dxtablestate").toByteArray()); if (settings.contains("dxc/wcytablestate")) LogParam::setDXCWCYTableState(settings.value("dxc/wcytablestate").toByteArray()); if (settings.contains("dxc/wwvtablestate")) LogParam::setDXCWWVTableState(settings.value("dxc/wwvtablestate").toByteArray()); if (settings.contains("dxc/toalltablestate")) LogParam::setDXCTOALLTableState(settings.value("dxc/toalltablestate").toByteArray()); if (settings.contains("dxc/consolefontsize")) LogParam::setDXCConsoleFontSize(settings.value("dxc/consolefontsize").toInt()); if (settings.contains("dxc/servers")) LogParam::setDXCServerlist(settings.value("dxc/servers").toStringList()); if (settings.contains("dxc/last_server")) LogParam::setDXCLastServer(settings.value("dxc/last_server").toString()); if (settings.contains("dxc/filter_mode_cw") || settings.contains("dxc/filter_mode_phone") || settings.contains("dxc/filter_mode_digital") || settings.contains("dxc/filter_mode_ft8") ) { QString value("NOTHING"); if ( settings.value("dxc/filter_mode_cw",true).toBool() ) value.append("|" + BandPlan::MODE_GROUP_STRING_CW); if ( settings.value("dxc/filter_mode_phone",true).toBool() ) value.append("|" + BandPlan::MODE_GROUP_STRING_PHONE); if ( settings.value("dxc/filter_mode_digital",true).toBool() ) value.append("|" + BandPlan::MODE_GROUP_STRING_DIGITAL); if ( settings.value("dxc/filter_mode_ft8",true).toBool() ) value.append("|" + BandPlan::MODE_GROUP_STRING_FTx); LogParam::setDXCFilterModeRE(value); } const QList &bands = BandPlan::bandsList(false, true); QStringList excludedBandFilter; for ( const Band &band : bands ) { if ( !settings.value("dxc/filter_band_" + band.name,true).toBool()) excludedBandFilter << band.name; } if ( !excludedBandFilter.isEmpty() ) LogParam::setDXCExcludedBands(excludedBandFilter); if (settings.contains("export/min")) LogParam::setExportColumnSet("min", settings.value("export/min").value>()); if (settings.contains("export/sql")) LogParam::setExportColumnSet("sql", settings.value("export/sql").value>()); if (settings.contains("export/c1")) LogParam::setExportColumnSet("c1", settings.value("export/c1").value>()); if (settings.contains("export/c2")) LogParam::setExportColumnSet("c2", settings.value("export/c2").value>()); if (settings.contains("export/c3")) LogParam::setExportColumnSet("c3", settings.value("export/c3").value>()); if (settings.contains("logbook/state")) LogParam::setLogbookState(settings.value("logbook/state").toByteArray()); if (settings.contains("logbook/filters/band")) LogParam::setLogbookFilterBand(settings.value("logbook/filters/band").toString()); if (settings.contains("logbook/filters/mode")) LogParam::setLogbookFilterMode(settings.value("logbook/filters/mode").toString()); if (settings.contains("logbook/filters/country")) LogParam::setLogbookFilterCountry(settings.value("logbook/filters/country").toString()); if (settings.contains("logbook/filters/user")) LogParam::setLogbookFilterUserFilter(settings.value("logbook/filters/user").toString()); if (settings.contains("logbook/filters/member")) LogParam::setLogbookFilterClub(settings.value("logbook/filters/member").toString()); if (settings.contains("alertbeep")) LogParam::setMainWindowAlertBeep(settings.value("alertbeep").toBool()); if (settings.contains("darkmode")) LogParam::setMainWindowDarkMode(settings.value("darkmode").toBool()); if (settings.contains("geometry")) LogParam::setMainWindowGeometry(settings.value("geometry").toByteArray()); if (settings.contains("windowState")) LogParam::setMainWindowState(settings.value("windowState").toByteArray()); if (settings.contains("bandmapwidgets")) LogParam::setMainWindowBandmapWidgets(settings.value("bandmapwidgets").toString()); return true; } bool DBSchemaMigration::setSelectedProfile(const QString &tablename, const QString &profileName) { FCT_IDENTIFICATION; QSqlQuery query; if ( !query.prepare(QString("UPDATE %1 " "SET selected = CASE " " WHEN profile_name = :profileName THEN 1 " " ELSE NULL " " END " "WHERE selected = 1 OR profile_name = :profileName2").arg(tablename)) ) { qWarning() << "Cannot prepare Update statement for" << tablename; return false; } query.bindValue(":profileName", profileName); query.bindValue(":profileName2", profileName); if( !query.exec() ) { qWarning()<< "Cannot update the profile" << tablename << profileName << query.lastError(); return false; } return true; } QString DBSchemaMigration::fixIntlField(const QSqlQuery &query, const QString &columName, const QString &columnNameIntl) { FCT_IDENTIFICATION; QString retValue; QString fieldValue = query.value(columName).toString(); if ( !fieldValue.isEmpty() ) { retValue = Data::removeAccents(fieldValue); } else { retValue = Data::removeAccents(query.value(columnNameIntl).toString()); } return retValue; } bool DBSchemaMigration::refreshUploadStatusTrigger() { FCT_IDENTIFICATION; QSqlQuery query("SELECT name " "FROM PRAGMA_TABLE_INFO('contacts') c " "WHERE c.name NOT IN ('clublog_qso_upload_date', " " 'clublog_qso_upload_status', " " 'hrdlog_qso_upload_date', " " 'hrdlog_qso_upload_status', " " 'qrzcom_qso_upload_date', " " 'qrzcom_qso_upload_status', " " 'hamlogeu_qso_upload_date', " " 'hamlogeu_qso_upload_status', " " 'hamqth_qso_upload_date', " " 'hamqth_qso_upload_status')"); if ( !query.exec() ) { qWarning() << "Cannot get Contacts columns"; return false; } QStringList whenClause; QStringList afterUpdateClause; while ( query.next() ) { const QString &columnName = query.value(0).toString(); afterUpdateClause << QString("\"" + columnName + "\""); whenClause << QString("old.\"%1\" != new.\"%2\"").arg(columnName, columnName); } QSqlQuery stmt; if ( !stmt.exec("DROP TRIGGER IF EXISTS update_contacts_upload_status") ) { qWarning() << "Cannot drop all Update Contacts Upload Trigger"; return false; } auto generateListSpecificConditions = [](const QStringList &columns) { QStringList result; for (const QString &col : columns) result << QString("old.\"%1\" != new.\"%2\"").arg(col, col); return result.join(" OR "); }; if ( !stmt.exec(QString("CREATE TRIGGER update_contacts_upload_status " "AFTER UPDATE OF %1 " "ON contacts " "WHEN (%2) " "BEGIN " " UPDATE contacts " " SET hrdlog_qso_upload_status = CASE WHEN old.hrdlog_qso_upload_status = 'Y' AND (%3) THEN 'M' ELSE old.hrdlog_qso_upload_status END, " " qrzcom_qso_upload_status = CASE WHEN old.qrzcom_qso_upload_status = 'Y' THEN 'M' ELSE old.qrzcom_qso_upload_status END , " " hamlogeu_qso_upload_status = CASE WHEN old.hamlogeu_qso_upload_status = 'Y' THEN 'M' ELSE old.hamlogeu_qso_upload_status END , " " hamqth_qso_upload_status = CASE WHEN old.hamqth_qso_upload_status = 'Y' THEN 'M' ELSE old.hamqth_qso_upload_status END , " " clublog_qso_upload_status = CASE WHEN old.clublog_qso_upload_status = 'Y' AND (%4) THEN 'M' ELSE old.clublog_qso_upload_status END " " WHERE id = new.id;" " UPDATE contacts_autovalue " " SET wavelog_qso_upload_status = 'M' " " WHERE contactid = new.id AND wavelog_qso_upload_status = 'Y'; " "END").arg(afterUpdateClause.join(","), whenClause.join(" OR "), generateListSpecificConditions(HRDLogUploader::uploadedFields), generateListSpecificConditions(ClubLogUploader::uploadedFields))) ) { qWarning().noquote() << "Cannot create Update Contacts Upload Trigger" << stmt.lastQuery(); return false; } return true; } foldynl-QLog-3252ff9/core/Migration.h000066400000000000000000000030441517334601000174160ustar00rootroot00000000000000#ifndef QLOG_CORE_MIGRATION_H #define QLOG_CORE_MIGRATION_H #include "core/LOVDownloader.h" class QProgressDialog; class DBSchemaMigration : public QObject { Q_OBJECT public: DBSchemaMigration(QObject *parent = nullptr) : QObject(parent) {} bool run(bool force = false); static bool backupAllQSOsToADX(bool force = false); static constexpr int latestVersion = 38; private: bool functionMigration(int version); bool migrate(int toVersion); int getVersion(); bool setVersion(int version); bool runSqlFile(QString filename); int tableRows(const QString &name); bool updateExternalResource(bool force = false); void updateExternalResourceProgress(QProgressDialog&, LOVDownloader&, const LOVDownloader::SourceType & sourceType, const QString &counter, bool force = false); bool fixIntlFields(); bool insertUUID(); bool fillMyDXCC(); bool createTriggers(); bool importQSLCards2DB(); bool fillCQITUZStationProfiles(); bool resetConfigs(); bool profiles2DB(); bool settings2DB(); bool removeSettings2DB(); bool setSelectedProfile(const QString &tablename, const QString &profileName); QString fixIntlField(const QSqlQuery &query, const QString &columName, const QString &columnNameIntl); bool refreshUploadStatusTrigger(); friend class MigrationSqlTest_FriendAccessor; }; #endif // QLOG_CORE_MIGRATION_H foldynl-QLog-3252ff9/core/NetworkNotification.cpp000066400000000000000000000520261517334601000220240ustar00rootroot00000000000000#include #include "NetworkNotification.h" #include "debug.h" #include "LogParam.h" MODULE_IDENTIFICATION("qlog.ui.networknotification"); NetworkNotification::NetworkNotification(QObject *parent) : QObject(parent) { FCT_IDENTIFICATION; } QString NetworkNotification::getNotifQSOAdiAddrs() { FCT_IDENTIFICATION; return LogParam::getNetworkNotifLogQSOAddrs(); } void NetworkNotification::saveNotifQSOAdiAddrs(const QString &addresses) { FCT_IDENTIFICATION; LogParam::setNetworkNotifLogQSOAddrs(addresses); } QString NetworkNotification::getNotifDXSpotAddrs() { FCT_IDENTIFICATION; return LogParam::getNetworkNotifDXCSpotAddrs(); } void NetworkNotification::saveNotifDXSpotAddrs(const QString &addresses) { FCT_IDENTIFICATION; LogParam::setNetworkNotifDXCSpotAddrs(addresses); } QString NetworkNotification::getNotifWSJTXCQSpotAddrs() { FCT_IDENTIFICATION; return LogParam::getNetworkNotifWSJTXCQSpotAddrs(); } void NetworkNotification::saveNotifWSJTXCQSpotAddrs(const QString &addresses) { FCT_IDENTIFICATION; LogParam::setNetworkNotifWSJTXCQSpotAddrs(addresses); } QString NetworkNotification::getNotifSpotAlertAddrs() { FCT_IDENTIFICATION; return LogParam::getNetworkNotifAlertsSpotAddrs(); } void NetworkNotification::saveNotifSpotAlertAddrs(const QString &addresses) { FCT_IDENTIFICATION; LogParam::setNetworkNotifAlertsSpotAddrs(addresses); } QString NetworkNotification::getNotifRigStateAddrs() { FCT_IDENTIFICATION; return LogParam::getNetworkNotifRigStateAddrs(); } void NetworkNotification::saveNotifRigStateAddrs(const QString &addresses) { FCT_IDENTIFICATION; LogParam::setNetworkNotifRigStateAddrs(addresses); } void NetworkNotification::QSOInserted(const QSqlRecord &record) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "Inserted: " << record; HostsPortString destList(getNotifQSOAdiAddrs()); if ( destList.getAddrList().size() > 0 ) { QSONotificationMsg qsoMsg(record, QSONotificationMsg::QSO_INSERT); send(qsoMsg.getJson(), destList); } } void NetworkNotification::QSOUpdated(const QSqlRecord &record) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "Updated: " << record; HostsPortString destList(getNotifQSOAdiAddrs()); if ( destList.getAddrList().size() > 0 ) { QSONotificationMsg qsoMsg(record, QSONotificationMsg::QSO_UPDATE); send(qsoMsg.getJson(), destList); } } void NetworkNotification::QSODeleted(const QSqlRecord &record) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "Deleted: " << record; HostsPortString destList(getNotifQSOAdiAddrs()); if ( destList.getAddrList().size() > 0 ) { QSONotificationMsg qsoMsg(record, QSONotificationMsg::QSO_DELETE); send(qsoMsg.getJson(), destList); } } void NetworkNotification::dxSpot(const DxSpot &spot) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "DX Spot"; HostsPortString destList(getNotifDXSpotAddrs()); if ( destList.getAddrList().size() > 0 ) { DXSpotNotificationMsg dxSpotMsg(spot); send(dxSpotMsg.getJson(), destList); } } void NetworkNotification::wcySpot(const WCYSpot &spot) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "WCY Spot"; HostsPortString destList(getNotifDXSpotAddrs()); if ( destList.getAddrList().size() > 0 ) { WCYSpotNotificationMsg WCYSpotMsg(spot); send(WCYSpotMsg.getJson(), destList); } } void NetworkNotification::wwvSpot(const WWVSpot &spot) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "WWV Spot"; HostsPortString destList(getNotifDXSpotAddrs()); if ( destList.getAddrList().size() > 0 ) { WWVSpotNotificationMsg WWVSpotMsg(spot); send(WWVSpotMsg.getJson(), destList); } } void NetworkNotification::toAllSpot(const ToAllSpot &spot) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "ToALL Spot"; HostsPortString destList(getNotifDXSpotAddrs()); if ( destList.getAddrList().size() > 0 ) { ToAllSpotNotificationMsg ToAllSpotMsg(spot); send(ToAllSpotMsg.getJson(), destList); } } void NetworkNotification::WSJTXCQSpot(const WsjtxEntry &spot) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "WSJTX CQ Spot"; HostsPortString destList(getNotifWSJTXCQSpotAddrs()); if ( destList.getAddrList().size() > 0 ) { WSJTXCQSpotNotificationMsg dxSpotMsg(spot); send(dxSpotMsg.getJson(), destList); } } void NetworkNotification::spotAlert(const SpotAlert &spot) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "Usert Alert"; HostsPortString destList(getNotifSpotAlertAddrs()); if ( destList.getAddrList().size() > 0 ) { SpotAlertNotificationMsg spotAlertMsg(spot); send(spotAlertMsg.getJson(), destList); } } void NetworkNotification::rigStatus(const Rig::Status &status) { FCT_IDENTIFICATION; qCDebug(function_parameters) << "Rig Status"; HostsPortString destList(getNotifRigStateAddrs()); if ( destList.getAddrList().size() > 0 ) { RigStatusNotificationMsg rigStatusMsg(status); send(rigStatusMsg.getJson(), destList); } } void NetworkNotification::send(const QByteArray &data, const HostsPortString &dests) { FCT_IDENTIFICATION; qCDebug(function_parameters) << QString(data); if ( data.isEmpty() ) return; const QList &addrList = dests.getAddrList(); for ( const HostPortAddress &addr : addrList ) { qCDebug(runtime) << "Sending to " << addr; udpSocket.writeDatagram(data, addr, addr.getPort()); } } GenericNotificationMsg::GenericNotificationMsg(QObject *parent) : QObject(parent) { FCT_IDENTIFICATION; msg["appid"] = "QLog"; msg["logid"] = LogParam::getLogID(); msg["time"] = QDateTime::currentMSecsSinceEpoch(); } /* QSO Notification Message * Example * { "appid":"QLog", "data":{ "operation":"insert", "rowid":355, "type":"adif", "value":"OK1TEST2022032018353620220320183557599599Testing NamePragueJO70GB152810.1264930mCWEU503Czech RepublicNNNN530m9.266243887046823NN10.12649N1.33PRAHAJO70GDmoje_noveLADAS94OK1MLG" }, "logid":"{2046e323-b340-4634-8d52-4e70a4231978}", "msgtype":"qso", "time":1647801358067 } * More info https://github.com/foldynl/QLog/wiki/Notifications */ QSONotificationMsg::QSONotificationMsg(const QSqlRecord &record, const QSOOperation operation, QObject *parent) : GenericNotificationMsg(parent) { FCT_IDENTIFICATION; QString data; QTextStream stream(&data, QIODevice::ReadWrite); /* currently only ADIF is supported */ /* ADX and JSON do not support export single record */ LogFormat* format = LogFormat::open(LogFormat::ADI, stream); if (!format) { qWarning() << "cannot created ADIF Export Formatter"; return; } //format->exportStart(); format->exportContact(record); stream.flush(); //format->exportEnd(); QJsonObject qsoData; qsoData["operation"] = QSOOperation2String.value(operation,"unknown"); qsoData["type"] = "adif"; qsoData["rowid"] = record.value(record.indexOf("id")).toInt(); qsoData["value"] = data.replace("\n", ""); msg["msgtype"] = "qso"; msg["data"] = qsoData; delete format; } /* DXC Spot Message * Example * { "appid": "QLog", "data": { "band": "40m", "comment": "tnx qso", "dx": { "call": "YB0AR", "cont": "OC", "country": "Indonesia", "cqz": 28, "dxcc": 327, "ituz": 54, "member": ["LoTW", "eQSLAG"] "pfx": "YB", "utcoffset": -7 }, "freq": "7.1880", "mode": "PHONE", "rcvtime": "20220316 20:04:30", "spotter": { "call": "G0DEF", "cont": "EU", "country": "England", "cqz": 14, "dxcc": 223, "ituz": 27, "pfx": "G", "utcoffset": 0 }, "status": "newentity" }, "logid":"{2046e323-b340-4634-8d52-4e70a4231978}", "msgtype": "dxspot", "time": 1647461070837 } * More info https://github.com/foldynl/QLog/wiki/Notifications */ DXSpotNotificationMsg::DXSpotNotificationMsg(const DxSpot &spot, QObject *parent) : GenericSpotNotificationMsg(parent) { FCT_IDENTIFICATION; QJsonObject spotData; spotData["rcvtime"] = spot.dateTime.toString("yyyyMMdd hh:mm:ss"); spotData["freq"] = qRound(spot.freq * 10000.0) / 10000.0; spotData["band"] = spot.band; spotData["mode"] = spot.modeGroupString; spotData["comment"] = spot.comment; spotData["status"] = DxccStatus2String.value(spot.status, "unknown"); QJsonObject dxInfo; dxInfo["call"] = spot.callsign; dxInfo["country"] = spot.dxcc.country; dxInfo["pfx"] = spot.dxcc.prefix; dxInfo["dxcc"] = spot.dxcc.dxcc; dxInfo["cont"] = spot.dxcc.cont; dxInfo["cqz"] = spot.dxcc.cqz; dxInfo["ituz"] = spot.dxcc.ituz; dxInfo["utcoffset"] = spot.dxcc.tz; dxInfo["member"] = QJsonArray::fromStringList(spot.memberList2StringList()); QJsonObject spotterInfo; spotterInfo["call"] = spot.spotter; spotterInfo["country"] = spot.dxcc_spotter.country; spotterInfo["pfx"] = spot.dxcc_spotter.prefix; spotterInfo["dxcc"] = spot.dxcc_spotter.dxcc; spotterInfo["cont"] = spot.dxcc_spotter.cont; spotterInfo["cqz"] = spot.dxcc_spotter.cqz; spotterInfo["ituz"] = spot.dxcc_spotter.ituz; spotterInfo["utcoffset"] = spot.dxcc_spotter.tz; spotData["spotter"] = spotterInfo; spotData["dx"] = dxInfo; msg["msgtype"] = "dxspot"; msg["data"] = spotData; } /* WSJTX Spot Message * Example * { "appid":"QLog", "data":{ "band":"80m", "comment":"CQ OK1MLG JO70", "dx":{ "call":"OK1MLG", "cont":"EU", "country":"Europe", "cqz":15, "dxcc":503, "grid":"JO70", "ituz":28, "member":["LOTW", "eQSLAG"] "pfx":"OK", "utcoffset":-2 }, "freq":"3.5730", "mode":"FT8", "rcvtime":"20220318 17:04:29", "status":"newband" }, "logid":"{2046e323-b340-4634-8d52-4e70a4231978}", "msgtype":"wsjtxcqspot", "time":1647623069705 } * More info https://github.com/foldynl/QLog/wiki/Notifications */ WSJTXCQSpotNotificationMsg::WSJTXCQSpotNotificationMsg(const WsjtxEntry &spot, QObject *parent) : GenericSpotNotificationMsg(parent) { FCT_IDENTIFICATION; QJsonObject spotData; spotData["rcvtime"] = spot.receivedTime.toString("yyyyMMdd hh:mm:ss"); spotData["freq"] = qRound(spot.freq * 10000.0) / 10000.0; spotData["band"] = spot.band; spotData["mode"] = spot.decodedMode; spotData["comment"] = spot.decode.message; spotData["status"] = DxccStatus2String.value(spot.status, "unknown"); QJsonObject dxInfo; dxInfo["call"] = spot.callsign; dxInfo["country"] = spot.dxcc.country; dxInfo["pfx"] = spot.dxcc.prefix; dxInfo["dxcc"] = spot.dxcc.dxcc; dxInfo["cont"] = spot.dxcc.cont; dxInfo["cqz"] = spot.dxcc.cqz; dxInfo["ituz"] = spot.dxcc.ituz; dxInfo["utcoffset"] = spot.dxcc.tz; dxInfo["grid"] = spot.grid; dxInfo["member"] = QJsonArray::fromStringList(spot.memberList2StringList()); spotData["dx"] = dxInfo; msg["msgtype"] = "wsjtxcqspot"; msg["data"] = spotData; } GenericSpotNotificationMsg::GenericSpotNotificationMsg(QObject *parent) : GenericNotificationMsg(parent) { FCT_IDENTIFICATION; } /* Spot Alert Message * Example * { "appid":"QLog", "data":{ "band":"17m", "comment":"CW 7 dB 25 WPM CQ ", "dx":{ "call":"ZL3CW", "cont":"OC", "country":"New Zealand", "cqz":32, "dxcc":170, "ituz":60, "member": ["LOTW", "eQSLAG"] "pfx":"ZL", "utcoffset":-12 }, "freq":18.073, "mode":"CW", "rcvtime":"20220510 08:42:34", "rules":[ "rule1", "rule2" ], "spotter":{ "call":"SM6FMB", "cont":"EU", "country":"Sweden", "cqz":14, "dxcc":284, "ituz":18, "pfx":"SM", "utcoffset":-1 }, "status":"newentity" }, "logid":"{2046e323-b340-4634-8d52-4e70a4231978}", "msgtype":"spotalert", "time":1652172154472 } * More info https://github.com/foldynl/QLog/wiki/Notifications */ SpotAlertNotificationMsg::SpotAlertNotificationMsg(const SpotAlert &alert, QObject *parent) : GenericSpotNotificationMsg(parent) { FCT_IDENTIFICATION; QJsonObject spotData; spotData["rcvtime"] = alert.spot.dateTime.toString("yyyyMMdd hh:mm:ss"); spotData["freq"] = qRound(alert.spot.freq * 10000.0) / 10000.0; spotData["band"] = alert.spot.band; spotData["mode"] = alert.spot.modeGroupString; spotData["comment"] = alert.spot.comment; spotData["status"] = DxccStatus2String.value(alert.spot.status, "unknown"); spotData["rules"] = QJsonArray::fromStringList(alert.ruleNameList); QJsonObject dxInfo; dxInfo["call"] = alert.spot.callsign; dxInfo["country"] = alert.spot.dxcc.country; dxInfo["pfx"] = alert.spot.dxcc.prefix; dxInfo["dxcc"] = alert.spot.dxcc.dxcc; dxInfo["cont"] = alert.spot.dxcc.cont; dxInfo["cqz"] = alert.spot.dxcc.cqz; dxInfo["ituz"] = alert.spot.dxcc.ituz; dxInfo["utcoffset"] = alert.spot.dxcc.tz; dxInfo["member"] = QJsonArray::fromStringList(alert.spot.memberList2StringList()); QJsonObject spotterInfo; spotterInfo["call"] = alert.spot.spotter; spotterInfo["country"] = alert.spot.dxcc_spotter.country; spotterInfo["pfx"] = alert.spot.dxcc_spotter.prefix; spotterInfo["dxcc"] = alert.spot.dxcc_spotter.dxcc; spotterInfo["cont"] = alert.spot.dxcc_spotter.cont; spotterInfo["cqz"] = alert.spot.dxcc_spotter.cqz; spotterInfo["ituz"] = alert.spot.dxcc_spotter.ituz; spotterInfo["utcoffset"] = alert.spot.dxcc_spotter.tz; spotData["spotter"] = spotterInfo; spotData["dx"] = dxInfo; msg["msgtype"] = "spotalert"; msg["data"] = spotData; } /* WCY Spot Message * Example * { "appid":"QLog", "data":{ "A":13, "Au":"no", "GMF":"act", "K":3, "R":0, "SA":"qui", "SFI":68, "expK":3, "rcvtime":"20220923 11:29:16" }, "logid":"{c804ab21-c1bf-4b7f-90a6-8927bdb10dd0}", "msgtype":"wcyspot", "time":1663932556260 } * More info https://github.com/foldynl/QLog/wiki/Notifications */ WCYSpotNotificationMsg::WCYSpotNotificationMsg(const WCYSpot &spot, QObject *parent) : GenericNotificationMsg(parent) { FCT_IDENTIFICATION; QJsonObject spotData; spotData["rcvtime"] = spot.time.toString("yyyyMMdd hh:mm:ss"); spotData["K"] = spot.KIndex; spotData["expK"] = spot.expK; spotData["A"] = spot.AIndex; spotData["R"] = spot.RIndex; spotData["SFI"] = spot.SFI; spotData["SA"] = spot.SA; spotData["GMF"] = spot.GMF; spotData["Au"] = spot.Au; msg["msgtype"] = "wcyspot"; msg["data"] = spotData; } /* WWVSpot Message * Example * { "appid":"QLog", "data":{ "A":12, "Info1":"No Storms", "Info2":"No Storms", "K":2, "SFI":68, "rcvtime":"20220923 11:29:16" }, "logid":"{c804ab21-c1bf-4b7f-90a6-8927bdb10dd0}", "msgtype":"wwvspot", "time":1663932556294 } * More info https://github.com/foldynl/QLog/wiki/Notifications */ WWVSpotNotificationMsg::WWVSpotNotificationMsg(const WWVSpot &spot, QObject *parent) : GenericNotificationMsg(parent) { FCT_IDENTIFICATION; QJsonObject spotData; spotData["rcvtime"] = spot.time.toString("yyyyMMdd hh:mm:ss"); spotData["SFI"] = spot.SFI; spotData["A"] = spot.AIndex; spotData["K"] = spot.KIndex; spotData["Info1"] = spot.info1; spotData["Info2"] = spot.info2; msg["msgtype"] = "wwvspot"; msg["data"] = spotData; } /* ToAllSpot Message * Example * { "appid":"QLog", "data":{ "message":"GB7RDX New Users Welcome. cluster.g3ldi.co.uk Port 7000", "rcvtime":"20220923 11:29:16", "spotter":{ "call":"G3LDI", "cont":"EU", "country":"England", "cqz":14, "dxcc":223, "ituz":27, "pfx":"G", "utcoffset":0 } }, "logid":"{c804ab21-c1bf-4b7f-90a6-8927bdb10dd0}", "msgtype":"toallspot", "time":1663932556327 } * More info https://github.com/foldynl/QLog/wiki/Notifications */ ToAllSpotNotificationMsg::ToAllSpotNotificationMsg(const ToAllSpot &spot, QObject *parent) : GenericNotificationMsg(parent) { FCT_IDENTIFICATION; QJsonObject spotData; spotData["rcvtime"] = spot.time.toString("yyyyMMdd hh:mm:ss"); spotData["message"] = spot.message; QJsonObject spotterInfo; spotterInfo["call"] = spot.spotter; spotterInfo["country"] = spot.dxcc_spotter.country; spotterInfo["pfx"] = spot.dxcc_spotter.prefix; spotterInfo["dxcc"] = spot.dxcc_spotter.dxcc; spotterInfo["cont"] = spot.dxcc_spotter.cont; spotterInfo["cqz"] = spot.dxcc_spotter.cqz; spotterInfo["ituz"] = spot.dxcc_spotter.ituz; spotterInfo["utcoffset"] = spot.dxcc_spotter.tz; spotData["spotter"] = spotterInfo; msg["msgtype"] = "toallspot"; msg["data"] = spotData; } /* Rig Status Message * Example * { "appid":"QLog", "msgtype":"rigstatus", "time":1647197319251, "data":{ "profile" : "IC7300", "connected" : true, "txvfo" : "CURR", "rxvfo" : "CURR", -- TX/RX VFOs have the same value - split is not supported "txpower" : 0.01 "keyspeed" : 23 "vfostates" : [ { "vfo" : "CURR", "freq" : "7.18800" "mode" : "FM", "rawmode" : "FM", "ptt" : false, "rit" : 0.1 "xit" : 0.0 "bandwidth" : 2400 }, { .... -- currently, the second VFO is not present } ] }, "logid":"{2046e323-b340-4634-8d52-4e70a4231978}" } * Empty/Zero fields are not sent. Sent is everything that is known at the given moment of event. * More info https://github.com/foldynl/QLog/wiki/Notifications */ RigStatusNotificationMsg::RigStatusNotificationMsg(const Rig::Status &status, QObject *parent) : GenericNotificationMsg(parent) { FCT_IDENTIFICATION; QJsonObject vfoState; auto addIfNoEmpty = [&](const QString &key, const QString &value, bool addCond = true) { if ( !value.isEmpty() && addCond) vfoState[key] = value; }; auto addBoolIfNoEmpty = [&](const QString &key, const qint8 &value, bool addCond = true) { if ( addCond ) vfoState[key] = ( value != 0 ); }; auto addDoubleIfNoEmpty = [&](const QString &key, const double &value, bool addCond = true) { if ( value != 0.0 && addCond ) vfoState[key] = value; }; addIfNoEmpty("vfo", status.vfo); addIfNoEmpty("freq", QString::number(status.freq, 'f', 5), status.freq != 0.0); addIfNoEmpty("mode", status.mode); addIfNoEmpty("submode", status.submode); addIfNoEmpty("rawmode", status.rawmode); addBoolIfNoEmpty("ptt", status.ptt, status.ptt != -1); addDoubleIfNoEmpty("rit", status.rit); addDoubleIfNoEmpty("xit", status.xit); addDoubleIfNoEmpty("bandwidth", status.bandwidth); QJsonArray vfoStates; vfoStates.append(vfoState); QJsonObject rigData; rigData["profile"] = status.profile; rigData["connected"] = status.isConnected; if ( !status.vfo.isEmpty() ) { rigData["txvfo"] = status.vfo; rigData["rxvfo"] = status.vfo; } rigData["split"] = status.splitEnabled; if ( status.splitEnabled && status.txFreq > 0.0 ) rigData["txfreq"] = status.txFreq; if ( status.power > 0.0 ) rigData["txpower"] = status.power; if ( vfoState.size() > 0 ) rigData["vfostates"] = vfoStates; if ( status.keySpeed > 0 ) rigData["keyspeed"] = status.keySpeed; msg["msgtype"] = "rigstatus"; msg["data"] = rigData; } foldynl-QLog-3252ff9/core/NetworkNotification.h000066400000000000000000000100521517334601000214620ustar00rootroot00000000000000#ifndef QLOG_CORE_NETWORKNOTIFICATION_H #define QLOG_CORE_NETWORKNOTIFICATION_H #include #include #include #include #include #include "data/HostsPortString.h" #include "logformat/LogFormat.h" #include "data/DxSpot.h" #include "data/WsjtxEntry.h" #include "data/SpotAlert.h" #include "data/WCYSpot.h" #include "data/WWVSpot.h" #include "data/ToAllSpot.h" #include "rig/Rig.h" class GenericNotificationMsg : public QObject { Q_OBJECT public: explicit GenericNotificationMsg(QObject *parent = nullptr); QByteArray getJson() const { return QJsonDocument(msg).toJson(QJsonDocument::Compact); }; protected: QJsonObject msg; }; class QSONotificationMsg : public GenericNotificationMsg { public: enum QSOOperation { QSO_INSERT = 0, QSO_UPDATE = 1, QSO_DELETE = 2 }; explicit QSONotificationMsg(const QSqlRecord&, const QSOOperation, QObject *parent = nullptr); private: QMap QSOOperation2String = { {QSOOperation::QSO_INSERT, "insert"}, {QSOOperation::QSO_UPDATE, "update"}, {QSOOperation::QSO_DELETE, "delete"}, }; }; class GenericSpotNotificationMsg : public GenericNotificationMsg { public: explicit GenericSpotNotificationMsg(QObject *parent = nullptr); protected: QMap DxccStatus2String = { {DxccStatus::NewEntity, "newentity"}, {DxccStatus::NewBandMode, "newbandmode"}, {DxccStatus::NewBand, "newband"}, {DxccStatus::NewMode, "newmode"}, {DxccStatus::NewSlot, "newslot"}, {DxccStatus::Worked, "worked"}, {DxccStatus::Confirmed, "confirmed"}, {DxccStatus::UnknownStatus, "unknown"}, }; }; class DXSpotNotificationMsg : public GenericSpotNotificationMsg { public: explicit DXSpotNotificationMsg(const DxSpot&, QObject *parent = nullptr); }; class WSJTXCQSpotNotificationMsg : public GenericSpotNotificationMsg { public: explicit WSJTXCQSpotNotificationMsg(const WsjtxEntry&, QObject *parent = nullptr); }; class SpotAlertNotificationMsg : public GenericSpotNotificationMsg { public: explicit SpotAlertNotificationMsg(const SpotAlert&alert, QObject *parent = nullptr); }; class WCYSpotNotificationMsg : public GenericNotificationMsg { public: explicit WCYSpotNotificationMsg(const WCYSpot&, QObject *parent = nullptr); }; class WWVSpotNotificationMsg : public GenericNotificationMsg { public: explicit WWVSpotNotificationMsg(const WWVSpot&, QObject *parent = nullptr); }; class ToAllSpotNotificationMsg : public GenericNotificationMsg { public: explicit ToAllSpotNotificationMsg(const ToAllSpot&, QObject *parent = nullptr); }; class RigStatusNotificationMsg : public GenericNotificationMsg { public: explicit RigStatusNotificationMsg(const Rig::Status&, QObject *parent = nullptr); }; class NetworkNotification : public QObject { Q_OBJECT public: explicit NetworkNotification(QObject *parent = nullptr); static QString getNotifQSOAdiAddrs(); static void saveNotifQSOAdiAddrs(const QString &); static QString getNotifDXSpotAddrs(); static void saveNotifDXSpotAddrs(const QString &); static QString getNotifWSJTXCQSpotAddrs(); static void saveNotifWSJTXCQSpotAddrs(const QString &); static QString getNotifSpotAlertAddrs(); static void saveNotifSpotAlertAddrs(const QString &); static QString getNotifRigStateAddrs(); static void saveNotifRigStateAddrs(const QString &); public slots: void QSOInserted(const QSqlRecord &); void QSOUpdated(const QSqlRecord &); void QSODeleted(const QSqlRecord &); void dxSpot(const DxSpot&); void wcySpot(const WCYSpot&); void wwvSpot(const WWVSpot&); void toAllSpot(const ToAllSpot&); void WSJTXCQSpot(const WsjtxEntry&); void spotAlert(const SpotAlert&); void rigStatus(const Rig::Status&); private: QUdpSocket udpSocket; void send(const QByteArray &, const HostsPortString &); }; #endif // QLOG_CORE_NETWORKNOTIFICATION_H foldynl-QLog-3252ff9/core/PasswordCipher.cpp000066400000000000000000000231031517334601000207530ustar00rootroot00000000000000#include #include #include #include #include #include #include "PasswordCipher.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.passwordcipher"); namespace { const char kMagic[4] = {'P','M','G','R'}; const quint8 kVersion = 1; const quint8 kKdfPBKDF2 = 1; const quint8 kAeadAES256GCM = 1; inline QByteArray toUtf8Norm(const QString& s) { return s.toUtf8(); } inline bool randFill(QByteArray& out) { return RAND_bytes(reinterpret_cast(out.data()), out.size()) == 1; } inline void logOpensslError(const char* where) { unsigned long ec = ERR_get_error(); if (ec != 0) { char buf[256] = {0}; ERR_error_string_n(ec, buf, sizeof(buf)); qCDebug(runtime) << where << "openssl:" << buf; } else { qCDebug(runtime) << where << "failed"; } } } void PasswordCipher::cleanse(QByteArray& buf) { FCT_IDENTIFICATION; if (!buf.isEmpty()) OPENSSL_cleanse(buf.data(), static_cast(buf.size())); } bool PasswordCipher::kdf_pbkdf2_sha256(const QByteArray& passUtf8, const QByteArray& salt, int iters, QByteArray& outKey32) { FCT_IDENTIFICATION; outKey32.resize(kKeyLen); int ok = PKCS5_PBKDF2_HMAC(passUtf8.constData(), passUtf8.size(), reinterpret_cast(salt.constData()), salt.size(), iters, EVP_sha256(), outKey32.size(), reinterpret_cast(outKey32.data())); if (ok != 1) { logOpensslError("PKCS5_PBKDF2_HMAC"); outKey32.clear(); return false; } return true; } bool PasswordCipher::aes_gcm_encrypt(const QByteArray& key, const QByteArray& iv, const QByteArray& pt, QByteArray& ct, QByteArray& tag) { FCT_IDENTIFICATION; EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); if ( !ctx ) { logOpensslError("EVP_CIPHER_CTX_new"); return false; } bool ok = false; do { if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr) != 1) { logOpensslError("EncryptInit"); break; } if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr) != 1) { logOpensslError("SET_IVLEN"); break; } if (EVP_EncryptInit_ex(ctx, nullptr, nullptr, reinterpret_cast(key.constData()), reinterpret_cast(iv.constData())) != 1) { logOpensslError("EncryptInit key/iv"); break; } ct.resize(pt.size()); int outl = 0, total = 0; if (EVP_EncryptUpdate(ctx, reinterpret_cast(ct.data()), &outl, reinterpret_cast(pt.constData()), pt.size()) != 1) { logOpensslError("EncryptUpdate"); break; } total += outl; if (EVP_EncryptFinal_ex(ctx, reinterpret_cast(ct.data()) + total, &outl) != 1) { logOpensslError("EncryptFinal"); break; } total += outl; ct.resize(total); tag.resize(kTagLen); if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag.size(), tag.data()) != 1) { logOpensslError("GET_TAG"); break; } ok = true; } while(false); if (!ok) { cleanse(ct); cleanse(tag); } EVP_CIPHER_CTX_free(ctx); return ok; } bool PasswordCipher::aes_gcm_decrypt(const QByteArray& key, const QByteArray& iv, const QByteArray& ct, const QByteArray& tag, QByteArray& pt) { FCT_IDENTIFICATION; EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); if ( !ctx ) { logOpensslError("EVP_CIPHER_CTX_new"); return false; } bool ok = false; do { if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr) != 1) { logOpensslError("DecryptInit"); break; } if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr) != 1) { logOpensslError("SET_IVLEN"); break; } if (EVP_DecryptInit_ex(ctx, nullptr, nullptr, reinterpret_cast(key.constData()), reinterpret_cast(iv.constData())) != 1) { logOpensslError("DecryptInit key/iv"); break; } pt.resize(ct.size()); int outl = 0, total = 0; if (EVP_DecryptUpdate(ctx, reinterpret_cast(pt.data()), &outl, reinterpret_cast(ct.constData()), ct.size()) != 1) { logOpensslError("DecryptUpdate"); break; } total += outl; if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag.size(), const_cast(tag.constData())) != 1) { logOpensslError("SET_TAG"); break; } int finok = EVP_DecryptFinal_ex(ctx, reinterpret_cast(pt.data()) + total, &outl); if (finok != 1) { // Auth failed or wrong key/passphrase/iv/tag pt.clear(); logOpensslError("DecryptFinal (auth fail)"); break; } total += outl; pt.resize(total); ok = true; } while(false); EVP_CIPHER_CTX_free(ctx); return ok; } bool PasswordCipher::encrypt(const QString& passphrase, const QByteArray& plaintext, QByteArray& outBase64) { FCT_IDENTIFICATION; outBase64.clear(); if ( plaintext.isEmpty() ) return false; QByteArray pass = toUtf8Norm(passphrase); QByteArray salt(kSaltLen, 0); if (!randFill(salt)) { logOpensslError("RAND salt"); return false; } QByteArray key; if ( !kdf_pbkdf2_sha256(pass, salt, kPBKDF2Iters, key)) { cleanse(pass); return false; } QByteArray iv(kIVLen, 0); if (!randFill(iv)) { logOpensslError("RAND iv"); cleanse(key); cleanse(pass); return false; } QByteArray ct, tag; if (!aes_gcm_encrypt(key, iv, plaintext, ct, tag)) { cleanse(key); cleanse(pass); return false; } cleanse(pass); // Build blob QByteArray blob; blob.reserve(4+1+1+1+1+1+1+1+4 + salt.size() + iv.size() + ct.size() + tag.size()); QDataStream ds(&blob, QIODevice::WriteOnly); ds.setByteOrder(QDataStream::BigEndian); ds.writeRawData(kMagic, 4); ds << kVersion; ds << kKdfPBKDF2; ds << kAeadAES256GCM; ds << static_cast(salt.size()); ds << static_cast(iv.size()); ds << static_cast(tag.size()); ds << static_cast(0); // reserved ds << static_cast(kPBKDF2Iters); ds.writeRawData(salt.constData(), salt.size()); ds.writeRawData(iv.constData(), iv.size()); ds.writeRawData(ct.constData(), ct.size()); ds.writeRawData(tag.constData(), tag.size()); outBase64 = blob.toBase64(); cleanse(key); return true; } bool PasswordCipher::decrypt(const QString& passphrase, const QByteArray& inBase64, QByteArray& plaintext) { FCT_IDENTIFICATION; plaintext.clear(); QByteArray blob = QByteArray::fromBase64(inBase64); if (blob.size() < (int)(4+1+1+1+1+1+1+1+4)) return false; QDataStream ds(blob); ds.setByteOrder(QDataStream::BigEndian); char mg[4]; if (ds.readRawData(mg, 4) != 4) return false; if (memcmp(mg, kMagic, 4) != 0) return false; quint8 ver=0, kdf=0, aead=0, slen=0, ivlen=0, tlen=0, rsvd=0; quint32 iters=0; ds >> ver >> kdf >> aead >> slen >> ivlen >> tlen >> rsvd >> iters; if (ds.status()!=QDataStream::Ok) return false; if (ver != kVersion || kdf != kKdfPBKDF2 || aead != kAeadAES256GCM) return false; if (slen==0 || ivlen==0 || tlen==0) return false; if (iters < 10000) return false; // sanity QByteArray salt(slen, 0), iv(ivlen, 0); if (ds.readRawData(salt.data(), slen) != slen) return false; if (ds.readRawData(iv.data(), ivlen) != ivlen) return false; // Remaining = ct + tag int remain = blob.size() - (4+1+1+1+1+1+1+1+4 + slen + ivlen); if (remain <= tlen) return false; int ctlen = remain - tlen; QByteArray ct(ctlen, 0), tag(tlen, 0); if (ds.readRawData(ct.data(), ctlen) != ctlen) return false; if (ds.readRawData(tag.data(), tlen) != tlen) return false; QByteArray pass = toUtf8Norm(passphrase); QByteArray key; if (!kdf_pbkdf2_sha256(pass, salt, static_cast(iters), key)) { cleanse(pass); return false; } bool ok = aes_gcm_decrypt(key, iv, ct, tag, plaintext); cleanse(key); cleanse(pass); if (!ok) plaintext.clear(); return ok; } foldynl-QLog-3252ff9/core/PasswordCipher.h000066400000000000000000000036771517334601000204360ustar00rootroot00000000000000#ifndef PASSWORDCIPHER_H #define PASSWORDCIPHER_H #include #include /* Blob layout (all big-endian where applicable): magic: "PMGR" (4 bytes) ver: 0x01 (1) kdf: 0x01 (1) // 1=PBKDF2-SHA256 aead: 0x01 (1) // 1=AES-256-GCM slen: 0x10 (1) // salt len (16) ivlen: 0x0C (1) // iv len (12) tlen: 0x10 (1) // tag len (16) rsvd: 0x00 (1) iters: uint32_be (4) // PBKDF2 iterations salt: slen bytes iv: ivlen bytes ct: N bytes tag: tlen bytes */ class PasswordCipher { public: static const int kSaltLen = 16; static const int kIVLen = 12; // GCM standard static const int kTagLen = 16; static const int kKeyLen = 32; // AES-256 static const int kPBKDF2Iters = 300000; static bool encrypt(const QString& passphrase, const QByteArray& plaintext, QByteArray& outBase64); static bool decrypt(const QString& passphrase, const QByteArray& inBase64, QByteArray& plaintext); private: static bool kdf_pbkdf2_sha256(const QByteArray& passUtf8, const QByteArray& salt, int iters, QByteArray& outKey32); static bool aes_gcm_encrypt(const QByteArray& key, const QByteArray& iv, const QByteArray& pt, QByteArray& ct, QByteArray& tag); static bool aes_gcm_decrypt(const QByteArray& key, const QByteArray& iv, const QByteArray& ct, const QByteArray& tag, QByteArray& pt); static void cleanse(QByteArray& buf); }; #endif // PASSWORDCIPHER_H foldynl-QLog-3252ff9/core/PlatformParameterManager.cpp000066400000000000000000000336631517334601000227520ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "PlatformParameterManager.h" #include "core/LogParam.h" #include "core/LogDatabase.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.platformparametermanager"); QList PlatformParameterManager::knownParameters() { FCT_IDENTIFICATION; // List of known platform-dependent parameters. // These are the parameters that are stored by LogParam class return { { "services/lotw/callbook/tqsl", QObject::tr("TQSL Path"), true } }; } QList PlatformParameterManager::getParameters(const QString &importDbPath, const QString &sourcePlatform) { FCT_IDENTIFICATION; qCDebug(function_parameters) << importDbPath << sourcePlatform; QList result; const QString currentPlatform = LogDatabase::currentPlatformId(); const bool platformDiffers = (sourcePlatform != currentPlatform); const bool targetIsFlatpak = (currentPlatform == LogDatabase::PLATFORM_LINUXFLATPAK); const bool sourceIsFlatpak = (sourcePlatform == LogDatabase::PLATFORM_LINUXFLATPAK); qCDebug(runtime) << "Source platform:" << sourcePlatform << "Current platform:" << currentPlatform << "Differs:" << platformDiffers; // Open the imported database const QString connectionName = QStringLiteral("PlatformParamImport"); { QSqlDatabase importDb = QSqlDatabase::addDatabase("QSQLITE", connectionName); importDb.setDatabaseName(importDbPath); if ( !importDb.open() ) { qWarning() << "Cannot open import database:" << importDb.lastError().text(); QSqlDatabase::removeDatabase(connectionName); return result; } // params defined in LogParam const QList known = knownParameters(); for ( const PlatformParameterManager::KnownParamDef ¶m : known ) { // - If target is Flatpak: skip (path is fixed, e.g. /app/bin/tqsl) if ( param.isExecutablePath && targetIsFlatpak ) { qCDebug(runtime) << "Skipping" << param.key << "- target is Flatpak (fixed path)"; continue; } PlatformParameter p; p.key = param.key; p.displayName = param.displayName; p.requiresChange = platformDiffers; p.newValue = QString(); // Read the value from the imported database // do not use LogParam function here because the class gets value from the main DB. QSqlQuery query(importDb); if ( query.prepare("SELECT value FROM log_param WHERE name = :name") ) { query.bindValue(":name", p.key); if ( query.exec() && query.first() ) { // For executable paths from Flatpak source: path is not useful if ( param.isExecutablePath && sourceIsFlatpak ) p.currentValue = QObject::tr("(Flatpak internal path)"); else p.currentValue = query.value(0).toString(); } } result.append(p); } importDb.close(); } QSqlDatabase::removeDatabase(connectionName); return result; } void PlatformParameterManager::applyParameters(const QList ¶ms) { FCT_IDENTIFICATION; for ( const PlatformParameter &p : params ) { // Only apply if user provided a new value if ( !p.newValue.isEmpty() ) { qCDebug(runtime) << "Applying parameter:" << p.key << "=" << p.newValue; // Use LogParam to set the value in the current database // This method is called when the imported DB becomes the default DB. // Therefore, we can use the LogParam class. if ( LogParam::isLoTWTQSLPathKey(p.key) ) LogParam::setLoTWTQSLPath(p.newValue); // Add more parameter handlers here as needed } } } void PlatformParameterManager::applyFlatpakFixedPaths() { FCT_IDENTIFICATION; const QString currentPlatform = LogDatabase::currentPlatformId(); if ( currentPlatform != LogDatabase::PLATFORM_LINUXFLATPAK ) { qCDebug(runtime) << "Not Flatpak target, skipping fixed paths"; return; } qCDebug(runtime) << "Applying Flatpak fixed paths"; // Set TQSL path to fixed Flatpak location - empty is OK because flatpak has built-in value. LogParam::setLoTWTQSLPath(""); // Clear rigctld_path in all rig profiles (empty = autodetect will find /app/bin/rigctld) QSqlQuery query; if ( query.exec("UPDATE rig_profiles SET rigctld_path = NULL") ) qCDebug(runtime) << "Cleared rigctld_path in all rig profiles"; else qWarning() << "Failed to clear rigctld_path:" << query.lastError().text(); } QString PlatformParameterManager::pendingParametersPath() { return LogDatabase::dbDirectory().filePath("qlog.db.pending.params"); } QList PlatformParameterManager::getProfileParameters(const QString &importDbPath, const QString &sourcePlatform) { FCT_IDENTIFICATION; qCDebug(function_parameters) << importDbPath << sourcePlatform; QList result; const QString currentPlatform = LogDatabase::currentPlatformId(); const bool targetIsFlatpak = (currentPlatform == LogDatabase::PLATFORM_LINUXFLATPAK); const bool sourceIsFlatpak = (sourcePlatform == LogDatabase::PLATFORM_LINUXFLATPAK); const QString connectionName = QStringLiteral("ProfilePortParamImport"); { QSqlDatabase importDb = QSqlDatabase::addDatabase("QSQLITE", connectionName); importDb.setDatabaseName(importDbPath); if ( !importDb.open() ) { qWarning() << "Cannot open import database:" << importDb.lastError().text(); QSqlDatabase::removeDatabase(connectionName); return result; } // Define profile tables and their port columns struct ProfileDef { QString tableName; QString columnName; QString displayPrefix; bool isExecutablePath; // true for paths to executables (like rigctld_path) }; QList profileDefs = { { "rig_profiles", "port_pathname", QObject::tr("Rig"), false }, { "rig_profiles", "ptt_port_pathname", QObject::tr("Rig PTT"), false }, { "rig_profiles", "rigctld_path", QObject::tr("Rig rigctld"), true }, { "rot_profiles", "port_pathname", QObject::tr("Rotator"), false }, { "cwkey_profiles", "port_pathname", QObject::tr("CW Keyer"), false } }; for ( const ProfileDef &def : profileDefs ) { if ( def.isExecutablePath && targetIsFlatpak ) { qCDebug(runtime) << "Skipping" << def.columnName << "- target is Flatpak (fixed path)"; continue; } QSqlQuery query(importDb); QString sql = QString("SELECT profile_name, %1 FROM %2 WHERE %1 IS NOT NULL AND %1 != ''") .arg(def.columnName, def.tableName); if ( !query.exec(sql) ) { qCDebug(runtime) << "Query failed for" << def.tableName << ":" << query.lastError().text(); continue; } while ( query.next() ) { ProfileParameter p; p.tableName = def.tableName; p.profileName = query.value(0).toString(); p.columnName = def.columnName; p.displayName = QString("%1: %2").arg(def.displayPrefix, p.profileName); p.newValue = QString(); p.isExecutablePath = def.isExecutablePath; if ( def.isExecutablePath && sourceIsFlatpak ) p.currentValue = QObject::tr("(Flatpak internal path)"); else p.currentValue = query.value(1).toString(); result.append(p); } } importDb.close(); } QSqlDatabase::removeDatabase(connectionName); qCDebug(runtime) << "Found" << result.size() << "profile port parameters"; return result; } void PlatformParameterManager::applyProfileParameters(const QList ¶ms) { FCT_IDENTIFICATION; for ( const ProfileParameter &p : params ) { if ( p.newValue.isEmpty() ) continue; qCDebug(runtime) << "Applying profile port parameter:" << p.tableName << p.profileName << p.columnName << "=" << p.newValue; QSqlQuery query; QString sql = QString("UPDATE %1 SET %2 = :value WHERE profile_name = :profile") .arg(p.tableName, p.columnName); if ( !query.prepare(sql) ) { qWarning() << "Cannot prepare update query:" << query.lastError().text(); continue; } query.bindValue(":value", p.newValue); query.bindValue(":profile", p.profileName); if ( !query.exec() ) qWarning() << "Cannot update profile port:" << query.lastError().text(); } } bool PlatformParameterManager::saveParametersToFile(const QList ¶ms, const QList &profileParams, const QString &filePath) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filePath; QJsonObject root; // Save log_param parameters QJsonArray paramArray; for ( const PlatformParameter &p : params ) { if ( !p.newValue.isEmpty() ) { QJsonObject obj; obj["key"] = p.key; obj["newValue"] = p.newValue; paramArray.append(obj); } } root["parameters"] = paramArray; // Save profile port parameters QJsonArray profileArray; for ( const ProfileParameter &p : profileParams ) { if ( !p.newValue.isEmpty() ) { QJsonObject obj; obj["tableName"] = p.tableName; obj["profileName"] = p.profileName; obj["columnName"] = p.columnName; obj["newValue"] = p.newValue; obj["isExec"] = p.isExecutablePath; profileArray.append(obj); } } root["profilePorts"] = profileArray; if ( paramArray.isEmpty() && profileArray.isEmpty() ) { qCDebug(runtime) << "No parameters to save"; return true; } QJsonDocument doc(root); QFile file(filePath); if ( !file.open(QIODevice::WriteOnly) ) { qWarning() << "Cannot open file for writing:" << filePath; return false; } file.write(doc.toJson(QJsonDocument::Compact)); file.close(); qCDebug(runtime) << "Saved" << paramArray.size() << "params and" << profileArray.size() << "profile ports to" << filePath; return true; } QList PlatformParameterManager::loadParametersFromFile(const QString &filePath) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filePath; QList result; QFile file(filePath); if ( !file.exists() ) { qCDebug(runtime) << "No parameters file found"; return result; } if ( !file.open(QIODevice::ReadOnly) ) { qWarning() << "Cannot open parameters file:" << filePath; return result; } QByteArray data = file.readAll(); file.close(); QJsonParseError error; const QJsonDocument doc = QJsonDocument::fromJson(data, &error); if ( error.error != QJsonParseError::NoError ) { qWarning() << "JSON parse error:" << error.errorString(); return result; } const QJsonObject root = doc.object(); const QJsonArray array = root["parameters"].toArray(); for ( const QJsonValue &val : array ) { QJsonObject obj = val.toObject(); PlatformParameter p; p.key = obj["key"].toString(); p.newValue = obj["newValue"].toString(); p.requiresChange = false; result.append(p); } qCDebug(runtime) << "Loaded" << result.size() << "parameters from" << filePath; return result; } QList PlatformParameterManager::loadProfileParametersFromFile(const QString &filePath) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filePath; QList result; QFile file(filePath); if ( !file.exists() ) { qCDebug(runtime) << "No parameters file found"; return result; } if ( !file.open(QIODevice::ReadOnly) ) { qWarning() << "Cannot open parameters file:" << filePath; return result; } QByteArray data = file.readAll(); file.close(); QJsonParseError error; const QJsonDocument doc = QJsonDocument::fromJson(data, &error); if ( error.error != QJsonParseError::NoError ) { qWarning() << "JSON parse error:" << error.errorString(); return result; } const QJsonObject root = doc.object(); const QJsonArray array = root["profilePorts"].toArray(); for ( const QJsonValue &val : array ) { QJsonObject obj = val.toObject(); ProfileParameter p; p.tableName = obj["tableName"].toString(); p.profileName = obj["profileName"].toString(); p.columnName = obj["columnName"].toString(); p.newValue = obj["newValue"].toString(); p.isExecutablePath = obj["isExec"].toBool(); result.append(p); } qCDebug(runtime) << "Loaded" << result.size() << "profile port parameters from" << filePath; return result; } foldynl-QLog-3252ff9/core/PlatformParameterManager.h000066400000000000000000000064401517334601000224100ustar00rootroot00000000000000#ifndef QLOG_CORE_PLATFORMPARAMETERMANAGER_H #define QLOG_CORE_PLATFORMPARAMETERMANAGER_H #include #include #include struct PlatformParameter { QString key; // LogParam key (e.g. "services/lotw/callbook/tqsl") QString displayName; // Human-readable name (e.g. "TQSL Path") QString currentValue; // Value from imported DB QString newValue; // User-provided value for current platform bool requiresChange; // true if platform differs }; // Structure for profile-based port paths (rig, rotator, cwkey) struct ProfileParameter { QString tableName; // e.g. "rig_profiles" QString profileName; // e.g. "My Rig" QString columnName; // e.g. "port_pathname" QString displayName; // e.g. "Rig: My Rig - Serial Port" QString currentValue; // Value from imported DB QString newValue; // User-provided value for current platform bool isExecutablePath; // is exec - browse should be displayer }; class PlatformParameterManager { public: // Get list of platform-dependent parameters from imported DB // importDbPath: path to the imported database file // sourcePlatform: platform from which the DB was exported // Returns list of parameters that may need adjustment static QList getParameters(const QString &importDbPath, const QString &sourcePlatform); // Apply user-provided values to the current database // params: list of parameters with newValue set by user static void applyParameters(const QList ¶ms); // Apply fixed paths for Flatpak target (called during import) // Sets TQSL path to /app/bin/tqsl and clears rigctld_path in all profiles static void applyFlatpakFixedPaths(); // Get list of profile port parameters from imported DB // sourcePlatform: platform from which the DB was exported static QList getProfileParameters(const QString &importDbPath, const QString &sourcePlatform); // Apply profile port parameters to the current database static void applyProfileParameters(const QList ¶ms); // Save parameters to a JSON file for later application after restart static bool saveParametersToFile(const QList ¶ms, const QList &profileParams, const QString &filePath); // Load parameters from JSON file static QList loadParametersFromFile(const QString &filePath); // Load profile port parameters from JSON file static QList loadProfileParametersFromFile(const QString &filePath); // Get path to pending parameters file static QString pendingParametersPath(); private: // Structure for known platform-dependent parameters struct KnownParamDef { QString key; // LogParam key QString displayName; // Human-readable name bool isExecutablePath; // true for paths to executables }; // Template list of known platform-dependent parameters static QList knownParameters(); }; #endif // QLOG_CORE_PLATFORMPARAMETERMANAGER_H foldynl-QLog-3252ff9/core/PotaQE.cpp000066400000000000000000000036231517334601000171540ustar00rootroot00000000000000#include #include #include #include "core/debug.h" #include "PotaQE.h" MODULE_IDENTIFICATION("qlog.core.potaqe"); PotaQE::PotaQE(QObject *parent) : QObject{parent} { FCT_IDENTIFICATION; refreshTimer.setInterval(REFRESHPERIOD); spotUpdater.moveToThread(&spotUpdaterThread); connect(&spotUpdaterThread, &QThread::started, &spotUpdater, &PotaAppActivatorDownloader::updateActivators); connect(&spotUpdaterThread, &QThread::started, &refreshTimer, QOverload<>::of(&QTimer::start)); connect(&spotUpdaterThread, &QThread::finished, &spotUpdater, &QObject::deleteLater); connect(&spotUpdater, &PotaAppActivatorDownloader::activatorsUpdated, this, &PotaQE::updateSpot); connect(&refreshTimer, &QTimer::timeout, &spotUpdater, &PotaAppActivatorDownloader::updateActivators); spotUpdaterThread.start(); } PotaQE::~PotaQE() { FCT_IDENTIFICATION; if ( spotUpdaterThread.isRunning() ) { spotUpdaterThread.quit(); spotUpdaterThread.wait(); } } // find park reference by callsign + freq +-5 kHz + mode. // Matching: // callsign ignores prefixes and suffixes (/P,/M,/QRP,...) (Based Callsign is used) // freq +- 5KHz const POTASpot PotaQE::findReferenceId(const Callsign &callsign, double freq) { FCT_IDENTIFICATION; const QString &baseCallsign = callsign.getBase(); if ( !callsign.isValid() || baseCallsign.isEmpty() ) return POTASpot(); QMutexLocker locker(&activatorLock); auto i = activatorSpots.constFind(baseCallsign); while ( i != activatorSpots.cend() && i.key() == baseCallsign ) { const POTASpot &spot = i.value(); if ( qAbs(spot.frequency - freq) <= FREQTOL ) return spot; i++; } return POTASpot(); } void PotaQE::updateSpot() { FCT_IDENTIFICATION; QMutexLocker locker(&activatorLock); spotUpdater.swapActivators(activatorSpots); } foldynl-QLog-3252ff9/core/PotaQE.h000066400000000000000000000014771517334601000166260ustar00rootroot00000000000000#ifndef QLOG_CORE_POTAQE_H #define QLOG_CORE_POTAQE_H #include #include #include #include "data/Callsign.h" #include "service/potaapp/PotaApp.h" class PotaQE : public QObject { Q_OBJECT public: static PotaQE *instance() { static PotaQE instance; return &instance; }; const POTASpot findReferenceId(const Callsign &callsign, double freq); private slots: void updateSpot(); private: QThread spotUpdaterThread; PotaAppActivatorDownloader spotUpdater; QTimer refreshTimer; QMutex activatorLock; const double FREQTOL = 0.005; // in MHz const int REFRESHPERIOD = 60 * 1000; PotaAppActivatorDownloader::ActivatorStorage activatorSpots; explicit PotaQE(QObject *parent = nullptr); ~PotaQE(); }; #endif // QLOG_CORE_POTAQE_H foldynl-QLog-3252ff9/core/PropConditions.cpp000066400000000000000000000326311517334601000207760ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include "PropConditions.h" #include "debug.h" #include "data/Data.h" //#define FLUX_URL "https://services.swpc.noaa.gov/products/summary/10cm-flux.json" #define K_INDEX_URL "https://www.hamqsl.com/solarxml.php" #define SOLAR_SUMMARY_IMG "https://www.hamqsl.com/solar101vhf.php" #define AURORA_MAP "https://services.swpc.noaa.gov/json/ovation_aurora_latest.json" #define MUF_POINTS "https://prop.kc2g.com/api/stations.json?maxage=2700" #define DXC_TRENDS "https://api.ure.es/v2/heatmap" // the resend mechanism was implemented only because of a issue with prop.kc2g.com // This site has IPv4 and IPv6 DNS record, and if the notebook is IPv4 only, QT uses an IPv6 // address for the first attempt and an IPv4 address for the second attempt. // This resulted in a long interval before information was obtained from this server. // Resend mechanism accelerates all this. #define RESEND_ATTEMPTS 3 //intervals are defined in seconds #define RESEND_BASE_INTERVAL 5 #define BASE_UPDATE_INTERVAL (15 * 60) // in seconds #define DXTRENDS_UPDATE_INTERVAL (5 * 60) // in seconds #define DXTRENDS_TIMEOUT 60 MODULE_IDENTIFICATION("qlog.core.conditions"); PropConditions::PropConditions(QObject *parent) : QObject(parent), agentString(QString("QLog/%1").arg(VERSION).toUtf8()) { FCT_IDENTIFICATION; nam = new QNetworkAccessManager(this); connect(nam, &QNetworkAccessManager::finished, this, &PropConditions::processReply); QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &PropConditions::update); update(); timer->start(BASE_UPDATE_INTERVAL * 1000); QTimer *timerTrends = new QTimer(this); connect(timerTrends, &QTimer::timeout, this, &PropConditions::updateDxTrends); updateDxTrends(); timerTrends->start(DXTRENDS_UPDATE_INTERVAL * 1000); connect(&dxTrendTimeoutTimer, &QTimer::timeout, this, &PropConditions::dxTrendTimeout); } void PropConditions::update() { FCT_IDENTIFICATION; nam->get(prepareRequest(QUrl(SOLAR_SUMMARY_IMG))); nam->get(prepareRequest(QUrl(K_INDEX_URL))); nam->get(prepareRequest(QUrl(AURORA_MAP))); nam->get(prepareRequest(QUrl(MUF_POINTS))); } void PropConditions::updateDxTrends() { FCT_IDENTIFICATION; dxTrendResult.clear(); dxTrendTimeoutTimer.stop(); dxTrendPendingConnections.clear(); // pending connections will be ignored. for ( const QString& continent : Data::getContinentList() ) dxTrendPendingConnections << nam->get(prepareRequest(QUrl(DXC_TRENDS + QString("/%0/15").arg(continent)))); dxTrendTimeoutTimer.start(DXTRENDS_TIMEOUT * 1000); } void PropConditions::processReply(QNetworkReply* reply) { FCT_IDENTIFICATION; QByteArray data = reply->readAll(); qCDebug(runtime) << data; int replyStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); qCDebug(runtime) << reply->error() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) << reply->url(); if ( reply->error() == QNetworkReply::NoError && replyStatusCode >= 200 && replyStatusCode < 300 ) { failedRequests[reply->url()] = 0; const QUrl &replyURL = reply->url(); if (replyURL == QUrl(SOLAR_SUMMARY_IMG)) { QFile file(solarSummaryFile()); if ( file.open(QIODevice::WriteOnly)) { file.write(data); file.flush(); file.close(); } } else if (replyURL == QUrl(K_INDEX_URL)) { QDomDocument doc; if ( !doc.setContent(data) ) { qWarning() << "Cannot parse response from " << K_INDEX_URL; return; } QDomNodeList solarData = doc.elementsByTagName("solardata"); QDomNode n = solarData.item(0); if ( n.isNull() ) { qWarning() << "Cannot find solardata in " << K_INDEX_URL; return; } QDomElement aindex = n.firstChildElement("aindex"); QDomElement kindex = n.firstChildElement("kindex"); QDomElement solarflux = n.firstChildElement("solarflux"); if ( !aindex.isNull() ) { a_index = aindex.text().toInt(); qCDebug(runtime) << "A-Index: " << a_index; a_index_last_update = QDateTime::currentDateTime(); emit AIndexUpdated(); } if ( !kindex.isNull() ) { k_index = kindex.text().toDouble(); qCDebug(runtime) << "K-Index: " << k_index; k_index_last_update = QDateTime::currentDateTime(); emit KIndexUpdated(); } if ( !solarflux.isNull() ) { flux = solarflux.text().toInt(); qCDebug(runtime) << "Flux: " << flux; flux_last_update = QDateTime::currentDateTime(); emit fluxUpdated(); } } else if (replyURL == QUrl(AURORA_MAP)) { auroraMap.clear(); QJsonDocument doc = QJsonDocument::fromJson(data); if ( ! doc.isNull() ) { double skipElement = 0.0; qCDebug(runtime) << "Aurora forecast Time:" << doc["Forecast Time"].toString(); const QJsonArray &jsonArray = doc["coordinates"].toArray(); for (const QJsonValue &value : jsonArray) { QJsonArray obj = value.toArray(); if ( obj.size() == 3 ) { double longitute = obj[0].toDouble(); double latitude = obj[1].toDouble(); double prob = obj[2].toDouble(); auroraMap.addPoint(longitute, latitude, prob, &skipElement); } } auroraMap_last_update = QDateTime::currentDateTime(); emit auroraMapUpdated(); } } else if (replyURL == QUrl(MUF_POINTS)) { mufMap.clear(); QJsonDocument doc = QJsonDocument::fromJson(data); if ( ! doc.isNull() ) { double skipElement = 0.0; const QJsonArray &jsonArray = doc.array(); for (const QJsonValue &value : jsonArray) { QJsonObject obj = value.toObject(); QJsonObject station = obj["station"].toObject(); double longitute = station["longitude"].toString().toDouble(); double latitude = station["latitude"].toString().toDouble(); double muf = obj["mufd"].toDouble(); mufMap.addPoint(longitute, latitude, muf, &skipElement); } mufMap_last_update = QDateTime::currentDateTime(); emit mufMapUpdated(); } } else if ( dxTrendPendingConnections.contains(reply) ) { dxTrendPendingConnections.remove(reply); QJsonDocument doc = QJsonDocument::fromJson(data); const QString &requestContinent = replyURL.path().section('/', -2, -2); if ( ! doc.isNull() ) { QJsonObject jsonObject = doc.object(); for ( auto continentIt = jsonObject.begin(); continentIt != jsonObject.end(); ++continentIt ) { const QString &toContinent = continentIt.key(); // "AF", "AS", "EU".... const QJsonObject &values = continentIt->toObject(); for ( auto valueIt = values.begin(); valueIt != values.end(); ++valueIt ) { const QString &band = valueIt.key() + "m"; // "10", "12", "15" ... int spotCount = valueIt->toString().toInt(); // Number of Spots dxTrendResult[requestContinent][toContinent][band] = spotCount; } } } if ( dxTrendPendingConnections.isEmpty() ) { dxTrendTimeoutTimer.stop(); qCDebug(runtime) << "DXTrend finalized"; emit dxTrendFinalized(dxTrendResult); } } reply->deleteLater(); emit conditionsUpdated(); } else { qCDebug(runtime) << "HTTP Status Code" << replyStatusCode; dxTrendPendingConnections.remove(reply); repeateRequest(reply->url()); reply->deleteLater(); } } void PropConditions::repeateRequest(const QUrl &url) { FCT_IDENTIFICATION; failedRequests[url]++; if ( failedRequests[url] <= RESEND_ATTEMPTS ) { int resendInterval = RESEND_BASE_INTERVAL * failedRequests[url]; qCDebug(runtime) << "Scheduled URL request resend" << resendInterval << "; URL:" << url.toString(); QTimer::singleShot(1000 * RESEND_BASE_INTERVAL * failedRequests[url], this, [this, url]() { qCDebug(runtime) << "Resending request" << url.toString(); QNetworkReply *req = nam->get(prepareRequest(url)); if ( url.toString().contains(DXC_TRENDS)) dxTrendPendingConnections << req; }); } else { qCDebug(runtime) << "Propagation - detected consecutive errors from" << url.toString(); } } QNetworkRequest PropConditions::prepareRequest(const QUrl &url) { FCT_IDENTIFICATION; QNetworkRequest req(url); req.setRawHeader("User-Agent", agentString); return req; } void PropConditions::dxTrendTimeout() { FCT_IDENTIFICATION; dxTrendTimeoutTimer.stop(); for ( auto it = dxTrendPendingConnections.begin(); it != dxTrendPendingConnections.end(); ) { QNetworkReply* reply = *it; it = dxTrendPendingConnections.erase(it); if ( reply ) { reply->abort(); reply->deleteLater(); } } dxTrendPendingConnections.clear(); dxTrendResult.clear(); emit dxTrendFinalized(dxTrendResult); // emit empty result } PropConditions::~PropConditions() { dxTrendTimeout(); nam->deleteLater(); } bool PropConditions::isFluxValid() { FCT_IDENTIFICATION; bool ret = false; qCDebug(runtime)<<"Date valid: " << flux_last_update.isValid() << " last_update: " << flux_last_update; ret = (flux_last_update.isValid() && flux_last_update.secsTo(QDateTime::currentDateTime()) < 20 * 60); qCDebug(runtime)<< "Result: " << ret; return ret; } bool PropConditions::isKIndexValid() { FCT_IDENTIFICATION; bool ret = false; qCDebug(runtime)<<"Date valid: " << k_index_last_update.isValid() << " last_update: " << k_index_last_update; ret = (k_index_last_update.isValid() && k_index_last_update.secsTo(QDateTime::currentDateTime()) < 20 * 60); qCDebug(runtime)<< "Result: " << ret; return ret; } bool PropConditions::isAIndexValid() { FCT_IDENTIFICATION; bool ret = false; qCDebug(runtime)<<"Date valid: " << a_index_last_update.isValid() << " last_update: " << a_index_last_update; ret = (a_index_last_update.isValid() && a_index_last_update.secsTo(QDateTime::currentDateTime()) < 20 * 60); qCDebug(runtime)<< "Result: " << ret; return ret; } bool PropConditions::isAuroraMapValid() { FCT_IDENTIFICATION; qCDebug(runtime)<<"Date valid: " << auroraMap_last_update.isValid() << " last_update: " << auroraMap_last_update << " aurora count: " << auroraMap.count(); bool ret = (auroraMap_last_update.isValid() && auroraMap_last_update.secsTo(QDateTime::currentDateTime()) < 20 * 60 && auroraMap.count() > 0); qCDebug(runtime)<< "Result: " << ret; return ret; } bool PropConditions::isMufMapValid() { FCT_IDENTIFICATION; qCDebug(runtime)<<"Date valid: " << mufMap_last_update.isValid() << " last_update: " << mufMap_last_update << " aurora count: " << mufMap.count(); bool ret = (mufMap_last_update.isValid() && mufMap_last_update.secsTo(QDateTime::currentDateTime()) < 20 * 60 && mufMap.count() > 0); qCDebug(runtime)<< "Result: " << ret; return ret; } int PropConditions::getFlux() { FCT_IDENTIFICATION; qCDebug(runtime)<<"Current Flux: " << flux << " last_update: " << flux_last_update; return flux; } int PropConditions::getAIndex() { FCT_IDENTIFICATION; qCDebug(runtime)<<"Current A-Index: " << a_index << " last_update: " << a_index_last_update; return a_index; } double PropConditions::getKIndex() { FCT_IDENTIFICATION; qCDebug(runtime)<<"Current K-Index: " << k_index << " last_update: " << k_index_last_update; return k_index; } QList::MapPoint> PropConditions::getAuroraPoints() const { FCT_IDENTIFICATION; return auroraMap.getMap(); } QList::MapPoint> PropConditions::getMUFPoints() const { return mufMap.getMap(); } QString PropConditions::solarSummaryFile() { FCT_IDENTIFICATION; QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); return dir.filePath("solar101vhf.gif"); } foldynl-QLog-3252ff9/core/PropConditions.h000066400000000000000000000052651517334601000204460ustar00rootroot00000000000000#ifndef QLOG_CORE_PROPCONDITIONS_H #define QLOG_CORE_PROPCONDITIONS_H #include #include #include #include class QNetworkAccessManager; class QNetworkReply; class QNetworkRequest; template class GenericValueMap { public: explicit GenericValueMap() {} ~GenericValueMap(){}; struct MapPoint { double longitude; double latitude; T value; }; virtual void addPoint(double longitude, double latitude, const T &value, const T *skipValue = nullptr) { if ( skipValue && value == *skipValue ) return; GenericValueMap::MapPoint point; point.longitude = longitude; point.latitude = latitude; point.value = value; map.append(point); }; QList getMap() const { return map; }; void clear() { map.clear(); }; int count() const { return map.size(); }; private: QList map; }; class PropConditions : public QObject { Q_OBJECT public: explicit PropConditions(QObject *parent = nullptr); ~PropConditions(); bool isFluxValid(); bool isKIndexValid(); bool isAIndexValid(); bool isAuroraMapValid(); bool isMufMapValid(); int getFlux(); int getAIndex(); double getKIndex(); QList::MapPoint> getAuroraPoints() const; QList::MapPoint> getMUFPoints() const; static QString solarSummaryFile(); signals: void conditionsUpdated(); void fluxUpdated(); void KIndexUpdated(); void AIndexUpdated(); void auroraMapUpdated(); void mufMapUpdated(); void dxTrendFinalized(QHash>>); public slots: void update(); void updateDxTrends(); void processReply(QNetworkReply* reply); private: QDateTime flux_last_update; QDateTime k_index_last_update; QDateTime a_index_last_update; QDateTime auroraMap_last_update; QDateTime mufMap_last_update; int flux; int a_index; double k_index; GenericValueMap auroraMap; GenericValueMap mufMap; QHash failedRequests; QSet dxTrendPendingConnections; QTimer dxTrendTimeoutTimer; QHash>> dxTrendResult; QByteArray agentString; void repeateRequest(const QUrl &); QNetworkRequest prepareRequest(const QUrl &); private slots: void dxTrendTimeout(); private: QNetworkAccessManager* nam; }; #endif // QLOG_CORE_PROPCONDITIONS_H foldynl-QLog-3252ff9/core/QSLPrintLabelRenderer.cpp000066400000000000000000000370031517334601000221250ustar00rootroot00000000000000#include #include #include #include #include #include "QSLPrintLabelRenderer.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.qslprintlabelrenderer"); QSLPrintLabelRenderer::QSLPrintLabelRenderer() { FCT_IDENTIFICATION; } void QSLPrintLabelRenderer::setTemplate(const LabelTemplate &tmpl) { FCT_IDENTIFICATION; qCDebug(function_parameters) << tmpl.name; labelTemplate = tmpl; } void QSLPrintLabelRenderer::setLabels(const QList &inLabels) { FCT_IDENTIFICATION; qCDebug(function_parameters) << labels.size(); labels = inLabels; } void QSLPrintLabelRenderer::setFooterLeft(const QString &text) { FCT_IDENTIFICATION; qCDebug(function_parameters) << text; footerLeft = text; } void QSLPrintLabelRenderer::setFooterRight(const QString &text) { FCT_IDENTIFICATION; qCDebug(function_parameters) << text; footerRight = text; } void QSLPrintLabelRenderer::setSkipLabels(int count) { FCT_IDENTIFICATION; qCDebug(function_parameters) << count; skipLabels = qMax(0, count); } void QSLPrintLabelRenderer::setPrintBorders(bool enabled) { FCT_IDENTIFICATION; qCDebug(function_parameters) << enabled; printBorders = enabled; } void QSLPrintLabelRenderer::setStyleOptions(const LabelStyleOptions &opts) { FCT_IDENTIFICATION; styleOptions = opts; } int QSLPrintLabelRenderer::labelsPerPage() const { FCT_IDENTIFICATION; return labelTemplate.cols * labelTemplate.rows; } int QSLPrintLabelRenderer::labelCount() const { FCT_IDENTIFICATION; return labels.size(); } int QSLPrintLabelRenderer::pageCount() const { FCT_IDENTIFICATION; int totalSlots = labels.size() + skipLabels; int perPage = labelsPerPage(); return ( perPage > 0 ) ? (totalSlots + perPage - 1) / perPage : 0; } qreal QSLPrintLabelRenderer::mmToUnits(const qreal mm, const QPaintDevice *device, bool yAxis) const { FCT_IDENTIFICATION; return mm * (yAxis ? device->logicalDpiY() : device->logicalDpiX()) / 25.4; // to inch - DPI (px/inch) } void QSLPrintLabelRenderer::drawLabel(QPainter *painter, const QRectF &labelRect, const QSLLabelData &label) { FCT_IDENTIFICATION; if ( !painter ) return; const QPaintDevice *device = painter->device(); if ( !device ) return; if ( printBorders ) { painter->save(); painter->setPen(QPen(Qt::black, 0.5)); painter->setBrush(Qt::NoBrush); painter->drawRect(labelRect); painter->restore(); } qreal padH = mmToUnits(2.0, device); qreal padV = mmToUnits(1.5, device, true); QRectF contentRect = labelRect.adjusted(padH, padV, -padH, -padV); if ( contentRect.width() <= 0 || contentRect.height() <= 0 ) return; // Fonts from style options QFont fontToRadio(styleOptions.sansFontFamily); fontToRadio.setPointSizeF(styleOptions.toRadioFontSize); QFont fontCallsign(styleOptions.sansFontFamily); fontCallsign.setPointSizeF(styleOptions.callsignFontSize); fontCallsign.setBold(true); QFont fontHeader(styleOptions.sansFontFamily); fontHeader.setPointSizeF(styleOptions.headerFontSize); fontHeader.setBold(true); QFont fontData(styleOptions.monoFontFamily.isEmpty() ? QFontDatabase::systemFont(QFontDatabase::FixedFont) : QFont(styleOptions.monoFontFamily)); fontData.setPointSizeF(styleOptions.dataFontSize); QFont fontFooter(styleOptions.sansFontFamily); fontFooter.setPointSizeF(styleOptions.headerFontSize); // Metrics QFontMetricsF fmToRadio(fontToRadio, device); QFontMetricsF fmCallsign(fontCallsign, device); QFontMetricsF fmHeader(fontHeader, device); QFontMetricsF fmData(fontData, device); QFontMetricsF fmFooter(fontFooter, device); // Vertical layout calculation const qreal lineToRadio = fmToRadio.height(); const qreal lineCallsign = fmCallsign.height(); const qreal lineHeader = fmHeader.height(); const qreal lineData = fmData.height(); const qreal lineFooter = fmFooter.height(); // Line 1: "To Radio" + callsign share the same vertical line // "To Radio" left-aligned, callsign centered const qreal line1Height = qMax(lineToRadio, lineCallsign); qreal currentY = contentRect.top(); // --- Line 1: "To Radio" + Callsign --- painter->setFont(fontToRadio); painter->setPen(Qt::black); const QRectF toRadioRect(contentRect.left(), currentY, contentRect.width(), line1Height); const QString toRadioText = styleOptions.toRadioText.isEmpty() ? "To Radio" : styleOptions.toRadioText; painter->drawText(toRadioRect, Qt::AlignLeft | Qt::AlignVCenter, toRadioText); painter->setFont(fontCallsign); painter->drawText(toRadioRect, Qt::AlignHCenter | Qt::AlignVCenter, label.callsign); currentY += line1Height; // --- Compute dynamic column widths --- // Column headers (from style options, with non-empty guard) const QString hdrDate = styleOptions.hdrDate.isEmpty() ? "Date" : styleOptions.hdrDate; const QString hdrTime = styleOptions.hdrTime.isEmpty() ? "Time" : styleOptions.hdrTime; const QString hdrBand = styleOptions.hdrBand.isEmpty() ? "Band" : styleOptions.hdrBand; const QString hdrMode = styleOptions.hdrMode.isEmpty() ? "Mode" : styleOptions.hdrMode; const QString hdrQsl = styleOptions.hdrQsl.isEmpty() ? "QSL" : styleOptions.hdrQsl; // Measure column widths using worst-case representative strings // to ensure consistent layout across all labels qreal colWidthDate = qMax(fmHeader.horizontalAdvance(hdrDate), fmData.horizontalAdvance("2025-07-26")); qreal colWidthTime = qMax(fmHeader.horizontalAdvance(hdrTime), fmData.horizontalAdvance("00:00")); qreal colWidthBand = qMax(fmHeader.horizontalAdvance(hdrBand), fmData.horizontalAdvance("160M")); qreal colWidthMode = qMax(fmHeader.horizontalAdvance(hdrMode), fmData.horizontalAdvance("SSB")); qreal colWidthQsl = qMax(fmHeader.horizontalAdvance(hdrQsl), fmData.horizontalAdvance("TNX")); const bool hasExtra = !styleOptions.extraColumnHeader.isEmpty(); qreal colWidthExtra = 0.0; if ( hasExtra ) colWidthExtra = qMax(fmHeader.horizontalAdvance(styleOptions.extraColumnHeader), fmData.horizontalAdvance("XXXXXXXXXX")); // Add inter-column spacing (1.5mm fixed gap) qreal colGap = mmToUnits(1.5, device); const qreal totalWidth = colWidthDate + colWidthTime + colWidthBand + colWidthMode + colWidthQsl + (hasExtra ? colWidthExtra : 0.0) + (hasExtra ? 5.0 : 4.0) * colGap; // Scale columns proportionally if total exceeds content width const qreal availWidth = contentRect.width(); if ( totalWidth > availWidth && totalWidth > 0 ) { qreal scale = availWidth / totalWidth; colWidthDate *= scale; colWidthTime *= scale; colWidthBand *= scale; colWidthMode *= scale; colWidthQsl *= scale; colWidthExtra *= scale; colGap *= scale; } // --- Line 2: Column headers --- const qreal headerRowHeight = lineHeader + mmToUnits(0.5, device, true); painter->setFont(fontHeader); qreal colX = contentRect.left(); painter->drawText(QRectF(colX, currentY, colWidthDate, headerRowHeight), Qt::AlignLeft | Qt::AlignVCenter, hdrDate); colX += colWidthDate + colGap; painter->drawText(QRectF(colX, currentY, colWidthTime, headerRowHeight), Qt::AlignLeft | Qt::AlignVCenter, hdrTime); colX += colWidthTime + colGap; painter->drawText(QRectF(colX, currentY, colWidthBand, headerRowHeight), Qt::AlignLeft | Qt::AlignVCenter, hdrBand); colX += colWidthBand + colGap; painter->drawText(QRectF(colX, currentY, colWidthMode, headerRowHeight), Qt::AlignLeft | Qt::AlignVCenter, hdrMode); colX += colWidthMode + colGap; painter->drawText(QRectF(colX, currentY, colWidthQsl, headerRowHeight), Qt::AlignLeft | Qt::AlignVCenter, hdrQsl); if ( hasExtra ) { colX += colWidthQsl + colGap; painter->drawText(QRectF(colX, currentY, colWidthExtra, headerRowHeight), Qt::AlignLeft | Qt::AlignVCenter, styleOptions.extraColumnHeader); } currentY += headerRowHeight; // --- QSO data rows (up to maxQsoRows) --- const qreal dataRowHeight = lineData + mmToUnits(0.3, device, true); painter->setFont(fontData); const int maxRows = qMin(label.qsos.size(), styleOptions.maxQsoRows); for ( int i = 0; i < styleOptions.maxQsoRows; ++i ) { if ( i < maxRows ) { const QSLLabelData::QsoRow &row = label.qsos.at(i); colX = contentRect.left(); painter->drawText(QRectF(colX, currentY, colWidthDate, dataRowHeight), Qt::AlignLeft | Qt::AlignVCenter, row.date); colX += colWidthDate + colGap; painter->drawText(QRectF(colX, currentY, colWidthTime, dataRowHeight), Qt::AlignLeft | Qt::AlignVCenter, row.time); colX += colWidthTime + colGap; painter->drawText(QRectF(colX, currentY, colWidthBand, dataRowHeight), Qt::AlignLeft | Qt::AlignVCenter, row.band); colX += colWidthBand + colGap; painter->drawText(QRectF(colX, currentY, colWidthMode, dataRowHeight), Qt::AlignLeft | Qt::AlignVCenter, row.mode); colX += colWidthMode + colGap; painter->drawText(QRectF(colX, currentY, colWidthQsl, dataRowHeight), Qt::AlignLeft | Qt::AlignVCenter, row.qsl); if ( hasExtra ) { colX += colWidthQsl + colGap; painter->drawText(QRectF(colX, currentY, colWidthExtra, dataRowHeight), Qt::AlignLeft | Qt::AlignVCenter, row.extra); } } currentY += dataRowHeight; } // --- Footer line --- const QRectF footerRect(contentRect.left(), contentRect.bottom() - lineFooter, contentRect.width(), lineFooter); painter->setFont(fontFooter); if ( !footerLeft.isEmpty() ) painter->drawText(footerRect, Qt::AlignLeft | Qt::AlignVCenter, footerLeft); if ( !footerRight.isEmpty() ) painter->drawText(footerRect, Qt::AlignRight | Qt::AlignVCenter, footerRight); } void QSLPrintLabelRenderer::drawPage(QPainter *painter, int pageIndex) { FCT_IDENTIFICATION; qCDebug(function_parameters) << pageIndex; if ( !painter ) return; QPaintDevice *device = painter->device(); if ( !device ) return; const int perPage = labelsPerPage(); if ( perPage <= 0 ) return; const int slotStart = pageIndex * perPage; for ( int row = 0; row < labelTemplate.rows; ++row ) { for ( int col = 0; col < labelTemplate.cols; ++col ) { const int slotIndex = slotStart + row * labelTemplate.cols + col; const int labelIndex = slotIndex - skipLabels; // Skip blank positions (for skip labels on first page) if ( labelIndex < 0 ) continue; // Past all labels if ( labelIndex >= labels.size() ) return; const qreal xMm = labelTemplate.leftMarginMm + col * (labelTemplate.labelWidthMm + labelTemplate.hSpacingMm); const qreal yMm = labelTemplate.topMarginMm + row * (labelTemplate.labelHeightMm + labelTemplate.vSpacingMm); const qreal x = mmToUnits(xMm, device); const qreal y = mmToUnits(yMm, device, true); const qreal w = mmToUnits(labelTemplate.labelWidthMm, device); const qreal h = mmToUnits(labelTemplate.labelHeightMm, device, true); const QRectF labelRect(x, y, w, h); drawLabel(painter, labelRect, labels.at(labelIndex)); } } } QImage QSLPrintLabelRenderer::renderPage(int pageIndex, int dpi) { FCT_IDENTIFICATION; qCDebug(function_parameters) << pageIndex << dpi; if ( dpi <= 0 ) { qCWarning(runtime) << "Invalid DPI" << dpi; return QImage(); } if ( pageIndex < 0 || pageIndex >= pageCount() ) { qCWarning(runtime) << "Invalid page index" << pageIndex; return QImage(); } QSizeF pageSizeMm = QPageSize(labelTemplate.pageSize).size(QPageSize::Millimeter); if ( labelTemplate.orientation == QPageLayout::Landscape ) pageSizeMm.transpose(); const int widthPx = qRound(pageSizeMm.width() * dpi / 25.4); const int heightPx = qRound(pageSizeMm.height() * dpi / 25.4); QImage image(widthPx, heightPx, QImage::Format_ARGB32_Premultiplied); image.setDotsPerMeterX(qRound(dpi / 25.4 * 1000.0)); image.setDotsPerMeterY(qRound(dpi / 25.4 * 1000.0)); image.fill(Qt::white); QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::TextAntialiasing, true); drawPage(&painter, pageIndex); painter.end(); return image; } void QSLPrintLabelRenderer::printAll(QPrinter *printer) { FCT_IDENTIFICATION; if ( !printer ) { qCWarning(runtime) << "Null printer"; return; } const int pages = pageCount(); if ( pages <= 0 ) { qCWarning(runtime) << "No pages to print"; return; } printer->setResolution(PRINTER_RESOLUTION); const QPageLayout layout(QPageSize(labelTemplate.pageSize), labelTemplate.orientation, QMarginsF(0, 0, 0, 0), QPageLayout::Millimeter); printer->setPageLayout(layout); QPainter painter(printer); if ( !painter.isActive() ) { qCWarning(runtime) << "Cannot begin painting on printer"; return; } for ( int i = 0; i < pages; ++i ) { if ( i > 0 ) printer->newPage(); drawPage(&painter, i); } painter.end(); } QList QSLPrintLabelRenderer::predefinedTemplates() { FCT_IDENTIFICATION; static const QList templates = { {"Avery 3664", QPageLayout::Portrait, QPageSize::A4, 3, 8, 70.0, 33.8, 4.3, 0.0, 0.0, 0.0}, {"Avery 3422", QPageLayout::Portrait, QPageSize::A4, 3, 8, 70.0, 35.0, 8.5, 0.0, 0.0, 0.0}, {"Avery 3474", QPageLayout::Portrait, QPageSize::A4, 2, 12, 105.0, 24.0, 4.5, 0.0, 0.0, 0.0}, {"Avery 5160 / 8160", QPageLayout::Portrait, QPageSize::Letter, 3, 10, 66.7, 25.4, 12.7, 4.8, 3.2, 0.0}, {"Avery 5163 / 8163", QPageLayout::Portrait, QPageSize::Letter, 2, 5, 101.6, 50.8, 12.70, 4.762, 3.175, 0.0}, {"Avery L7160", QPageLayout::Portrait, QPageSize::A4, 3, 7, 63.5, 38.1, 15.15, 7.25, 2.54, 0.0}, {"Avery L7161", QPageLayout::Portrait, QPageSize::A4, 3, 5, 63.5, 46.6, 15.15, 7.25, 2.54, 0.0}, {"Avery 5164", QPageLayout::Portrait, QPageSize::Letter, 2, 3, 101.6, 84.67, 12.70, 4.762, 3.175, 0.0}, }; return templates; } foldynl-QLog-3252ff9/core/QSLPrintLabelRenderer.h000066400000000000000000000052761517334601000216010ustar00rootroot00000000000000#ifndef QLOG_CORE_QSLPRINTLABELRENDERER_H #define QLOG_CORE_QSLPRINTLABELRENDERER_H #include #include #include #include #include #include class QPainter; class QPrinter; class QPaintDevice; struct LabelTemplate { QString name; QPageLayout::Orientation orientation; QPageSize::PageSizeId pageSize; int cols; int rows; double labelWidthMm; double labelHeightMm; double topMarginMm; double leftMarginMm; double hSpacingMm; double vSpacingMm; }; struct LabelStyleOptions { QString sansFontFamily; // empty = system default QString monoFontFamily; // empty = system fixed font qreal toRadioFontSize = 7.5; qreal callsignFontSize = 14.0; qreal headerFontSize = 7.0; qreal dataFontSize = 8.0; QString extraColumnHeader; // empty = no extra column int maxQsoRows = 4; // 1-4 QSO data rows per label QString toRadioText = "To Radio"; QString hdrDate = "Date"; QString hdrTime = "Time"; QString hdrBand = "Band"; QString hdrMode = "Mode"; QString hdrQsl = "QSL"; }; struct QSLLabelData { QString callsign; struct QsoRow { QString date; // formatted by dialog according to user date format QString time; // "09:38" QString band; // "20M" QString mode; // "SSB" QString qsl; // "PSE" or "TNX" QString extra; // raw DB value for extra column, empty if unused }; QList qsos; }; class QSLPrintLabelRenderer { public: QSLPrintLabelRenderer(); void setTemplate(const LabelTemplate &tmpl); void setLabels(const QList &inLabels); void setFooterLeft(const QString &text); void setFooterRight(const QString &text); void setSkipLabels(int count); void setPrintBorders(bool enabled); void setStyleOptions(const LabelStyleOptions &opts); int pageCount() const; int labelCount() const; QImage renderPage(int pageIndex, int dpi = 150); void printAll(QPrinter *printer); static QList predefinedTemplates(); private: void drawLabel(QPainter *painter, const QRectF &labelRect, const QSLLabelData &label); void drawPage(QPainter *painter, int pageIndex); qreal mmToUnits(const qreal mm, const QPaintDevice *device, bool yAxis = false) const; int labelsPerPage() const; LabelTemplate labelTemplate; QList labels; QString footerLeft; QString footerRight; int skipLabels = 0; bool printBorders = false; LabelStyleOptions styleOptions; const int PRINTER_RESOLUTION = 300; }; #endif // QLOG_CORE_QSLPRINTLABELRENDERER_H foldynl-QLog-3252ff9/core/QSLStorage.cpp000066400000000000000000000337701517334601000200150ustar00rootroot00000000000000#include #include #include #include #include #include "QSLStorage.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.qslstorage"); QSLStorage::QSLStorage(QObject *parent) : QObject(parent) { FCT_IDENTIFICATION; } bool QSLStorage::add(const QSLObject &qslObject) { FCT_IDENTIFICATION; qCDebug(function_parameters) << qslObject.getQSOID() << qslObject.getSource() << qslObject.getQSLName(); QSqlQuery insert; if ( !insert.prepare("REPLACE INTO contacts_qsl_cards (contactid, source, name, data) " " VALUES (:contactid, :source, :name, :data)" ) ) { qCDebug(runtime) << " Cannot prepare INSERT for PaperQSL " << insert.lastError(); return false; } insert.bindValue(":contactid", qslObject.getQSOID()); insert.bindValue(":source", qslObject.getSource()); insert.bindValue(":name", qslObject.getQSLName()); insert.bindValue(":data", qslObject.getBLOB(QSLObject::BASE64FORM)); if ( !insert.exec() ) { qCDebug(runtime) << "Cannot import QSL" << insert.lastError(); return false; } return true; } bool QSLStorage::remove(const QSqlRecord &qso, const QSLObject::SourceType source, const QString &qslName) { FCT_IDENTIFICATION; QSqlQuery query; if ( !query.prepare("DELETE FROM contacts_qsl_cards " "WHERE source = :source " "AND contactid = :contactid " "AND name = :qsl_name")) { qCDebug(runtime) << "Cannot prepare SQL Statement"; return false; } query.bindValue(":source", source); query.bindValue(":contactid", qso.value("id")); query.bindValue(":qsl_name", qslName); if ( !query.exec() ) { qCDebug(runtime) << "Cannot delete QSL file" << qslName; return false; } return true; } QStringList QSLStorage::getAvailableQSLNames(const QSqlRecord &qso, const QSLObject::SourceType sourceFilter) const { FCT_IDENTIFICATION; QStringList ret; QSqlQuery query; if ( !query.prepare("SELECT name FROM contacts_qsl_cards " "WHERE source = :source " "AND contactid = :contactid " "ORDER BY name")) { qCDebug(runtime) << "Cannot prepare SQL Statement"; return ret; } query.bindValue(":source", sourceFilter); query.bindValue(":contactid", qso.value("id")); if ( query.exec() ) { while(query.next()) { ret << query.value(0).toString(); } } else { qCDebug(runtime) << "Error" << query.lastError(); } return ret; } QSLObject QSLStorage::getQSL(const QSqlRecord &qso, const QSLObject::SourceType source, const QString &qslName) const { FCT_IDENTIFICATION; QSqlQuery query; if ( !query.prepare("SELECT data FROM contacts_qsl_cards " "WHERE source = :source " "AND contactid = :contactid " "AND name = :qsl_name " "ORDER BY name LIMIT 1")) { qCDebug(runtime) << "Cannot prepare SQL Statement"; } else { query.bindValue(":source", source); query.bindValue(":contactid", qso.value("id")); query.bindValue(":qsl_name", qslName); if ( query.exec() && query.next() ) return QSLObject(qso, source, qslName, query.value(0).toByteArray(), QSLObject::BASE64FORM); } return QSLObject (qso, source, qslName, QByteArray(), QSLObject::RAWBYTES); } QSLStorage::FilterValues QSLStorage::getDistinctFilterValues() const { FCT_IDENTIFICATION; FilterValues ret; QSqlQuery query; if ( !query.prepare("SELECT DISTINCT translate_to_locale(c.country), strftime('%Y', c.start_time), " "strftime('%m', c.start_time), c.band, c.mode, c.cont, c.dxcc " "FROM contacts_qsl_cards q " "JOIN contacts c ON q.contactid = c.id") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return ret; } QSet bands, modes, continents; QMap> yearMonthSets; if ( query.exec() ) { while ( query.next() ) { const QString country = query.value(0).toString(); const QString year = query.value(1).toString(); const QString month = query.value(2).toString(); const QString band = query.value(3).toString(); const QString mode = query.value(4).toString(); const QString cont = query.value(5).toString(); const int dxcc = query.value(6).toInt(); if ( !country.isEmpty() && dxcc > 0 ) ret.countries.insert(country, dxcc); if ( !year.isEmpty() ) yearMonthSets[year].insert(month.isEmpty() ? "00" : month); if ( !band.isEmpty() ) bands.insert(band); if ( !mode.isEmpty() ) modes.insert(mode); if ( !cont.isEmpty() ) continents.insert(cont); } } else { qCDebug(runtime) << "Error" << query.lastError(); } ret.bands = bands.values(); ret.modes = modes.values(); ret.continents = continents.values(); // Build sorted yearMonths map for ( QMap>::const_iterator it = yearMonthSets.constBegin(); it != yearMonthSets.constEnd(); ++it ) { QStringList months = it.value().values(); std::sort(months.begin(), months.end()); ret.yearMonths.insert(it.key(), months); } std::sort(ret.bands.begin(), ret.bands.end()); std::sort(ret.modes.begin(), ret.modes.end()); std::sort(ret.continents.begin(), ret.continents.end()); return ret; } static QList executeGalleryQuery(QSqlQuery &query) { QList ret; if ( query.exec() ) { while ( query.next() ) { QSLGalleryItem item; item.contactId = query.value(0).toULongLong(); item.source = static_cast(query.value(1).toInt()); item.name = query.value(2).toString(); item.callsign = query.value(3).toString(); item.startTime = query.value(4).toDateTime(); item.country = query.value(5).toString(); item.favorite = query.value(6).toBool(); ret << item; } } return ret; } QList QSLStorage::getGalleryItems() const { FCT_IDENTIFICATION; QSqlQuery query; if ( !query.prepare(galleryBaseSQL + "ORDER BY c.start_time DESC") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return QList(); } QList ret = executeGalleryQuery(query); if ( ret.isEmpty() ) qCDebug(runtime) << "No gallery items found or error" << query.lastError(); return ret; } QList QSLStorage::getGalleryItemsByDxcc(int dxcc) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << dxcc; QSqlQuery query; if ( !query.prepare(galleryBaseSQL + "WHERE c.dxcc = :dxcc ORDER BY c.start_time DESC") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return QList(); } query.bindValue(":dxcc", dxcc); QList ret = executeGalleryQuery(query); if ( ret.isEmpty() ) qCDebug(runtime) << "No gallery items for dxcc" << dxcc << query.lastError(); return ret; } QList QSLStorage::getGalleryItemsByYear(const QString &year) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << year; QSqlQuery query; if ( !query.prepare(galleryBaseSQL + "WHERE strftime('%Y', c.start_time) = :year ORDER BY c.start_time DESC") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return QList(); } query.bindValue(":year", year); QList ret = executeGalleryQuery(query); if ( ret.isEmpty() ) qCDebug(runtime) << "No gallery items for year" << year << query.lastError(); return ret; } QList QSLStorage::getGalleryItemsByYearMonth(const QString &year, const QString &month) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << year << month; QSqlQuery query; if ( !query.prepare(galleryBaseSQL + "WHERE strftime('%Y', c.start_time) = :year " "AND strftime('%m', c.start_time) = :month ORDER BY c.start_time DESC") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return QList(); } query.bindValue(":year", year); query.bindValue(":month", month); QList ret = executeGalleryQuery(query); if ( ret.isEmpty() ) qCDebug(runtime) << "No gallery items for" << year << month << query.lastError(); return ret; } QList QSLStorage::getGalleryItemsByBand(const QString &band) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << band; QSqlQuery query; if ( !query.prepare(galleryBaseSQL + "WHERE c.band = :band ORDER BY c.start_time DESC") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return QList(); } query.bindValue(":band", band); QList ret = executeGalleryQuery(query); if ( ret.isEmpty() ) qCDebug(runtime) << "No gallery items for band" << band << query.lastError(); return ret; } QList QSLStorage::getGalleryItemsByMode(const QString &mode) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << mode; QSqlQuery query; if ( !query.prepare(galleryBaseSQL + "WHERE c.mode = :mode ORDER BY c.start_time DESC") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return QList(); } query.bindValue(":mode", mode); QList ret = executeGalleryQuery(query); if ( ret.isEmpty() ) qCDebug(runtime) << "No gallery items for mode" << mode << query.lastError(); return ret; } QList QSLStorage::getGalleryItemsByContinent(const QString &continent) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << continent; QSqlQuery query; if ( !query.prepare(galleryBaseSQL + "WHERE c.cont = :cont ORDER BY c.start_time DESC") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return QList(); } query.bindValue(":cont", continent); QList ret = executeGalleryQuery(query); if ( ret.isEmpty() ) qCDebug(runtime) << "No gallery items for continent" << continent << query.lastError(); return ret; } QByteArray QSLStorage::getQSLData(qulonglong contactId, int source, const QString &name) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << contactId << source << name; QSqlQuery query; if ( !query.prepare("SELECT data FROM contacts_qsl_cards " "WHERE contactid = :contactid AND source = :source AND name = :name " "LIMIT 1") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return QByteArray(); } query.bindValue(":contactid", static_cast(contactId)); query.bindValue(":source", source); query.bindValue(":name", name); if ( query.exec() && query.next() ) return QByteArray::fromBase64(query.value(0).toByteArray()); qCDebug(runtime) << "QSL data not found" << query.lastError(); return QByteArray(); } QList QSLStorage::getGalleryItemsFavorite() const { FCT_IDENTIFICATION; QSqlQuery query; if ( !query.prepare(galleryBaseSQL + "WHERE q.favorite = 1 ORDER BY c.start_time DESC") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return QList(); } QList ret = executeGalleryQuery(query); if ( ret.isEmpty() ) qCDebug(runtime) << "No favorite gallery items found or error" << query.lastError(); return ret; } bool QSLStorage::setFavorite(qulonglong contactId, QSLObject::SourceType source, const QString &name, bool favorite) { FCT_IDENTIFICATION; qCDebug(function_parameters) << contactId << source << name << favorite; QSqlQuery query; if ( !query.prepare("UPDATE contacts_qsl_cards SET favorite = :fav " "WHERE contactid = :contactid AND source = :source AND name = :name") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return false; } query.bindValue(":fav", favorite ? 1 : 0); query.bindValue(":contactid", static_cast(contactId)); query.bindValue(":source", static_cast(source)); query.bindValue(":name", name); if ( !query.exec() ) { qCDebug(runtime) << "Cannot update favorite" << query.lastError(); return false; } return true; } bool QSLStorage::isFavorite(qulonglong contactId, QSLObject::SourceType source, const QString &name) const { FCT_IDENTIFICATION; QSqlQuery query; if ( !query.prepare("SELECT favorite FROM contacts_qsl_cards " "WHERE contactid = :contactid AND source = :source AND name = :name " "LIMIT 1") ) { qCDebug(runtime) << "Cannot prepare SQL Statement" << query.lastError(); return false; } query.bindValue(":contactid", static_cast(contactId)); query.bindValue(":source", static_cast(source)); query.bindValue(":name", name); if ( query.exec() && query.next() ) return query.value(0).toBool(); return false; } foldynl-QLog-3252ff9/core/QSLStorage.h000066400000000000000000000073051517334601000174550ustar00rootroot00000000000000#ifndef QLOG_CORE_QSLSTORAGE_H #define QLOG_CORE_QSLSTORAGE_H #include #include #include #include #include #include class QSLObject { public: enum SourceType { QSLFILE = 0, EQSL = 1, }; enum BLOBFormat { BASE64FORM, RAWBYTES }; explicit QSLObject( const qulonglong &qsoID, const SourceType source, const QString &qslName, const QByteArray &inBlob, const BLOBFormat format) : qsoID(qsoID), source(source), qslName(qslName), blob((format == RAWBYTES) ? inBlob : QByteArray::fromBase64(inBlob)) {}; explicit QSLObject( const QSqlRecord &qso, const SourceType source, const QString &qslName, const QByteArray &inBlob, const BLOBFormat format) : QSLObject(qso.value("id").toULongLong(), source, qslName, inBlob, format) {} qulonglong getQSOID() const {return qsoID;}; QSLObject::SourceType getSource() const {return source;}; QString getQSLName() const {return qslName;}; QByteArray getBLOB(BLOBFormat format = RAWBYTES) const {return (format == BASE64FORM) ? blob.toBase64() : blob;}; private: qulonglong qsoID; SourceType source; QString qslName; QByteArray blob; }; struct QSLGalleryItem { qulonglong contactId; QSLObject::SourceType source; QString name; QString callsign; QDateTime startTime; QString country; bool favorite = false; }; class QSLStorage : public QObject { Q_OBJECT public: explicit QSLStorage(QObject *parent = nullptr); bool add(const QSLObject &); bool remove(const QSqlRecord &qso, const QSLObject::SourceType source, const QString &qslName); QStringList getAvailableQSLNames(const QSqlRecord &qso, const QSLObject::SourceType sourceFilter) const; QSLObject getQSL(const QSqlRecord &qso, const QSLObject::SourceType source, const QString &qslName) const; struct FilterValues { QMap countries; // localizedName -> dxcc_id QMap yearMonths; // year -> sorted list of months ("01".."12") QStringList bands; QStringList modes; QStringList continents; }; FilterValues getDistinctFilterValues() const; QList getGalleryItems() const; QList getGalleryItemsByDxcc(int dxcc) const; QList getGalleryItemsByYear(const QString &year) const; QList getGalleryItemsByYearMonth(const QString &year, const QString &month) const; QList getGalleryItemsFavorite() const; QList getGalleryItemsByBand(const QString &band) const; QList getGalleryItemsByMode(const QString &mode) const; QList getGalleryItemsByContinent(const QString &continent) const; QByteArray getQSLData(qulonglong contactId, int source, const QString &name) const; bool setFavorite(qulonglong contactId, QSLObject::SourceType source, const QString &name, bool favorite); bool isFavorite(qulonglong contactId, QSLObject::SourceType source, const QString &name) const; private: const QString galleryBaseSQL= "SELECT q.contactid, q.source, q.name, c.callsign, c.start_time, translate_to_locale(c.country), q.favorite " "FROM contacts_qsl_cards q " "JOIN contacts c ON q.contactid = c.id "; }; #endif // QLOG_CORE_QSLSTORAGE_H foldynl-QLog-3252ff9/core/QSOFilterManager.cpp000066400000000000000000000234241517334601000211270ustar00rootroot00000000000000#include #include #include "QSOFilterManager.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.qsofiltermanager"); QSOFilterManager::QSOFilterManager(QObject *parent) : QObject(parent), stmtsReady(true) { FCT_IDENTIFICATION; if ( !insertRuleStmt.prepare(QLatin1String("INSERT INTO qso_filter_rules(filter_name, table_field_index, operator_id, value) " "VALUES (:filterName, :tableFieldIndex, :operatorID, :valueString)") ) ) { qWarning() << "cannot preapre insert insertRuleStmt"; stmtsReady = false; } if ( !insertFilterStmt.prepare(QLatin1String("INSERT INTO qso_filters (filter_name, matching_type) VALUES (:filterName, :matchingType) " "ON CONFLICT(filter_name) DO UPDATE SET matching_type = :matchingType WHERE filter_name = :filterName") ) ) { qWarning() << "cannot preapre insert insertFilterStmt"; stmtsReady = false; } if ( !deleteFilterStmt.prepare(QLatin1String("DELETE FROM qso_filter_rules WHERE filter_name = :filterName") ) ) { qWarning() << "cannot preapre insert deleteFilterStmt"; stmtsReady = false; } } bool QSOFilterManager::deleteFilterRules(const QString &filterName) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filterName; deleteFilterStmt.bindValue(":filterName", filterName); bool ret = deleteFilterStmt.exec(); if ( !ret ) qCDebug(runtime) << "SQL Error" << deleteFilterStmt.lastError().text(); return ret; } bool QSOFilterManager::replaceFilter(const QString &filterName, const int matchingType) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filterName << matchingType; insertFilterStmt.bindValue(":filterName", filterName); insertFilterStmt.bindValue(":matchingType", matchingType); bool ret = insertFilterStmt.exec(); if ( !ret ) qCDebug(runtime) << "SQL Error" << insertFilterStmt.lastError().text(); return ret; } bool QSOFilterManager::insertFilterRule(const QString & filterName, const QSOFilterRule &rule) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filterName << rule.tableFieldIndex << rule.operatorID << rule.value; insertRuleStmt.bindValue(":filterName", filterName); insertRuleStmt.bindValue(":tableFieldIndex", rule.tableFieldIndex); insertRuleStmt.bindValue(":operatorID", rule.operatorID); insertRuleStmt.bindValue(":valueString", (rule.value.isEmpty()) ? QVariant() : rule.value); bool ret = insertRuleStmt.exec(); if ( !ret ) qCDebug(runtime) << "SQL Error" << insertRuleStmt.lastError().text(); return ret; } bool QSOFilterManager::save(const QSOFilter &filter) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filter.filterName << filter.machingType; if ( !stmtsReady ) return false; QSqlDatabase::database().transaction(); if ( !replaceFilter(filter.filterName, filter.machingType) ) { QSqlDatabase::database().rollback(); return false; } if ( !deleteFilterRules(filter.filterName) ) { QSqlDatabase::database().rollback(); return false; } for ( const QSOFilterRule &rule : filter.rules ) { if ( !insertFilterRule(filter.filterName, rule) ) { QSqlDatabase::database().rollback(); return false; } } QSqlDatabase::database().commit(); return true; } bool QSOFilterManager::remove(const QString &filterName) { FCT_IDENTIFICATION; qCDebug(function_parameters) << filterName; QSqlQuery filterStmt; if ( ! filterStmt.prepare(QLatin1String("DELETE FROM qso_filters " "WHERE filter_name = :filterName;")) ) { qWarning() << "Cannot prepare delete statement"; return false; } filterStmt.bindValue(":filterName", filterName); if ( ! filterStmt.exec() ) { qInfo()<< "Cannot get filters names from DB" << filterStmt.lastError(); return false; } return true; } QStringList QSOFilterManager::getFilterList() const { FCT_IDENTIFICATION; QStringList ret; QSqlQuery filterStmt; if ( ! filterStmt.prepare(QLatin1String("SELECT filter_name " "FROM qso_filters " "ORDER BY filter_name")) ) { qWarning() << "Cannot prepare select statement"; return ret; } if ( filterStmt.exec() ) { while ( filterStmt.next() ) ret << filterStmt.value(0).toString(); } else qInfo()<< "Cannot get filters names from DB" << filterStmt.lastError();; return ret; } QSOFilter QSOFilterManager::getFilter(const QString &filterName) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << filterName; QSOFilter ret; QSqlQuery query; if ( ! query.prepare(QLatin1String("SELECT matching_type, table_field_index, operator_id, value " "FROM qso_filter_rules r, qso_filters f " "WHERE f.filter_name = :filter " " AND f.filter_name = r.filter_name")) ) { qWarning() << "Cannot prepare select statement"; return ret; } query.bindValue(":filter", filterName); if ( query.exec() ) { ret.filterName = filterName; while ( query.next() ) { QSOFilterRule rule; const QSqlRecord &record = query.record(); ret.machingType = record.value("matching_type").toInt(); rule.tableFieldIndex = record.value("table_field_index").toInt(); rule.operatorID = record.value("operator_id").toInt(); rule.value = record.value("value").toString(); ret.addRule(rule); } } else qCDebug(runtime) << "SQL execution error: " << query.lastError().text(); return ret; } QString QSOFilterManager::getWhereClause(const QString &filterName, const QString &columnPrefix) { FCT_IDENTIFICATION; QSqlQuery userFilterQuery; QString ret; QString finalColumnPfx = columnPrefix; finalColumnPfx += finalColumnPfx.isEmpty() ? "" : "."; if ( ! userFilterQuery.prepare( QString( "SELECT " "'(' || GROUP_CONCAT( ' ' || '" + finalColumnPfx + "' || c.name || ' ' || CASE WHEN r.value IS NULL AND o.sql_operator IN ('=', 'like') THEN 'IS' " " WHEN r.value IS NULL and r.operator_id NOT IN ('=', 'like') THEN 'IS NOT' " " WHEN o.sql_operator = ('starts with') THEN 'like' " " ELSE o.sql_operator END || " "' (' || quote(CASE o.sql_operator WHEN 'like' THEN '%' || r.value || '%' " " WHEN 'not like' THEN '%' || r.value || '%' " " WHEN 'starts with' THEN r.value || '%' " " ELSE r.value END) || ') ', m.sql_operator) || ')' " "FROM qso_filters f, qso_filter_rules r, " "qso_filter_operators o, qso_filter_matching_types m, " "PRAGMA_TABLE_INFO('contacts') c " "WHERE f.filter_name = :filterName " " AND f.filter_name = r.filter_name " " AND o.operator_id = r.operator_id " " AND m.matching_id = f.matching_type " " AND c.cid = r.table_field_index")) ) { qWarning() << "Cannot prepare select statement"; return ret; } userFilterQuery.bindValue(":filterName", filterName); qCDebug(runtime) << "User filter SQL: " << userFilterQuery.lastQuery(); if ( userFilterQuery.exec() ) { userFilterQuery.next(); ret = QString("( %1 )").arg(userFilterQuery.value(0).toString()); } else qCDebug(runtime) << "User filter error - " << userFilterQuery.lastError().text(); // This filter, when used with fields that contain time, only works by luck. // These fields are Timeon/Timeoff. They are stored by QSO Filter Dialog as values in the format // YYYY-MM-DDThh:mm:ss without a timezone. This is fine, since all times in QLog // are internally in UTC. The problem arises because this WHERE clause is later // used in a SELECT in the logbook. SQL does not compare the values as datetime, // but as strings — otherwise both sides would need to be proper datetime types. // Fortunately, both sides are strings in the same format, except that Timeon/Timeoff // includes a timezone at the end. Therefore, string comparison of the dates still works. return ret; } SqlListModel *QSOFilterManager::QSOFilterModel(const QString &firstValue, QObject *parent) { FCT_IDENTIFICATION; return new SqlListModel("SELECT filter_name " "FROM qso_filters " "ORDER BY filter_name COLLATE LOCALEAWARE ASC", firstValue, parent); } foldynl-QLog-3252ff9/core/QSOFilterManager.h000066400000000000000000000053201517334601000205670ustar00rootroot00000000000000#ifndef QSOFILTERMANAGER_H #define QSOFILTERMANAGER_H #include #include #include #include "models/LogbookModel.h" #include "models/SqlListModel.h" struct QSOFilterRule { QSOFilterRule() {}; QSOFilterRule(int in_idx, int in_operatorID, const QString &in_value) : tableFieldIndex(in_idx), operatorID(in_operatorID), value(in_value){ }; int tableFieldIndex; int operatorID; QString value; }; class QSOFilter { public: QString filterName; int machingType; QList rules; QSOFilter() : machingType(0){}; void addRule(const QSOFilterRule &rule) { rules.append(rule); } static QSOFilterRule createFromDateRule(const QDateTime &date) { return QSOFilterRule(LogbookModel::COLUMN_TIME_ON, 4, date.toString("yyyy-MM-ddTHH:mm:ss")); // 4 - should be enum - later '4' > } static QSOFilterRule createNonEmptyContestRule(const QString &contestID) { return QSOFilterRule(LogbookModel::COLUMN_CONTEST_ID, 2, contestID);// '2' is like } static QSOFilterRule createToDateRule(const QDateTime &date) { return QSOFilterRule(LogbookModel::COLUMN_TIME_ON, 5, date.toString("yyyy-MM-ddTHH:mm:ss")); // 5 - should be enum - later '5' < // ON of OFF??? } static QSOFilter createFromDateContestFilter(const QString &contestID, const QDateTime &date) { QSOFilter ret; ret.filterName = QString("%1-%2").arg(contestID, date.toString("yyyy/MM/dd hh:mm")); ret.machingType = 0; // should be enum - later ret.addRule(createFromDateRule(date)); ret.addRule(createNonEmptyContestRule(contestID)); return ret; } }; class QSOFilterManager : public QObject { Q_OBJECT public: static QSOFilterManager * instance() { static QSOFilterManager instance; return &instance; } static QString getWhereClause(const QString &filterName, const QString &columnPrefix = {}); static SqlListModel* QSOFilterModel(const QString &firstValue, QObject *parent = nullptr); bool save(const QSOFilter &filter); bool remove(const QString &filterName); QStringList getFilterList() const; QSOFilter getFilter(const QString &filterName) const; private: QSOFilterManager(QObject *parent = nullptr); bool replaceFilter(const QString &filterName, const int matchingType); bool insertFilterRule(const QString &filterName, const QSOFilterRule &rule); bool deleteFilterRules(const QString &filterName); bool stmtsReady; QSqlQuery insertRuleStmt; QSqlQuery insertFilterStmt; QSqlQuery deleteFilterStmt; }; #endif // QSOFILTERMANAGER_H foldynl-QLog-3252ff9/core/QuadKeyCache.h000066400000000000000000000030001517334601000177440ustar00rootroot00000000000000#ifndef QLOG_CORE_QUADKEYCACHE_H #define QLOG_CORE_QUADKEYCACHE_H #include #include #include #include template class QuadKeyCache : public QCache, QPair>, Value> { public: using Key = QPair, QPair>; void insert(const int keyA, const int keyB, const QString& keyC, const QString& keyD, Value* value) { Key key = qMakePair(qMakePair(keyA, keyB), qMakePair(keyC, keyD)); QCache::insert(key, value); } Value* value(const int keyA, const int keyB, const QString& keyC, const QString& keyD) const { Key key = qMakePair(qMakePair(keyA, keyB), qMakePair(keyC, keyD)); return QCache::object(key); } bool contains(const int keyA, const int keyB, const QString& keyC, const QString& keyD) const { Key key = qMakePair(qMakePair(keyA, keyB), qMakePair(keyC, keyD)); return QCache::contains(key); } int size() const { return QCache::size(); } void invalidate(const int keyA, const int keyB) { QList keysToRemove; for( const Key& key : QCache::keys() ) { if (key.first.first == keyA && key.first.second == keyB) keysToRemove.append(key); } for( const Key& key : keysToRemove ) QCache::remove(key); } }; #endif // QLOG_CORE_QUADKEYCACHE_H foldynl-QLog-3252ff9/core/WsjtxUDPReceiver.cpp000066400000000000000000000561221517334601000212020ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include "WsjtxUDPReceiver.h" #include "data/Data.h" #include "debug.h" #include "data/HostsPortString.h" #include "rig/macros.h" #include "data/BandPlan.h" #include "logformat/AdiFormat.h" #include "core/LogParam.h" MODULE_IDENTIFICATION("qlog.core.wsjtx"); // https://github.com/saitohirga/WSJT-X/blob/master/Network/NetworkMessage.hpp WsjtxUDPReceiver::WsjtxUDPReceiver(QObject *parent) : QObject(parent), socket(new QUdpSocket(this)), isOutputColorCQSpotEnabled(false) { FCT_IDENTIFICATION; reloadSetting(); connect(socket, &QUdpSocket::readyRead, this, &WsjtxUDPReceiver::readPendingDatagrams); connect(&wsjtSQLRecord, &UpdatableSQLRecord::recordReady, this, &WsjtxUDPReceiver::contactReady); } void WsjtxUDPReceiver::openPort() { FCT_IDENTIFICATION; if ( ! socket ) { return; } if( socket->state() == QAbstractSocket::BoundState) { socket->close(); } int newPort = getConfigPort(); qCDebug(runtime) << "Listen port"<< newPort; bool multicastEnabled = getConfigMulticastJoin(); qCDebug(runtime) << (( multicastEnabled ) ? "Multicast" : "Unicast") << "enabled"; if ( multicastEnabled ) { if ( ! socket->bind(QHostAddress::AnyIPv4, newPort, QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint) ) { qWarning() << "Cannot bind the Port for WSJTX"; } else { QHostAddress multicastAddress = QHostAddress(getConfigMulticastAddress()); const QList listNetworkIF = QNetworkInterface::allInterfaces(); /* Join Multicast Group on all Multicast-capable interfaces */ for ( const auto &networkIF : listNetworkIF ) { auto flags = QNetworkInterface::IsUp | QNetworkInterface::CanMulticast; if ( networkIF.isValid() && (networkIF.flags() & flags) ) { if ( ! socket->joinMulticastGroup(multicastAddress, networkIF) ) { qWarning() << "Cannot join the Multicast address" << networkIF.humanReadableName() << "; Address" << multicastAddress;; } else { qCDebug(runtime) << "Joined interface: " << networkIF.humanReadableName() << "; Address" << multicastAddress; } } } socket->setSocketOption(QAbstractSocket::MulticastTtlOption, getConfigMulticastTTL()); } } else { if ( ! socket->bind(QHostAddress::Any, newPort) ) { qWarning() << "Cannot bind the Port for WSJTX"; } else { qCDebug(runtime) << "Listening on all interfaces"; } } } void WsjtxUDPReceiver::forwardDatagram(const QNetworkDatagram &datagram) { FCT_IDENTIFICATION; HostsPortString forwardAddresses(getConfigForwardAddresses()); const QList &addrList = forwardAddresses.getAddrList(); for ( const HostPortAddress &addr : addrList ) { QUdpSocket udpSocket; qCDebug(runtime) << "Sending to " << addr; udpSocket.writeDatagram(datagram.data(), addr, addr.getPort()); } } float WsjtxUDPReceiver::modePeriodLength(const QString &mode) { FCT_IDENTIFICATION; float ret = 60; qCDebug(function_parameters) << mode; if ( mode == "FST4" || mode == "FT8" || mode == "MSK144" ) { ret = 15; } else if ( mode == "FT4" ) { ret = 7.5; } else if ( mode == "FT2" ) { ret = 3.8; } else if ( mode == "JT4" || mode == "JT9" || mode.contains("JT65") || mode == "QRA64" || mode == "ISCAT" ) { ret = 60; } else if ( mode == "FST4W" || mode == "WSPR" ) { ret = 120; } qCDebug(runtime) << "Period: " << ret; return ret; } quint16 WsjtxUDPReceiver::getConfigPort() { FCT_IDENTIFICATION; return LogParam::getNetworkWsjtxListenerPort(WsjtxUDPReceiver::DEFAULT_PORT); } void WsjtxUDPReceiver::saveConfigPort(quint16 port) { FCT_IDENTIFICATION; LogParam::setNetworkNotifRigStateAddrs(port); } QString WsjtxUDPReceiver::getConfigForwardAddresses() { FCT_IDENTIFICATION; return LogParam::getNetworkWsjtxForwardAddrs(); } void WsjtxUDPReceiver::saveConfigForwardAddresses(const QString &addresses) { FCT_IDENTIFICATION; LogParam::setNetworkWsjtxForwardAddrs(addresses); } void WsjtxUDPReceiver::saveConfigMulticastJoin(bool state) { FCT_IDENTIFICATION; LogParam::setNetworkWsjtxListenerJoinMulticast(state); } bool WsjtxUDPReceiver::getConfigMulticastJoin() { FCT_IDENTIFICATION; return LogParam::getNetworkWsjtxListenerJoinMulticast(); } void WsjtxUDPReceiver::saveConfigMulticastAddress(const QString &addr) { FCT_IDENTIFICATION; LogParam::setNetworkWsjtxListenerMulticastAddr(addr); } QString WsjtxUDPReceiver::getConfigMulticastAddress() { FCT_IDENTIFICATION; return LogParam::getNetworkWsjtxListenerMulticastAddr(); } void WsjtxUDPReceiver::saveConfigMulticastTTL(int ttl) { FCT_IDENTIFICATION; LogParam::setNetworkWsjtxListenerMulticastTTL(ttl); } int WsjtxUDPReceiver::getConfigMulticastTTL() { FCT_IDENTIFICATION; return LogParam::getNetworkWsjtxListenerMulticastTTL(); } bool WsjtxUDPReceiver::getConfigOutputColorCQSpot() { return LogParam::getWsjtxOutputColorCQSpot(); } void WsjtxUDPReceiver::saveConfigOutputColorCQSpot(bool status) { LogParam::setWsjtxOutputColorCQSpot(status); } void WsjtxUDPReceiver::readPendingDatagrams() { FCT_IDENTIFICATION; while (socket->hasPendingDatagrams()) { QNetworkDatagram datagram = socket->receiveDatagram(); /* remember WSJT receiving address becuase WSJT does not listen multicast address * but only UDP address. Therefore the command must be sent via UDP unicast */ wsjtxAddress = datagram.senderAddress(); wsjtxPort = datagram.senderPort(); qCDebug(runtime) << "Received from" << wsjtxAddress; QDataStream stream(datagram.data()); quint32 magic, schema, mtype; stream >> magic; stream >> schema; stream >> mtype; if (magic != 0xadbccbda) { qCDebug(runtime) << "Invalid wsjtx magic"; continue; } qCDebug(runtime) << "WSJT mtype << "<< mtype << " schema " << schema; forwardDatagram(datagram); switch (mtype) { /* WSJTX Status message */ case 1: { QByteArray id, mode, tx_mode, sub_mode, report, dx_call, dx_grid, de_call, de_grid, conf_name, tx_message; WsjtxStatus status; stream >> id >> status.dial_freq >> mode >> dx_call >> report >> tx_mode; stream >> status.tx_enabled >> status.transmitting >> status.decoding; stream >> status.rx_df >> status.tx_df >> de_call >> de_grid >> dx_grid; stream >> status.tx_watchdog >> sub_mode >> status.fast_mode >> status.special_op_mode >> status.freq_tolerance; stream >> status.tr_period >> conf_name >> tx_message; status.id = QString(id); status.mode = QString(mode); status.tx_mode = QString(mode); status.sub_mode = QString(sub_mode); status.report = QString(report); status.dx_call = QString(dx_call); status.dx_grid = QString(dx_grid); status.de_call = QString(de_call); status.de_grid = QString(de_grid); status.conf_name = QString(conf_name); status.tx_message = QString(tx_message); qCDebug(runtime)<> id >> decode.is_new >> decode.time >> decode.snr >> decode.dt >> decode.df; stream >> mode >> message >> decode.low_confidence >> decode.off_air; decode.id = QString(id); decode.mode = QString(mode); decode.message = QString(message); #if 0 if ( isJTDXId(decode.id) ) { /* It's a workaround for JTDX only. * JTDX sends the time without a time zone. Which is * interpreted by QLog as time in the local zone and * it is therefore recalculated, incorrectly, to UTC. * Therefore it is needed to add timezone to date information * received from JTDX */ // it is not needed to convert it here? } #endif qCDebug(runtime) << decode; emit decodeReceived(decode); break; } /* WSJTX Log message */ case 5: { QByteArray id, dx_call, dx_grid, mode, rprt_sent, rprt_rcvd, tx_pwr, comments; QByteArray name, op_call, my_call, my_grid, exch_sent, exch_rcvd, prop_mode; WsjtxLog log; stream >> id >> log.time_off >> dx_call >> dx_grid >> log.tx_freq >> mode >> rprt_sent; stream >> rprt_rcvd >> tx_pwr >> comments >> name >> log.time_on >> op_call; stream >> my_call >> my_grid >> exch_sent >> exch_rcvd >> prop_mode; log.id = QString(id); log.dx_call = QString(dx_call).toUpper(); log.dx_grid = QString(dx_grid).toUpper(); log.mode = QString(mode); log.rprt_sent = QString(rprt_sent); log.rprt_rcvd = QString(rprt_rcvd); log.tx_pwr = QString(tx_pwr); log.comments = QString(comments); log.name = QString(name); log.op_call = QString(op_call).toUpper(); log.my_call = QString(my_call).toUpper(); log.my_grid = QString(my_grid).toUpper(); log.exch_sent = QString(exch_sent); log.exch_rcvd = QString(exch_rcvd); log.prop_mode = QString(prop_mode); if ( isJTDXId(log.id) ) { /* It's a workaround for JTDX only. * JTDX sends the time without a time zone. Which is * interpreted by QLog as time in the local zone and * it is therefore recalculated, incorrectly, to UTC. * Therefore it is needed to add timezone to date information * received from JTDX */ qCDebug(runtime) << "JTDX detected - adding Timezone information"; log.time_on.setTimeZone(QTimeZone::utc()); log.time_off.setTimeZone(QTimeZone::utc()); } qCDebug(runtime) << log; insertContact(log); break; } /* WSJTX LogADIF message */ case 12: { QByteArray id, adif_text; WsjtxLogADIF log; const QString data = datagram.data(); if ( isCSNSat(data) ) { id = "CSN Sat"; int index = data.indexOf("> id >> adif_text; log.id = QString(id); log.log_adif = QString(adif_text); insertContact(log); break; } } } } void WsjtxUDPReceiver::insertContact(WsjtxLog log) { FCT_IDENTIFICATION; qCDebug(function_parameters) << log; QSqlTableModel model; model.setTable("contacts"); model.removeColumn(model.fieldIndex("id")); QSqlRecord record = model.record(0); double freq = Hz2MHz(static_cast(log.tx_freq)); record.setValue("freq", freq); record.setValue("band", BandPlan::freq2Band(freq).name); /* if field is empty then do not initialize it, leave it NULL * for database */ if ( !log.dx_call.isEmpty() ) { record.setValue("callsign", log.dx_call); } if ( !log.rprt_rcvd.isEmpty() ) { record.setValue("rst_rcvd", log.rprt_rcvd); } if ( !log.rprt_sent.isEmpty() ) { record.setValue("rst_sent", log.rprt_sent); } if ( !log.name.isEmpty() ) { record.setValue("name", Data::removeAccents(log.name)); record.setValue("name_intl", log.name); } if ( !log.dx_grid.isEmpty() ) { record.setValue("gridsquare", log.dx_grid); } if ( !log.mode.isEmpty() ) { QString mode = log.mode.toUpper(); QString submode; QPair legacy = Data::instance()->legacyMode(mode); if ( !legacy.first.isEmpty() ) { mode = legacy.first; submode = legacy.second; } record.setValue("mode", mode); record.setValue("submode", submode); } if ( log.time_on.isValid() ) { record.setValue("start_time", log.time_on); } if ( log.time_off.isValid() ) { record.setValue("end_time", log.time_off); } if ( !log.comments.isEmpty() ) { record.setValue("comment", Data::removeAccents(log.comments)); record.setValue("comment_intl", log.comments); } if ( !log.exch_sent.isEmpty() ) { record.setValue("stx_string", log.exch_sent); } if ( !log.exch_rcvd.isEmpty() ) { record.setValue("srx_string", log.exch_rcvd); } if ( !log.prop_mode.isEmpty() ) { record.setValue("prop_mode", log.prop_mode); } if ( !log.tx_pwr.isEmpty() ) { record.setValue("tx_pwr", log.tx_pwr); } if ( !log.op_call.isEmpty() ) { record.setValue("operator", Data::removeAccents(log.op_call)); } if ( !log.my_grid.isEmpty() ) { record.setValue("my_gridsquare", log.my_grid); } if ( !log.my_call.isEmpty() ) { record.setValue("station_callsign", log.my_call); } // The QSO record can be received in two formats from WSJTX (raw and ADIF). // Therefore, it is necessary to save the first record and possibly update it // with the second record and then emit the result. // For this we create an updatable SQLRecord wsjtSQLRecord.updateRecord(record); //emit addContact(record); } void WsjtxUDPReceiver::contactReady(QSqlRecord record) { FCT_IDENTIFICATION; emit addContact(record); } void WsjtxUDPReceiver::insertContact(WsjtxLogADIF log) { FCT_IDENTIFICATION; qCDebug(function_parameters) << log; QSqlTableModel model; model.setTable("contacts"); model.removeColumn(model.fieldIndex("id")); QSqlRecord record = model.record(0); QTextStream in(&log.log_adif); AdiFormat adif(in); adif.importNext(record); // the values ​​listed below have default values ​​defined in ADIF. // These are set to N. However, WSJTX and other apps do not send // these fields, which means that all records would be set to N - do not send. // It is unacceptable. So this piece of code deletes these defaults so that // in NewContact these values ​​are set from the values ​​in the GUI. // There is a risk that some clone will start sending these values ​​as well. // In this case, it will have to be handled differently. Currently it is OK record.remove(record.indexOf("qsl_sent")); record.remove(record.indexOf("lotw_qsl_sent")); record.remove(record.indexOf("eqsl_qsl_sent")); // The QSO record can be received in two formats from WSJTX (raw and ADIF). // Therefore, it is necessary to save the first record and possibly update it // with the second record and then emit the result. // For this we create an updatable SQLRecord wsjtSQLRecord.updateRecord(record); //emit addContact(record); } void WsjtxUDPReceiver::sendReply(const WsjtxEntry &entry) { FCT_IDENTIFICATION; const WsjtxDecode &decode = entry.decode; qCDebug(function_parameters) << decode; if (!socket) return; /* sending to WSJT to UDP address, not multicast address because * WSJTX does not listen multicast address */ qCDebug(runtime) << "Sending to" << wsjtxAddress; QByteArray data; QDataStream stream(&data, QIODevice::ReadWrite); stream.setVersion(QDataStream::Qt_5_4); // UDP_DEFAULT_SCHEMA_VERSION 3 stream << UDP_MAGIC_NUMBER; stream << UDP_DEFAULT_SCHEMA_VERSION; /* * from WSJTX: Network/NetworkMessage.hpp * Reply In 4 quint32 * Id (target unique key) utf8 * Time QTime * snr qint32 * Delta time (S) float (serialized as double) * Delta frequency (Hz) quint32 * Mode utf8 * Message utf8 * Low confidence bool * Modifiers quint8 * * In order for a server to provide a useful cooperative service * to WSJT-X it is possible for it to initiate a QSO by sending * this message to a client. WSJT-X filters this message and only * acts upon it if the message exactly describes a prior decode * and that decode is a CQ or QRZ message. The action taken is * exactly equivalent to the user double clicking the message in * the "Band activity" window. The intent of this message is for * servers to be able to provide an advanced look up of potential * QSO partners, for example determining if they have been worked * before or if working them may advance some objective like * award progress. The intention is not to provide a secondary * user interface for WSJT-X, it is expected that after QSO * initiation the rest of the QSO is carried out manually using * the normal WSJT-X user interface. * * The Modifiers field allows the equivalent of keyboard * modifiers to be sent "as if" those modifier keys where pressed * while double-clicking the specified decoded message. The * modifier values (hexadecimal) are as follows: * * no modifier 0x00 * SHIFT 0x02 * CTRL 0x04 CMD on Mac * ALT 0x08 * META 0x10 Windows key on MS Windows * KEYPAD 0x20 Keypad or arrows * Group switch 0x40 X11 only */ stream << UDP_COMMANDS::REPLY_CMD; stream << decode.id.toUtf8(); stream << decode.time; stream << decode.snr; stream << decode.dt; stream << decode.df; stream << decode.mode.toUtf8(); stream << decode.message.toUtf8(); stream << decode.low_confidence; stream << quint8(0); socket->writeDatagram(data, wsjtxAddress, wsjtxPort); } void WsjtxUDPReceiver::sendHighlightCallsign(const WsjtxEntry &entry) { FCT_IDENTIFICATION; // QColor() means that WSJTX clears the color sendHighlightCallsignColor(entry, Qt::black, Data::statusToColor(entry.status, false, QColor())); } void WsjtxUDPReceiver::sendClearHighlightCallsign(const WsjtxEntry &entry) { FCT_IDENTIFICATION; // QColor() means that WSJTX clears the color sendHighlightCallsignColor(entry, QColor(), QColor()); } void WsjtxUDPReceiver::sendClearAllHighlightCallsign() { FCT_IDENTIFICATION; WsjtxEntry tmp; tmp.callsign = "CLEARALL!"; sendHighlightCallsignColor(tmp, QColor(), QColor(), false); } void WsjtxUDPReceiver::sendHighlightCallsignColor(const WsjtxEntry &entry, const QColor &fgColor, const QColor &bgColor, bool highlightLast) { FCT_IDENTIFICATION; if ( !socket ) return; if ( !isOutputColorCQSpotEnabled ) { qCDebug(runtime) << "HighlightCallsign is disabled"; return; } const WsjtxDecode &decode = entry.decode; qCDebug(function_parameters) << decode << fgColor << bgColor << highlightLast; /* sending to WSJT to UDP address, not multicast address because * WSJTX does not listen multicast address */ qCDebug(runtime) << "Sending to" << wsjtxAddress; QByteArray data; QDataStream out(&data, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_4); // UDP_DEFAULT_SCHEMA_VERSION 3 out << UDP_MAGIC_NUMBER; out << UDP_DEFAULT_SCHEMA_VERSION; /* * from WSJTX: Network/NetworkMessage.hpp * Highlight Callsign In 13 quint32 * Id (unique key) utf8 * Callsign utf8 * Background Color QColor * Foreground Color QColor * Highlight last bool * * The server may send this message at any time. The message * specifies the background and foreground color that will be * used to highlight the specified callsign in the decoded * messages printed in the Band Activity panel. The WSJT-X * clients maintain a list of such instructions and apply them to * all decoded messages in the band activity window. To clear * and cancel highlighting send an invalid QColor value for * either or both of the background and foreground fields. When * using this mode the total number of callsign highlighting * requests should be limited otherwise the performance of WSJT-X * decoding may be impacted. A rough rule of thumb might be too * limit the number of active highlighting requests to no more * than 100. * * Using a callsign of "CLEARALL!" and anything for the * color values will clear the internal highlighting data. It will * NOT remove the highlighting on the screen, however. The exclamation * symbol is used to avoid accidental clearing of all highlighting * data via a decoded callsign, since an exclamation symbol is not * a valid character in a callsign. * * The "Highlight last" field allows the sender to request that * all instances of "Callsign" in the last period only, instead * of all instances in all periods, be highlighted. */ out << UDP_COMMANDS::HIGHLIGHT_CALLSIGN_CMD; out << decode.id.toUtf8(); out << entry.callsign.toUtf8(); out << bgColor; // Background Color out << fgColor; // Foreground Color out << true; // Highlight last socket->writeDatagram(data, wsjtxAddress, wsjtxPort); } void WsjtxUDPReceiver::reloadSetting() { FCT_IDENTIFICATION; openPort(); isOutputColorCQSpotEnabled = getConfigOutputColorCQSpot(); } foldynl-QLog-3252ff9/core/WsjtxUDPReceiver.h000066400000000000000000000054211517334601000206430ustar00rootroot00000000000000#ifndef QLOG_CORE_WSJTXUDPRECEIVER_H #define QLOG_CORE_WSJTXUDPRECEIVER_H #include #include #include #include #include #include "data/UpdatableSQLRecord.h" #include "data/WsjtxStatus.h" #include "data/WsjtxDecode.h" #include "data/WsjtxLog.h" #include "data/WsjtxLogADIF.h" #include "data/WsjtxEntry.h" class Data; class QUdpSocket; class WsjtxUDPReceiver : public QObject { Q_OBJECT public: explicit WsjtxUDPReceiver(QObject *parent = nullptr); static float modePeriodLength(const QString &); static quint16 getConfigPort(); static void saveConfigPort(quint16); static QString getConfigForwardAddresses(); static void saveConfigForwardAddresses(const QString &); static void saveConfigMulticastJoin(bool); static bool getConfigMulticastJoin(); static void saveConfigMulticastAddress(const QString &); static QString getConfigMulticastAddress(); static void saveConfigMulticastTTL(int); static int getConfigMulticastTTL(); static bool getConfigOutputColorCQSpot(); static void saveConfigOutputColorCQSpot(bool); // identification of different variants of the WSJTX protocol based on packet ID static bool isJTDXId(const QString &id) { return id.contains("JTDX"); } static bool isWriteLogId(const QString &id) { return id.contains("WRITELOG"); } static bool isCSNSat(const QString &data) { return data.contains("CSN Sat"); } signals: void statusReceived(WsjtxStatus); void decodeReceived(WsjtxDecode); void addContact(QSqlRecord); public slots: void sendReply(const WsjtxEntry&); void sendHighlightCallsign(const WsjtxEntry&); void sendClearHighlightCallsign(const WsjtxEntry&); void sendClearAllHighlightCallsign(); void reloadSetting(); private slots: void readPendingDatagrams(); void insertContact(WsjtxLog log); void contactReady(QSqlRecord record); void insertContact(WsjtxLogADIF log); private: QUdpSocket* socket; QHostAddress wsjtxAddress; quint16 wsjtxPort; bool isOutputColorCQSpotEnabled; UpdatableSQLRecord wsjtSQLRecord; static const int DEFAULT_PORT = 2237; const quint32 UDP_MAGIC_NUMBER = 0xadbccbda; const quint32 UDP_DEFAULT_SCHEMA_VERSION = 3; enum UDP_COMMANDS { REPLY_CMD = quint32(4), HIGHLIGHT_CALLSIGN_CMD = quint32(13), }; void openPort(); void forwardDatagram(const QNetworkDatagram &); void sendHighlightCallsignColor(const WsjtxEntry &entry, const QColor &fgColor, const QColor &bgColor, bool highlightLast = true); }; #endif // QLOG_CORE_WSJTXUDPRECEIVER_H foldynl-QLog-3252ff9/core/csv.hpp000066400000000000000000012365541517334601000166370ustar00rootroot00000000000000#pragma once /* CSV for C++, version 3.4.0 https://github.com/vincentlaucsb/csv-parser MIT License Copyright (c) 2017-2026 Vincent La 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 CSV_HPP #define CSV_HPP #include #include #include #include #include #include #include #include #include #include /** @file * @brief Defines functionality needed for basic CSV parsing */ #include #include #include #include #include #include #include #include #include #if !defined(CSV_ENABLE_THREADS) || CSV_ENABLE_THREADS #include #include #endif /** @file * @brief Contains the main CSV parsing algorithm and various utility functions */ #include #include #include #include #include #include #include #if !defined(__EMSCRIPTEN__) /* Copyright 2017 https://github.com/mandreyel * * 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. */ /* csv-parser local note: * * This vendored mio.hpp includes a minimal Windows-specific narrowing fix in * int64_high/int64_low to avoid -Wconversion failures under strict MinGW builds. * Keep this patch small and easy to rebase if/when upstream is updated. * * - Vincent La 3/31/2026 */ #ifndef MIO_MMAP_HEADER #define MIO_MMAP_HEADER // #include "mio/page.hpp" /* Copyright 2017 https://github.com/mandreyel * * 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 MIO_PAGE_HEADER #define MIO_PAGE_HEADER #ifdef _WIN32 # include #else # include #endif namespace mio { /** * This is used by `basic_mmap` to determine whether to create a read-only or * a read-write memory mapping. */ enum class access_mode { read, write }; /** * Determines the operating system's page allocation granularity. * * On the first call to this function, it invokes the operating system specific syscall * to determine the page size, caches the value, and returns it. Any subsequent call to * this function serves the cached value, so no further syscalls are made. */ inline size_t page_size() { static const size_t page_size = [] { #ifdef _WIN32 SYSTEM_INFO SystemInfo; GetSystemInfo(&SystemInfo); return SystemInfo.dwAllocationGranularity; #else return sysconf(_SC_PAGE_SIZE); #endif }(); return page_size; } /** * Alligns `offset` to the operating's system page size such that it subtracts the * difference until the nearest page boundary before `offset`, or does nothing if * `offset` is already page aligned. */ inline size_t make_offset_page_aligned(size_t offset) noexcept { const size_t page_size_ = page_size(); // Use integer division to round down to the nearest page alignment. return offset / page_size_ * page_size_; } } // namespace mio #endif // MIO_PAGE_HEADER #include #include #include #include #ifdef _WIN32 # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif // WIN32_LEAN_AND_MEAN # include #else // ifdef _WIN32 # define INVALID_HANDLE_VALUE -1 #endif // ifdef _WIN32 namespace mio { // This value may be provided as the `length` parameter to the constructor or // `map`, in which case a memory mapping of the entire file is created. enum { map_entire_file = 0 }; #ifdef _WIN32 using file_handle_type = HANDLE; #else using file_handle_type = int; #endif // This value represents an invalid file handle type. This can be used to // determine whether `basic_mmap::file_handle` is valid, for example. const static file_handle_type invalid_handle = INVALID_HANDLE_VALUE; template struct basic_mmap { using value_type = ByteT; using size_type = size_t; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; using const_pointer = const value_type*; using difference_type = std::ptrdiff_t; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using iterator_category = std::random_access_iterator_tag; using handle_type = file_handle_type; static_assert(sizeof(ByteT) == sizeof(char), "ByteT must be the same size as char."); private: // Points to the first requested byte, and not to the actual start of the mapping. pointer data_ = nullptr; // Length--in bytes--requested by user (which may not be the length of the // full mapping) and the length of the full mapping. size_type length_ = 0; size_type mapped_length_ = 0; // Letting user map a file using both an existing file handle and a path // introcudes some complexity (see `is_handle_internal_`). // On POSIX, we only need a file handle to create a mapping, while on // Windows systems the file handle is necessary to retrieve a file mapping // handle, but any subsequent operations on the mapped region must be done // through the latter. handle_type file_handle_ = INVALID_HANDLE_VALUE; #ifdef _WIN32 handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE; #endif // Letting user map a file using both an existing file handle and a path // introcudes some complexity in that we must not close the file handle if // user provided it, but we must close it if we obtained it using the // provided path. For this reason, this flag is used to determine when to // close `file_handle_`. bool is_handle_internal_; public: /** * The default constructed mmap object is in a non-mapped state, that is, * any operation that attempts to access nonexistent underlying data will * result in undefined behaviour/segmentation faults. */ basic_mmap() = default; #ifdef __cpp_exceptions /** * The same as invoking the `map` function, except any error that may occur * while establishing the mapping is wrapped in a `std::system_error` and is * thrown. */ template basic_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) { std::error_code error; map(path, offset, length, error); if(error) { throw std::system_error(error); } } /** * The same as invoking the `map` function, except any error that may occur * while establishing the mapping is wrapped in a `std::system_error` and is * thrown. */ basic_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) { std::error_code error; map(handle, offset, length, error); if(error) { throw std::system_error(error); } } #endif // __cpp_exceptions /** * `basic_mmap` has single-ownership semantics, so transferring ownership * may only be accomplished by moving the object. */ basic_mmap(const basic_mmap&) = delete; basic_mmap(basic_mmap&&); basic_mmap& operator=(const basic_mmap&) = delete; basic_mmap& operator=(basic_mmap&&); /** * If this is a read-write mapping, the destructor invokes sync. Regardless * of the access mode, unmap is invoked as a final step. */ ~basic_mmap(); /** * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, * however, a mapped region of a file gets its own handle, which is returned by * 'mapping_handle'. */ handle_type file_handle() const noexcept { return file_handle_; } handle_type mapping_handle() const noexcept; /** Returns whether a valid memory mapping has been created. */ bool is_open() const noexcept { return file_handle_ != invalid_handle; } /** * Returns true if no mapping was established, that is, conceptually the * same as though the length that was mapped was 0. This function is * provided so that this class has Container semantics. */ bool empty() const noexcept { return length() == 0; } /** Returns true if a mapping was established. */ bool is_mapped() const noexcept; /** * `size` and `length` both return the logical length, i.e. the number of bytes * user requested to be mapped, while `mapped_length` returns the actual number of * bytes that were mapped which is a multiple of the underlying operating system's * page allocation granularity. */ size_type size() const noexcept { return length(); } size_type length() const noexcept { return length_; } size_type mapped_length() const noexcept { return mapped_length_; } /** Returns the offset relative to the start of the mapping. */ size_type mapping_offset() const noexcept { return mapped_length_ - length_; } /** * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping * exists. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > pointer data() noexcept { return data_; } const_pointer data() const noexcept { return data_; } /** * Returns an iterator to the first requested byte, if a valid memory mapping * exists, otherwise this function call is undefined behaviour. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > iterator begin() noexcept { return data(); } const_iterator begin() const noexcept { return data(); } const_iterator cbegin() const noexcept { return data(); } /** * Returns an iterator one past the last requested byte, if a valid memory mapping * exists, otherwise this function call is undefined behaviour. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > iterator end() noexcept { return data() + length(); } const_iterator end() const noexcept { return data() + length(); } const_iterator cend() const noexcept { return data() + length(); } /** * Returns a reverse iterator to the last memory mapped byte, if a valid * memory mapping exists, otherwise this function call is undefined * behaviour. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } /** * Returns a reverse iterator past the first mapped byte, if a valid memory * mapping exists, otherwise this function call is undefined behaviour. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > reverse_iterator rend() noexcept { return reverse_iterator(begin()); } const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } /** * Returns a reference to the `i`th byte from the first requested byte (as returned * by `data`). If this is invoked when no valid memory mapping has been created * prior to this call, undefined behaviour ensues. */ reference operator[](const size_type i) noexcept { return data_[i]; } const_reference operator[](const size_type i) const noexcept { return data_[i]; } /** * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the * reason is reported via `error` and the object remains in a state as if this * function hadn't been called. * * `path`, which must be a path to an existing file, is used to retrieve a file * handle (which is closed when the object destructs or `unmap` is called), which is * then used to memory map the requested region. Upon failure, `error` is set to * indicate the reason and the object remains in an unmapped state. * * `offset` is the number of bytes, relative to the start of the file, where the * mapping should begin. When specifying it, there is no need to worry about * providing a value that is aligned with the operating system's page allocation * granularity. This is adjusted by the implementation such that the first requested * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at * `offset` from the start of the file. * * `length` is the number of bytes to map. It may be `map_entire_file`, in which * case a mapping of the entire file is created. */ template void map(const String& path, const size_type offset, const size_type length, std::error_code& error); /** * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the * reason is reported via `error` and the object remains in a state as if this * function hadn't been called. * * `path`, which must be a path to an existing file, is used to retrieve a file * handle (which is closed when the object destructs or `unmap` is called), which is * then used to memory map the requested region. Upon failure, `error` is set to * indicate the reason and the object remains in an unmapped state. * * The entire file is mapped. */ template void map(const String& path, std::error_code& error) { map(path, 0, map_entire_file, error); } /** * Establishes a memory mapping with AccessMode. If the mapping is * unsuccesful, the reason is reported via `error` and the object remains in * a state as if this function hadn't been called. * * `handle`, which must be a valid file handle, which is used to memory map the * requested region. Upon failure, `error` is set to indicate the reason and the * object remains in an unmapped state. * * `offset` is the number of bytes, relative to the start of the file, where the * mapping should begin. When specifying it, there is no need to worry about * providing a value that is aligned with the operating system's page allocation * granularity. This is adjusted by the implementation such that the first requested * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at * `offset` from the start of the file. * * `length` is the number of bytes to map. It may be `map_entire_file`, in which * case a mapping of the entire file is created. */ void map(const handle_type handle, const size_type offset, const size_type length, std::error_code& error); /** * Establishes a memory mapping with AccessMode. If the mapping is * unsuccesful, the reason is reported via `error` and the object remains in * a state as if this function hadn't been called. * * `handle`, which must be a valid file handle, which is used to memory map the * requested region. Upon failure, `error` is set to indicate the reason and the * object remains in an unmapped state. * * The entire file is mapped. */ void map(const handle_type handle, std::error_code& error) { map(handle, 0, map_entire_file, error); } /** * If a valid memory mapping has been created prior to this call, this call * instructs the kernel to unmap the memory region and disassociate this object * from the file. * * The file handle associated with the file that is mapped is only closed if the * mapping was created using a file path. If, on the other hand, an existing * file handle was used to create the mapping, the file handle is not closed. */ void unmap(); void swap(basic_mmap& other); /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ template typename std::enable_if::type sync(std::error_code& error); /** * All operators compare the address of the first byte and size of the two mapped * regions. */ private: template< access_mode A = AccessMode, typename = typename std::enable_if::type > pointer get_mapping_start() noexcept { return !data() ? nullptr : data() - mapping_offset(); } const_pointer get_mapping_start() const noexcept { return !data() ? nullptr : data() - mapping_offset(); } /** * The destructor syncs changes to disk if `AccessMode` is `write`, but not * if it's `read`, but since the destructor cannot be templated, we need to * do SFINAE in a dedicated function, where one syncs and the other is a noop. */ template typename std::enable_if::type conditional_sync(); template typename std::enable_if::type conditional_sync(); }; template bool operator==(const basic_mmap& a, const basic_mmap& b); template bool operator!=(const basic_mmap& a, const basic_mmap& b); template bool operator<(const basic_mmap& a, const basic_mmap& b); template bool operator<=(const basic_mmap& a, const basic_mmap& b); template bool operator>(const basic_mmap& a, const basic_mmap& b); template bool operator>=(const basic_mmap& a, const basic_mmap& b); /** * This is the basis for all read-only mmap objects and should be preferred over * directly using `basic_mmap`. */ template using basic_mmap_source = basic_mmap; /** * This is the basis for all read-write mmap objects and should be preferred over * directly using `basic_mmap`. */ template using basic_mmap_sink = basic_mmap; /** * These aliases cover the most common use cases, both representing a raw byte stream * (either with a char or an unsigned char/uint8_t). */ using mmap_source = basic_mmap_source; using ummap_source = basic_mmap_source; using mmap_sink = basic_mmap_sink; using ummap_sink = basic_mmap_sink; /** * Convenience factory method that constructs a mapping for any `basic_mmap` or * `basic_mmap` type. */ template< typename MMap, typename MappingToken > MMap make_mmap(const MappingToken& token, int64_t offset, int64_t length, std::error_code& error) { MMap mmap; mmap.map(token, offset, length, error); return mmap; } /** * Convenience factory method. * * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, * `std::filesystem::path`, `std::vector`, or similar), or a * `mmap_source::handle_type`. */ template mmap_source make_mmap_source(const MappingToken& token, mmap_source::size_type offset, mmap_source::size_type length, std::error_code& error) { return make_mmap(token, offset, length, error); } template mmap_source make_mmap_source(const MappingToken& token, std::error_code& error) { return make_mmap_source(token, 0, map_entire_file, error); } /** * Convenience factory method. * * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, * `std::filesystem::path`, `std::vector`, or similar), or a * `mmap_sink::handle_type`. */ template mmap_sink make_mmap_sink(const MappingToken& token, mmap_sink::size_type offset, mmap_sink::size_type length, std::error_code& error) { return make_mmap(token, offset, length, error); } template mmap_sink make_mmap_sink(const MappingToken& token, std::error_code& error) { return make_mmap_sink(token, 0, map_entire_file, error); } } // namespace mio // #include "detail/mmap.ipp" /* Copyright 2017 https://github.com/mandreyel * * 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 MIO_BASIC_MMAP_IMPL #define MIO_BASIC_MMAP_IMPL // #include "mio/mmap.hpp" // #include "mio/page.hpp" // #include "mio/detail/string_util.hpp" /* Copyright 2017 https://github.com/mandreyel * * 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 MIO_STRING_UTIL_HEADER #define MIO_STRING_UTIL_HEADER #include namespace mio { namespace detail { template< typename S, typename C = typename std::decay::type, typename = decltype(std::declval().data()), typename = typename std::enable_if< std::is_same::value #ifdef _WIN32 || std::is_same::value #endif >::type > struct char_type_helper { using type = typename C::value_type; }; template struct char_type { using type = typename char_type_helper::type; }; // TODO: can we avoid this brute force approach? template<> struct char_type { using type = char; }; template<> struct char_type { using type = char; }; template struct char_type { using type = char; }; template struct char_type { using type = char; }; #ifdef _WIN32 template<> struct char_type { using type = wchar_t; }; template<> struct char_type { using type = wchar_t; }; template struct char_type { using type = wchar_t; }; template struct char_type { using type = wchar_t; }; #endif // _WIN32 template struct is_c_str_helper { static constexpr bool value = std::is_same< CharT*, // TODO: I'm so sorry for this... Can this be made cleaner? typename std::add_pointer< typename std::remove_cv< typename std::remove_pointer< typename std::decay< S >::type >::type >::type >::type >::value; }; template struct is_c_str { static constexpr bool value = is_c_str_helper::value; }; #ifdef _WIN32 template struct is_c_wstr { static constexpr bool value = is_c_str_helper::value; }; #endif // _WIN32 template struct is_c_str_or_c_wstr { static constexpr bool value = is_c_str::value #ifdef _WIN32 || is_c_wstr::value #endif ; }; template< typename String, typename = decltype(std::declval().data()), typename = typename std::enable_if::value>::type > const typename char_type::type* c_str(const String& path) { return path.data(); } template< typename String, typename = decltype(std::declval().empty()), typename = typename std::enable_if::value>::type > bool empty(const String& path) { return path.empty(); } template< typename String, typename = typename std::enable_if::value>::type > const typename char_type::type* c_str(String path) { return path; } template< typename String, typename = typename std::enable_if::value>::type > bool empty(String path) { return !path || (*path == 0); } } // namespace detail } // namespace mio #endif // MIO_STRING_UTIL_HEADER #include #ifndef _WIN32 # include # include # include # include #endif namespace mio { namespace detail { #ifdef _WIN32 namespace win { /** Returns the 4 upper bytes of an 8-byte integer. */ inline DWORD int64_high(int64_t n) noexcept { return static_cast(static_cast(n) >> 32); } /** Returns the 4 lower bytes of an 8-byte integer. */ inline DWORD int64_low(int64_t n) noexcept { return static_cast(static_cast(n) & 0xffffffffULL); } template< typename String, typename = typename std::enable_if< std::is_same::type, char>::value >::type > file_handle_type open_file_helper(const String& path, const access_mode mode) { return ::CreateFileA(c_str(path), mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); } template typename std::enable_if< std::is_same::type, wchar_t>::value, file_handle_type >::type open_file_helper(const String& path, const access_mode mode) { return ::CreateFileW(c_str(path), mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); } } // win #endif // _WIN32 /** * Returns the last platform specific system error (errno on POSIX and * GetLastError on Win) as a `std::error_code`. */ inline std::error_code last_error() noexcept { std::error_code error; #ifdef _WIN32 error.assign(GetLastError(), std::system_category()); #else error.assign(errno, std::system_category()); #endif return error; } template file_handle_type open_file(const String& path, const access_mode mode, std::error_code& error) { error.clear(); if(detail::empty(path)) { error = std::make_error_code(std::errc::invalid_argument); return invalid_handle; } #ifdef _WIN32 const auto handle = win::open_file_helper(path, mode); #else // POSIX const auto handle = ::open(c_str(path), mode == access_mode::read ? O_RDONLY : O_RDWR); #endif if(handle == invalid_handle) { error = detail::last_error(); } return handle; } inline size_t query_file_size(file_handle_type handle, std::error_code& error) { error.clear(); #ifdef _WIN32 LARGE_INTEGER file_size; if(::GetFileSizeEx(handle, &file_size) == 0) { error = detail::last_error(); return 0; } return static_cast(file_size.QuadPart); #else // POSIX struct stat sbuf; if(::fstat(handle, &sbuf) == -1) { error = detail::last_error(); return 0; } return sbuf.st_size; #endif } struct mmap_context { char* data; int64_t length; int64_t mapped_length; #ifdef _WIN32 file_handle_type file_mapping_handle; #endif }; inline mmap_context memory_map(const file_handle_type file_handle, const int64_t offset, const int64_t length, const access_mode mode, std::error_code& error) { const int64_t aligned_offset = make_offset_page_aligned(offset); const int64_t length_to_map = offset - aligned_offset + length; #ifdef _WIN32 const int64_t max_file_size = offset + length; const auto file_mapping_handle = ::CreateFileMapping( file_handle, 0, mode == access_mode::read ? PAGE_READONLY : PAGE_READWRITE, win::int64_high(max_file_size), win::int64_low(max_file_size), 0); if(file_mapping_handle == invalid_handle) { error = detail::last_error(); return {}; } char* mapping_start = static_cast(::MapViewOfFile( file_mapping_handle, mode == access_mode::read ? FILE_MAP_READ : FILE_MAP_WRITE, win::int64_high(aligned_offset), win::int64_low(aligned_offset), length_to_map)); if(mapping_start == nullptr) { // Close file handle if mapping it failed. ::CloseHandle(file_mapping_handle); error = detail::last_error(); return {}; } #else // POSIX char* mapping_start = static_cast(::mmap( 0, // Don't give hint as to where to map. length_to_map, mode == access_mode::read ? PROT_READ : PROT_WRITE, MAP_SHARED, file_handle, aligned_offset)); if(mapping_start == MAP_FAILED) { error = detail::last_error(); return {}; } #endif mmap_context ctx; ctx.data = mapping_start + offset - aligned_offset; ctx.length = length; ctx.mapped_length = length_to_map; #ifdef _WIN32 ctx.file_mapping_handle = file_mapping_handle; #endif return ctx; } } // namespace detail // -- basic_mmap -- template basic_mmap::~basic_mmap() { conditional_sync(); unmap(); } template basic_mmap::basic_mmap(basic_mmap&& other) : data_(std::move(other.data_)) , length_(std::move(other.length_)) , mapped_length_(std::move(other.mapped_length_)) , file_handle_(std::move(other.file_handle_)) #ifdef _WIN32 , file_mapping_handle_(std::move(other.file_mapping_handle_)) #endif , is_handle_internal_(std::move(other.is_handle_internal_)) { other.data_ = nullptr; other.length_ = other.mapped_length_ = 0; other.file_handle_ = invalid_handle; #ifdef _WIN32 other.file_mapping_handle_ = invalid_handle; #endif } template basic_mmap& basic_mmap::operator=(basic_mmap&& other) { if(this != &other) { // First the existing mapping needs to be removed. unmap(); data_ = std::move(other.data_); length_ = std::move(other.length_); mapped_length_ = std::move(other.mapped_length_); file_handle_ = std::move(other.file_handle_); #ifdef _WIN32 file_mapping_handle_ = std::move(other.file_mapping_handle_); #endif is_handle_internal_ = std::move(other.is_handle_internal_); // The moved from basic_mmap's fields need to be reset, because // otherwise other's destructor will unmap the same mapping that was // just moved into this. other.data_ = nullptr; other.length_ = other.mapped_length_ = 0; other.file_handle_ = invalid_handle; #ifdef _WIN32 other.file_mapping_handle_ = invalid_handle; #endif other.is_handle_internal_ = false; } return *this; } template typename basic_mmap::handle_type basic_mmap::mapping_handle() const noexcept { #ifdef _WIN32 return file_mapping_handle_; #else return file_handle_; #endif } template template void basic_mmap::map(const String& path, const size_type offset, const size_type length, std::error_code& error) { error.clear(); if(detail::empty(path)) { error = std::make_error_code(std::errc::invalid_argument); return; } const auto handle = detail::open_file(path, AccessMode, error); if(error) { return; } map(handle, offset, length, error); // This MUST be after the call to map, as that sets this to true. if(!error) { is_handle_internal_ = true; } } template void basic_mmap::map(const handle_type handle, const size_type offset, const size_type length, std::error_code& error) { error.clear(); if(handle == invalid_handle) { error = std::make_error_code(std::errc::bad_file_descriptor); return; } const auto file_size = detail::query_file_size(handle, error); if(error) { return; } if(offset + length > file_size) { error = std::make_error_code(std::errc::invalid_argument); return; } const auto ctx = detail::memory_map(handle, offset, length == map_entire_file ? (file_size - offset) : length, AccessMode, error); if(!error) { // We must unmap the previous mapping that may have existed prior to this call. // Note that this must only be invoked after a new mapping has been created in // order to provide the strong guarantee that, should the new mapping fail, the // `map` function leaves this instance in a state as though the function had // never been invoked. unmap(); file_handle_ = handle; is_handle_internal_ = false; data_ = reinterpret_cast(ctx.data); length_ = ctx.length; mapped_length_ = ctx.mapped_length; #ifdef _WIN32 file_mapping_handle_ = ctx.file_mapping_handle; #endif } } template template typename std::enable_if::type basic_mmap::sync(std::error_code& error) { error.clear(); if(!is_open()) { error = std::make_error_code(std::errc::bad_file_descriptor); return; } if(data()) { #ifdef _WIN32 if(::FlushViewOfFile(get_mapping_start(), mapped_length_) == 0 || ::FlushFileBuffers(file_handle_) == 0) #else // POSIX if(::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0) #endif { error = detail::last_error(); return; } } #ifdef _WIN32 if(::FlushFileBuffers(file_handle_) == 0) { error = detail::last_error(); } #endif } template void basic_mmap::unmap() { if(!is_open()) { return; } // TODO do we care about errors here? #ifdef _WIN32 if(is_mapped()) { ::UnmapViewOfFile(get_mapping_start()); ::CloseHandle(file_mapping_handle_); } #else // POSIX if(data_) { ::munmap(const_cast(get_mapping_start()), mapped_length_); } #endif // If `file_handle_` was obtained by our opening it (when map is called with // a path, rather than an existing file handle), we need to close it, // otherwise it must not be closed as it may still be used outside this // instance. if(is_handle_internal_) { #ifdef _WIN32 ::CloseHandle(file_handle_); #else // POSIX ::close(file_handle_); #endif } // Reset fields to their default values. data_ = nullptr; length_ = mapped_length_ = 0; file_handle_ = invalid_handle; #ifdef _WIN32 file_mapping_handle_ = invalid_handle; #endif } template bool basic_mmap::is_mapped() const noexcept { #ifdef _WIN32 return file_mapping_handle_ != invalid_handle; #else // POSIX return is_open(); #endif } template void basic_mmap::swap(basic_mmap& other) { if(this != &other) { using std::swap; swap(data_, other.data_); swap(file_handle_, other.file_handle_); #ifdef _WIN32 swap(file_mapping_handle_, other.file_mapping_handle_); #endif swap(length_, other.length_); swap(mapped_length_, other.mapped_length_); swap(is_handle_internal_, other.is_handle_internal_); } } template template typename std::enable_if::type basic_mmap::conditional_sync() { // This is invoked from the destructor, so not much we can do about // failures here. std::error_code ec; sync(ec); } template template typename std::enable_if::type basic_mmap::conditional_sync() { // noop } template bool operator==(const basic_mmap& a, const basic_mmap& b) { return a.data() == b.data() && a.size() == b.size(); } template bool operator!=(const basic_mmap& a, const basic_mmap& b) { return !(a == b); } template bool operator<(const basic_mmap& a, const basic_mmap& b) { if(a.data() == b.data()) { return a.size() < b.size(); } return a.data() < b.data(); } template bool operator<=(const basic_mmap& a, const basic_mmap& b) { return !(a > b); } template bool operator>(const basic_mmap& a, const basic_mmap& b) { if(a.data() == b.data()) { return a.size() > b.size(); } return a.data() > b.data(); } template bool operator>=(const basic_mmap& a, const basic_mmap& b) { return !(a < b); } } // namespace mio #endif // MIO_BASIC_MMAP_IMPL #endif // MIO_MMAP_HEADER /* Copyright 2017 https://github.com/mandreyel * * 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 MIO_PAGE_HEADER #define MIO_PAGE_HEADER #ifdef _WIN32 # include #else # include #endif namespace mio { /** * This is used by `basic_mmap` to determine whether to create a read-only or * a read-write memory mapping. */ enum class access_mode { read, write }; /** * Determines the operating system's page allocation granularity. * * On the first call to this function, it invokes the operating system specific syscall * to determine the page size, caches the value, and returns it. Any subsequent call to * this function serves the cached value, so no further syscalls are made. */ inline size_t page_size() { static const size_t page_size = [] { #ifdef _WIN32 SYSTEM_INFO SystemInfo; GetSystemInfo(&SystemInfo); return SystemInfo.dwAllocationGranularity; #else return sysconf(_SC_PAGE_SIZE); #endif }(); return page_size; } /** * Alligns `offset` to the operating's system page size such that it subtracts the * difference until the nearest page boundary before `offset`, or does nothing if * `offset` is already page aligned. */ inline size_t make_offset_page_aligned(size_t offset) noexcept { const size_t page_size_ = page_size(); // Use integer division to round down to the nearest page alignment. return offset / page_size_ * page_size_; } } // namespace mio #endif // MIO_PAGE_HEADER /* Copyright 2017 https://github.com/mandreyel * * 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 MIO_SHARED_MMAP_HEADER #define MIO_SHARED_MMAP_HEADER // #include "mio/mmap.hpp" #include // std::error_code #include // std::shared_ptr namespace mio { /** * Exposes (nearly) the same interface as `basic_mmap`, but endowes it with * `std::shared_ptr` semantics. * * This is not the default behaviour of `basic_mmap` to avoid allocating on the heap if * shared semantics are not required. */ template< access_mode AccessMode, typename ByteT > class basic_shared_mmap { using impl_type = basic_mmap; std::shared_ptr pimpl_; public: using value_type = typename impl_type::value_type; using size_type = typename impl_type::size_type; using reference = typename impl_type::reference; using const_reference = typename impl_type::const_reference; using pointer = typename impl_type::pointer; using const_pointer = typename impl_type::const_pointer; using difference_type = typename impl_type::difference_type; using iterator = typename impl_type::iterator; using const_iterator = typename impl_type::const_iterator; using reverse_iterator = typename impl_type::reverse_iterator; using const_reverse_iterator = typename impl_type::const_reverse_iterator; using iterator_category = typename impl_type::iterator_category; using handle_type = typename impl_type::handle_type; using mmap_type = impl_type; basic_shared_mmap() = default; basic_shared_mmap(const basic_shared_mmap&) = default; basic_shared_mmap& operator=(const basic_shared_mmap&) = default; basic_shared_mmap(basic_shared_mmap&&) = default; basic_shared_mmap& operator=(basic_shared_mmap&&) = default; /** Takes ownership of an existing mmap object. */ basic_shared_mmap(mmap_type&& mmap) : pimpl_(std::make_shared(std::move(mmap))) {} /** Takes ownership of an existing mmap object. */ basic_shared_mmap& operator=(mmap_type&& mmap) { pimpl_ = std::make_shared(std::move(mmap)); return *this; } /** Initializes this object with an already established shared mmap. */ basic_shared_mmap(std::shared_ptr mmap) : pimpl_(std::move(mmap)) {} /** Initializes this object with an already established shared mmap. */ basic_shared_mmap& operator=(std::shared_ptr mmap) { pimpl_ = std::move(mmap); return *this; } #ifdef __cpp_exceptions /** * The same as invoking the `map` function, except any error that may occur * while establishing the mapping is wrapped in a `std::system_error` and is * thrown. */ template basic_shared_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) { std::error_code error; map(path, offset, length, error); if(error) { throw std::system_error(error); } } /** * The same as invoking the `map` function, except any error that may occur * while establishing the mapping is wrapped in a `std::system_error` and is * thrown. */ basic_shared_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) { std::error_code error; map(handle, offset, length, error); if(error) { throw std::system_error(error); } } #endif // __cpp_exceptions /** * If this is a read-write mapping and the last reference to the mapping, * the destructor invokes sync. Regardless of the access mode, unmap is * invoked as a final step. */ ~basic_shared_mmap() = default; /** Returns the underlying `std::shared_ptr` instance that holds the mmap. */ std::shared_ptr get_shared_ptr() { return pimpl_; } /** * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, * however, a mapped region of a file gets its own handle, which is returned by * 'mapping_handle'. */ handle_type file_handle() const noexcept { return pimpl_ ? pimpl_->file_handle() : invalid_handle; } handle_type mapping_handle() const noexcept { return pimpl_ ? pimpl_->mapping_handle() : invalid_handle; } /** Returns whether a valid memory mapping has been created. */ bool is_open() const noexcept { return pimpl_ && pimpl_->is_open(); } /** * Returns true if no mapping was established, that is, conceptually the * same as though the length that was mapped was 0. This function is * provided so that this class has Container semantics. */ bool empty() const noexcept { return !pimpl_ || pimpl_->empty(); } /** * `size` and `length` both return the logical length, i.e. the number of bytes * user requested to be mapped, while `mapped_length` returns the actual number of * bytes that were mapped which is a multiple of the underlying operating system's * page allocation granularity. */ size_type size() const noexcept { return pimpl_ ? pimpl_->length() : 0; } size_type length() const noexcept { return pimpl_ ? pimpl_->length() : 0; } size_type mapped_length() const noexcept { return pimpl_ ? pimpl_->mapped_length() : 0; } /** * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping * exists. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > pointer data() noexcept { return pimpl_->data(); } const_pointer data() const noexcept { return pimpl_ ? pimpl_->data() : nullptr; } /** * Returns an iterator to the first requested byte, if a valid memory mapping * exists, otherwise this function call is undefined behaviour. */ iterator begin() noexcept { return pimpl_->begin(); } const_iterator begin() const noexcept { return pimpl_->begin(); } const_iterator cbegin() const noexcept { return pimpl_->cbegin(); } /** * Returns an iterator one past the last requested byte, if a valid memory mapping * exists, otherwise this function call is undefined behaviour. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > iterator end() noexcept { return pimpl_->end(); } const_iterator end() const noexcept { return pimpl_->end(); } const_iterator cend() const noexcept { return pimpl_->cend(); } /** * Returns a reverse iterator to the last memory mapped byte, if a valid * memory mapping exists, otherwise this function call is undefined * behaviour. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > reverse_iterator rbegin() noexcept { return pimpl_->rbegin(); } const_reverse_iterator rbegin() const noexcept { return pimpl_->rbegin(); } const_reverse_iterator crbegin() const noexcept { return pimpl_->crbegin(); } /** * Returns a reverse iterator past the first mapped byte, if a valid memory * mapping exists, otherwise this function call is undefined behaviour. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > reverse_iterator rend() noexcept { return pimpl_->rend(); } const_reverse_iterator rend() const noexcept { return pimpl_->rend(); } const_reverse_iterator crend() const noexcept { return pimpl_->crend(); } /** * Returns a reference to the `i`th byte from the first requested byte (as returned * by `data`). If this is invoked when no valid memory mapping has been created * prior to this call, undefined behaviour ensues. */ reference operator[](const size_type i) noexcept { return (*pimpl_)[i]; } const_reference operator[](const size_type i) const noexcept { return (*pimpl_)[i]; } /** * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the * reason is reported via `error` and the object remains in a state as if this * function hadn't been called. * * `path`, which must be a path to an existing file, is used to retrieve a file * handle (which is closed when the object destructs or `unmap` is called), which is * then used to memory map the requested region. Upon failure, `error` is set to * indicate the reason and the object remains in an unmapped state. * * `offset` is the number of bytes, relative to the start of the file, where the * mapping should begin. When specifying it, there is no need to worry about * providing a value that is aligned with the operating system's page allocation * granularity. This is adjusted by the implementation such that the first requested * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at * `offset` from the start of the file. * * `length` is the number of bytes to map. It may be `map_entire_file`, in which * case a mapping of the entire file is created. */ template void map(const String& path, const size_type offset, const size_type length, std::error_code& error) { map_impl(path, offset, length, error); } /** * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the * reason is reported via `error` and the object remains in a state as if this * function hadn't been called. * * `path`, which must be a path to an existing file, is used to retrieve a file * handle (which is closed when the object destructs or `unmap` is called), which is * then used to memory map the requested region. Upon failure, `error` is set to * indicate the reason and the object remains in an unmapped state. * * The entire file is mapped. */ template void map(const String& path, std::error_code& error) { map_impl(path, 0, map_entire_file, error); } /** * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the * reason is reported via `error` and the object remains in a state as if this * function hadn't been called. * * `handle`, which must be a valid file handle, which is used to memory map the * requested region. Upon failure, `error` is set to indicate the reason and the * object remains in an unmapped state. * * `offset` is the number of bytes, relative to the start of the file, where the * mapping should begin. When specifying it, there is no need to worry about * providing a value that is aligned with the operating system's page allocation * granularity. This is adjusted by the implementation such that the first requested * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at * `offset` from the start of the file. * * `length` is the number of bytes to map. It may be `map_entire_file`, in which * case a mapping of the entire file is created. */ void map(const handle_type handle, const size_type offset, const size_type length, std::error_code& error) { map_impl(handle, offset, length, error); } /** * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the * reason is reported via `error` and the object remains in a state as if this * function hadn't been called. * * `handle`, which must be a valid file handle, which is used to memory map the * requested region. Upon failure, `error` is set to indicate the reason and the * object remains in an unmapped state. * * The entire file is mapped. */ void map(const handle_type handle, std::error_code& error) { map_impl(handle, 0, map_entire_file, error); } /** * If a valid memory mapping has been created prior to this call, this call * instructs the kernel to unmap the memory region and disassociate this object * from the file. * * The file handle associated with the file that is mapped is only closed if the * mapping was created using a file path. If, on the other hand, an existing * file handle was used to create the mapping, the file handle is not closed. */ void unmap() { if(pimpl_) pimpl_->unmap(); } void swap(basic_shared_mmap& other) { pimpl_.swap(other.pimpl_); } /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ template< access_mode A = AccessMode, typename = typename std::enable_if::type > void sync(std::error_code& error) { if(pimpl_) pimpl_->sync(error); } /** All operators compare the underlying `basic_mmap`'s addresses. */ friend bool operator==(const basic_shared_mmap& a, const basic_shared_mmap& b) { return a.pimpl_ == b.pimpl_; } friend bool operator!=(const basic_shared_mmap& a, const basic_shared_mmap& b) { return !(a == b); } friend bool operator<(const basic_shared_mmap& a, const basic_shared_mmap& b) { return a.pimpl_ < b.pimpl_; } friend bool operator<=(const basic_shared_mmap& a, const basic_shared_mmap& b) { return a.pimpl_ <= b.pimpl_; } friend bool operator>(const basic_shared_mmap& a, const basic_shared_mmap& b) { return a.pimpl_ > b.pimpl_; } friend bool operator>=(const basic_shared_mmap& a, const basic_shared_mmap& b) { return a.pimpl_ >= b.pimpl_; } private: template void map_impl(const MappingToken& token, const size_type offset, const size_type length, std::error_code& error) { if(!pimpl_) { mmap_type mmap = make_mmap(token, offset, length, error); if(error) { return; } pimpl_ = std::make_shared(std::move(mmap)); } else { pimpl_->map(token, offset, length, error); } } }; /** * This is the basis for all read-only mmap objects and should be preferred over * directly using basic_shared_mmap. */ template using basic_shared_mmap_source = basic_shared_mmap; /** * This is the basis for all read-write mmap objects and should be preferred over * directly using basic_shared_mmap. */ template using basic_shared_mmap_sink = basic_shared_mmap; /** * These aliases cover the most common use cases, both representing a raw byte stream * (either with a char or an unsigned char/uint8_t). */ using shared_mmap_source = basic_shared_mmap_source; using shared_ummap_source = basic_shared_mmap_source; using shared_mmap_sink = basic_shared_mmap_sink; using shared_ummap_sink = basic_shared_mmap_sink; } // namespace mio #endif // MIO_SHARED_MMAP_HEADER #endif /** @file * @brief SIMD-accelerated skip for runs of non-special CSV bytes. * * Conservative design: any byte that could be the delimiter, quote character, * \n, or \r causes an early return. * * Uses 4x cmpeq rather than a lookup-table shuffle because CSV has only four * sentinel characters. vpshufb (shuffle) truncates index bytes to their low * nibble, causing aliasing across 16-byte boundaries and silently skipping * real delimiters. The cmpeq approach is alias-free and equally fast for * small sentinel sets. * * UTF-8 safe: all CSV structural bytes are single-byte ASCII; multi-byte * sequences (values > 0x7F) are never misidentified as special. */ /** @file * A standalone header file containing shared code */ #include #include #include #include #include #if defined(_WIN32) # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # undef max # undef min #elif defined(__linux__) # include #endif /** Helper macro which should be #defined as "inline" * in the single header version */ #define CSV_INLINE inline #include #if defined(__EMSCRIPTEN__) #undef CSV_ENABLE_THREADS #define CSV_ENABLE_THREADS 0 #elif !defined(CSV_ENABLE_THREADS) #define CSV_ENABLE_THREADS 1 #endif // Minimal portability macros (Hedley subset) with CSV_ prefix. #if defined(__clang__) || defined(__GNUC__) #define CSV_CONST __attribute__((__const__)) #define CSV_PURE __attribute__((__pure__)) #if defined(_WIN32) #define CSV_PRIVATE #else #define CSV_PRIVATE __attribute__((__visibility__("hidden"))) #endif #define CSV_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) #elif defined(_MSC_VER) #define CSV_CONST #define CSV_PURE #define CSV_PRIVATE #define CSV_NON_NULL(...) #else #define CSV_CONST #define CSV_PURE #define CSV_PRIVATE #define CSV_NON_NULL(...) #endif // This library uses C++ exceptions for error reporting in public APIs. #if defined(__cpp_exceptions) || defined(_CPPUNWIND) || defined(__EXCEPTIONS) #define CSV_EXCEPTIONS_ENABLED 1 #else #define CSV_EXCEPTIONS_ENABLED 0 #endif #if !CSV_EXCEPTIONS_ENABLED #error "csv-parser requires C++ exceptions. Enable exception handling (for example, remove -fno-exceptions or use /EHsc)." #endif // Detect C++ standard version BEFORE namespace to properly include string_view // MSVC: __cplusplus == 199711L unless /Zc:__cplusplus is set; use _MSVC_LANG instead. #if defined(_MSVC_LANG) && _MSVC_LANG > __cplusplus # define CSV_CPLUSPLUS _MSVC_LANG #else # define CSV_CPLUSPLUS __cplusplus #endif #if CSV_CPLUSPLUS >= 202002L #define CSV_HAS_CXX20 #endif #if CSV_CPLUSPLUS >= 201703L #define CSV_HAS_CXX17 #endif #if CSV_CPLUSPLUS >= 201402L #define CSV_HAS_CXX14 #endif // Include string_view BEFORE csv namespace to avoid namespace pollution issues #ifdef CSV_HAS_CXX17 #include #else // Copyright 2017-2019 by Martin Moene // // string-view lite, a C++17-like string_view for C++98 and later. // For more information see https://github.com/martinmoene/string-view-lite // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef NONSTD_SV_LITE_H_INCLUDED #define NONSTD_SV_LITE_H_INCLUDED #define string_view_lite_MAJOR 1 #define string_view_lite_MINOR 1 #define string_view_lite_PATCH 0 #define string_view_lite_VERSION nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH) #define nssv_STRINGIFY( x ) nssv_STRINGIFY_( x ) #define nssv_STRINGIFY_( x ) #x // string-view lite configuration: #define nssv_STRING_VIEW_DEFAULT 0 #define nssv_STRING_VIEW_NONSTD 1 #define nssv_STRING_VIEW_STD 2 #if !defined( nssv_CONFIG_SELECT_STRING_VIEW ) # define nssv_CONFIG_SELECT_STRING_VIEW ( nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD ) #endif #if defined( nssv_CONFIG_SELECT_STD_STRING_VIEW ) || defined( nssv_CONFIG_SELECT_NONSTD_STRING_VIEW ) # error nssv_CONFIG_SELECT_STD_STRING_VIEW and nssv_CONFIG_SELECT_NONSTD_STRING_VIEW are deprecated and removed, please use nssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_... #endif #ifndef nssv_CONFIG_STD_SV_OPERATOR # define nssv_CONFIG_STD_SV_OPERATOR 0 #endif #ifndef nssv_CONFIG_USR_SV_OPERATOR # define nssv_CONFIG_USR_SV_OPERATOR 1 #endif #ifdef nssv_CONFIG_CONVERSION_STD_STRING # define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS nssv_CONFIG_CONVERSION_STD_STRING # define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS nssv_CONFIG_CONVERSION_STD_STRING #endif #ifndef nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS # define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS 1 #endif #ifndef nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS # define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS 1 #endif // Control presence of exception handling (try and auto discover): #ifndef nssv_CONFIG_NO_EXCEPTIONS # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) # define nssv_CONFIG_NO_EXCEPTIONS 0 # else # define nssv_CONFIG_NO_EXCEPTIONS 1 # endif #endif // C++ language version detection (C++20 is speculative): // Note: VC14.0/1900 (VS2015) lacks too much from C++14. #ifndef nssv_CPLUSPLUS # if defined(_MSVC_LANG ) && !defined(__clang__) # define nssv_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) # else # define nssv_CPLUSPLUS __cplusplus # endif #endif #define nssv_CPP98_OR_GREATER ( nssv_CPLUSPLUS >= 199711L ) #define nssv_CPP11_OR_GREATER ( nssv_CPLUSPLUS >= 201103L ) #define nssv_CPP11_OR_GREATER_ ( nssv_CPLUSPLUS >= 201103L ) #define nssv_CPP14_OR_GREATER ( nssv_CPLUSPLUS >= 201402L ) #define nssv_CPP17_OR_GREATER ( nssv_CPLUSPLUS >= 201703L ) #define nssv_CPP20_OR_GREATER ( nssv_CPLUSPLUS >= 202000L ) // use C++17 std::string_view if available and requested: #if nssv_CPP17_OR_GREATER && defined(__has_include ) # if __has_include( ) # define nssv_HAVE_STD_STRING_VIEW 1 # else # define nssv_HAVE_STD_STRING_VIEW 0 # endif #else # define nssv_HAVE_STD_STRING_VIEW 0 #endif #define nssv_USES_STD_STRING_VIEW ( (nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_STD) || ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_DEFAULT) && nssv_HAVE_STD_STRING_VIEW) ) #define nssv_HAVE_STARTS_WITH ( nssv_CPP20_OR_GREATER || !nssv_USES_STD_STRING_VIEW ) #define nssv_HAVE_ENDS_WITH nssv_HAVE_STARTS_WITH // // Use C++17 std::string_view: // #if nssv_USES_STD_STRING_VIEW #include // Extensions for std::string: #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS namespace nonstd { template< class CharT, class Traits, class Allocator = std::allocator > std::basic_string to_string( std::basic_string_view v, Allocator const & a = Allocator() ) { return std::basic_string( v.begin(), v.end(), a ); } template< class CharT, class Traits, class Allocator > std::basic_string_view to_string_view( std::basic_string const & s ) { return std::basic_string_view( s.data(), s.size() ); } // Literal operators sv and _sv: #if nssv_CONFIG_STD_SV_OPERATOR using namespace std::literals::string_view_literals; #endif #if nssv_CONFIG_USR_SV_OPERATOR inline namespace literals { inline namespace string_view_literals { constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1) { return std::string_view{ str, len }; } constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2) { return std::u16string_view{ str, len }; } constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3) { return std::u32string_view{ str, len }; } constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4) { return std::wstring_view{ str, len }; } }} // namespace literals::string_view_literals #endif // nssv_CONFIG_USR_SV_OPERATOR } // namespace nonstd #endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS namespace nonstd { using std::string_view; using std::wstring_view; using std::u16string_view; using std::u32string_view; using std::basic_string_view; // literal "sv" and "_sv", see above using std::operator==; using std::operator!=; using std::operator<; using std::operator<=; using std::operator>; using std::operator>=; using std::operator<<; } // namespace nonstd #else // nssv_HAVE_STD_STRING_VIEW // // Before C++17: use string_view lite: // // Compiler versions: // // MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0) // MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002) // MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003) // MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) // MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) // MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) // MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) // MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) // MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017) #if defined(_MSC_VER ) && !defined(__clang__) # define nssv_COMPILER_MSVC_VER (_MSC_VER ) # define nssv_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) #else # define nssv_COMPILER_MSVC_VER 0 # define nssv_COMPILER_MSVC_VERSION 0 #endif #define nssv_COMPILER_VERSION( major, minor, patch ) (10 * ( 10 * major + minor) + patch) #if defined(__clang__) # define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) #else # define nssv_COMPILER_CLANG_VERSION 0 #endif #if defined(__GNUC__) && !defined(__clang__) # define nssv_COMPILER_GNUC_VERSION nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #else # define nssv_COMPILER_GNUC_VERSION 0 #endif // half-open range [lo..hi): #define nssv_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) // Presence of language and library features: #ifdef _HAS_CPP0X # define nssv_HAS_CPP0X _HAS_CPP0X #else # define nssv_HAS_CPP0X 0 #endif // Unless defined otherwise below, consider VC14 as C++11 for variant-lite: #if nssv_COMPILER_MSVC_VER >= 1900 # undef nssv_CPP11_OR_GREATER # define nssv_CPP11_OR_GREATER 1 #endif #define nssv_CPP11_90 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1500) #define nssv_CPP11_100 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1600) #define nssv_CPP11_110 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1700) #define nssv_CPP11_120 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1800) #define nssv_CPP11_140 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1900) #define nssv_CPP11_141 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1910) #define nssv_CPP14_000 (nssv_CPP14_OR_GREATER) #define nssv_CPP17_000 (nssv_CPP17_OR_GREATER) // Presence of C++11 language features: #define nssv_HAVE_CONSTEXPR_11 nssv_CPP11_140 #define nssv_HAVE_EXPLICIT_CONVERSION nssv_CPP11_140 #define nssv_HAVE_INLINE_NAMESPACE nssv_CPP11_140 #define nssv_HAVE_NOEXCEPT nssv_CPP11_140 #define nssv_HAVE_NULLPTR nssv_CPP11_100 #define nssv_HAVE_REF_QUALIFIER nssv_CPP11_140 #define nssv_HAVE_UNICODE_LITERALS nssv_CPP11_140 #define nssv_HAVE_USER_DEFINED_LITERALS nssv_CPP11_140 #define nssv_HAVE_WCHAR16_T nssv_CPP11_100 #define nssv_HAVE_WCHAR32_T nssv_CPP11_100 #if ! ( ( nssv_CPP11 && nssv_COMPILER_CLANG_VERSION ) || nssv_BETWEEN( nssv_COMPILER_CLANG_VERSION, 300, 400 ) ) # define nssv_HAVE_STD_DEFINED_LITERALS nssv_CPP11_140 #endif // Presence of C++14 language features: #define nssv_HAVE_CONSTEXPR_14 nssv_CPP14_000 // Presence of C++17 language features: #define nssv_HAVE_NODISCARD nssv_CPP17_000 // Presence of C++ library features: #define nssv_HAVE_STD_HASH nssv_CPP11_120 // C++ feature usage: #if nssv_HAVE_CONSTEXPR_11 # define nssv_constexpr constexpr #else # define nssv_constexpr /*constexpr*/ #endif #if nssv_HAVE_CONSTEXPR_14 # define nssv_constexpr14 constexpr #else # define nssv_constexpr14 /*constexpr*/ #endif #if nssv_HAVE_EXPLICIT_CONVERSION # define nssv_explicit explicit #else # define nssv_explicit /*explicit*/ #endif #if nssv_HAVE_INLINE_NAMESPACE # define nssv_inline_ns inline #else # define nssv_inline_ns /*inline*/ #endif #if nssv_HAVE_NOEXCEPT # define nssv_noexcept noexcept #else # define nssv_noexcept /*noexcept*/ #endif //#if nssv_HAVE_REF_QUALIFIER //# define nssv_ref_qual & //# define nssv_refref_qual && //#else //# define nssv_ref_qual /*&*/ //# define nssv_refref_qual /*&&*/ //#endif #if nssv_HAVE_NULLPTR # define nssv_nullptr nullptr #else # define nssv_nullptr NULL #endif #if nssv_HAVE_NODISCARD # define nssv_nodiscard [[nodiscard]] #else # define nssv_nodiscard /*[[nodiscard]]*/ #endif // Additional includes: #include #include #include #include #include #include // std::char_traits<> #if ! nssv_CONFIG_NO_EXCEPTIONS # include #endif #if nssv_CPP11_OR_GREATER # include #endif // Clang, GNUC, MSVC warning suppression macros: #if defined(__clang__) # pragma clang diagnostic ignored "-Wreserved-user-defined-literal" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wuser-defined-literals" #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wliteral-suffix" #endif // __clang__ #if nssv_COMPILER_MSVC_VERSION >= 140 # define nssv_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] # define nssv_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) ) # define nssv_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) #else # define nssv_SUPPRESS_MSGSL_WARNING(expr) # define nssv_SUPPRESS_MSVC_WARNING(code, descr) # define nssv_DISABLE_MSVC_WARNINGS(codes) #endif #if defined(__clang__) # define nssv_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") #elif defined(__GNUC__) # define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") #elif nssv_COMPILER_MSVC_VERSION >= 140 # define nssv_RESTORE_WARNINGS() __pragma(warning(pop )) #else # define nssv_RESTORE_WARNINGS() #endif // Suppress the following MSVC (GSL) warnings: // - C4455, non-gsl : 'operator ""sv': literal suffix identifiers that do not // start with an underscore are reserved // - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions; // use brace initialization, gsl::narrow_cast or gsl::narow // - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead nssv_DISABLE_MSVC_WARNINGS( 4455 26481 26472 ) //nssv_DISABLE_CLANG_WARNINGS( "-Wuser-defined-literals" ) //nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix ) namespace nonstd { namespace sv_lite { template < class CharT, class Traits = std::char_traits > class basic_string_view; // // basic_string_view: // template < class CharT, class Traits /* = std::char_traits */ > class basic_string_view { public: // Member types: typedef Traits traits_type; typedef CharT value_type; typedef CharT * pointer; typedef CharT const * const_pointer; typedef CharT & reference; typedef CharT const & const_reference; typedef const_pointer iterator; typedef const_pointer const_iterator; typedef std::reverse_iterator< const_iterator > reverse_iterator; typedef std::reverse_iterator< const_iterator > const_reverse_iterator; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; // 24.4.2.1 Construction and assignment: nssv_constexpr basic_string_view() nssv_noexcept : data_( nssv_nullptr ) , size_( 0 ) {} #if nssv_CPP11_OR_GREATER nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept = default; #else nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept : data_( other.data_) , size_( other.size_) {} #endif nssv_constexpr basic_string_view( CharT const * s, size_type count ) : data_( s ) , size_( count ) {} nssv_constexpr basic_string_view( CharT const * s) : data_( s ) , size_( Traits::length(s) ) {} // Assignment: #if nssv_CPP11_OR_GREATER nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept = default; #else nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept { data_ = other.data_; size_ = other.size_; return *this; } #endif // 24.4.2.2 Iterator support: nssv_constexpr const_iterator begin() const nssv_noexcept { return data_; } nssv_constexpr const_iterator end() const nssv_noexcept { return data_ + size_; } nssv_constexpr const_iterator cbegin() const nssv_noexcept { return begin(); } nssv_constexpr const_iterator cend() const nssv_noexcept { return end(); } nssv_constexpr const_reverse_iterator rbegin() const nssv_noexcept { return const_reverse_iterator( end() ); } nssv_constexpr const_reverse_iterator rend() const nssv_noexcept { return const_reverse_iterator( begin() ); } nssv_constexpr const_reverse_iterator crbegin() const nssv_noexcept { return rbegin(); } nssv_constexpr const_reverse_iterator crend() const nssv_noexcept { return rend(); } // 24.4.2.3 Capacity: nssv_constexpr size_type size() const nssv_noexcept { return size_; } nssv_constexpr size_type length() const nssv_noexcept { return size_; } nssv_constexpr size_type max_size() const nssv_noexcept { return (std::numeric_limits< size_type >::max)(); } // since C++20 nssv_nodiscard nssv_constexpr bool empty() const nssv_noexcept { return 0 == size_; } // 24.4.2.4 Element access: nssv_constexpr const_reference operator[]( size_type pos ) const { return data_at( pos ); } nssv_constexpr14 const_reference at( size_type pos ) const { #if nssv_CONFIG_NO_EXCEPTIONS assert( pos < size() ); #else if ( pos >= size() ) { throw std::out_of_range("nonst::string_view::at()"); } #endif return data_at( pos ); } nssv_constexpr const_reference front() const { return data_at( 0 ); } nssv_constexpr const_reference back() const { return data_at( size() - 1 ); } nssv_constexpr const_pointer data() const nssv_noexcept { return data_; } // 24.4.2.5 Modifiers: nssv_constexpr14 void remove_prefix( size_type n ) { assert( n <= size() ); data_ += n; size_ -= n; } nssv_constexpr14 void remove_suffix( size_type n ) { assert( n <= size() ); size_ -= n; } nssv_constexpr14 void swap( basic_string_view & other ) nssv_noexcept { using std::swap; swap( data_, other.data_ ); swap( size_, other.size_ ); } // 24.4.2.6 String operations: size_type copy( CharT * dest, size_type n, size_type pos = 0 ) const { #if nssv_CONFIG_NO_EXCEPTIONS assert( pos <= size() ); #else if ( pos > size() ) { throw std::out_of_range("nonst::string_view::copy()"); } #endif const size_type rlen = (std::min)( n, size() - pos ); (void) Traits::copy( dest, data() + pos, rlen ); return rlen; } nssv_constexpr14 basic_string_view substr( size_type pos = 0, size_type n = npos ) const { #if nssv_CONFIG_NO_EXCEPTIONS assert( pos <= size() ); #else if ( pos > size() ) { throw std::out_of_range("nonst::string_view::substr()"); } #endif return basic_string_view( data() + pos, (std::min)( n, size() - pos ) ); } // compare(), 6x: nssv_constexpr14 int compare( basic_string_view other ) const nssv_noexcept // (1) { if ( const int result = Traits::compare( data(), other.data(), (std::min)( size(), other.size() ) ) ) return result; return size() == other.size() ? 0 : size() < other.size() ? -1 : 1; } nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other ) const // (2) { return substr( pos1, n1 ).compare( other ); } nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other, size_type pos2, size_type n2 ) const // (3) { return substr( pos1, n1 ).compare( other.substr( pos2, n2 ) ); } nssv_constexpr int compare( CharT const * s ) const // (4) { return compare( basic_string_view( s ) ); } nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s ) const // (5) { return substr( pos1, n1 ).compare( basic_string_view( s ) ); } nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s, size_type n2 ) const // (6) { return substr( pos1, n1 ).compare( basic_string_view( s, n2 ) ); } // 24.4.2.7 Searching: // starts_with(), 3x, since C++20: nssv_constexpr bool starts_with( basic_string_view v ) const nssv_noexcept // (1) { return size() >= v.size() && compare( 0, v.size(), v ) == 0; } nssv_constexpr bool starts_with( CharT c ) const nssv_noexcept // (2) { return starts_with( basic_string_view( &c, 1 ) ); } nssv_constexpr bool starts_with( CharT const * s ) const // (3) { return starts_with( basic_string_view( s ) ); } // ends_with(), 3x, since C++20: nssv_constexpr bool ends_with( basic_string_view v ) const nssv_noexcept // (1) { return size() >= v.size() && compare( size() - v.size(), npos, v ) == 0; } nssv_constexpr bool ends_with( CharT c ) const nssv_noexcept // (2) { return ends_with( basic_string_view( &c, 1 ) ); } nssv_constexpr bool ends_with( CharT const * s ) const // (3) { return ends_with( basic_string_view( s ) ); } // find(), 4x: nssv_constexpr14 size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1) { return assert( v.size() == 0 || v.data() != nssv_nullptr ) , pos >= size() ? npos : to_pos( std::search( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) ); } nssv_constexpr14 size_type find( CharT c, size_type pos = 0 ) const nssv_noexcept // (2) { return find( basic_string_view( &c, 1 ), pos ); } nssv_constexpr14 size_type find( CharT const * s, size_type pos, size_type n ) const // (3) { return find( basic_string_view( s, n ), pos ); } nssv_constexpr14 size_type find( CharT const * s, size_type pos = 0 ) const // (4) { return find( basic_string_view( s ), pos ); } // rfind(), 4x: nssv_constexpr14 size_type rfind( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1) { if ( size() < v.size() ) return npos; if ( v.empty() ) return (std::min)( size(), pos ); const_iterator last = cbegin() + (std::min)( size() - v.size(), pos ) + v.size(); const_iterator result = std::find_end( cbegin(), last, v.cbegin(), v.cend(), Traits::eq ); return result != last ? size_type( result - cbegin() ) : npos; } nssv_constexpr14 size_type rfind( CharT c, size_type pos = npos ) const nssv_noexcept // (2) { return rfind( basic_string_view( &c, 1 ), pos ); } nssv_constexpr14 size_type rfind( CharT const * s, size_type pos, size_type n ) const // (3) { return rfind( basic_string_view( s, n ), pos ); } nssv_constexpr14 size_type rfind( CharT const * s, size_type pos = npos ) const // (4) { return rfind( basic_string_view( s ), pos ); } // find_first_of(), 4x: nssv_constexpr size_type find_first_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1) { return pos >= size() ? npos : to_pos( std::find_first_of( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) ); } nssv_constexpr size_type find_first_of( CharT c, size_type pos = 0 ) const nssv_noexcept // (2) { return find_first_of( basic_string_view( &c, 1 ), pos ); } nssv_constexpr size_type find_first_of( CharT const * s, size_type pos, size_type n ) const // (3) { return find_first_of( basic_string_view( s, n ), pos ); } nssv_constexpr size_type find_first_of( CharT const * s, size_type pos = 0 ) const // (4) { return find_first_of( basic_string_view( s ), pos ); } // find_last_of(), 4x: nssv_constexpr size_type find_last_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1) { return empty() ? npos : pos >= size() ? find_last_of( v, size() - 1 ) : to_pos( std::find_first_of( const_reverse_iterator( cbegin() + pos + 1 ), crend(), v.cbegin(), v.cend(), Traits::eq ) ); } nssv_constexpr size_type find_last_of( CharT c, size_type pos = npos ) const nssv_noexcept // (2) { return find_last_of( basic_string_view( &c, 1 ), pos ); } nssv_constexpr size_type find_last_of( CharT const * s, size_type pos, size_type count ) const // (3) { return find_last_of( basic_string_view( s, count ), pos ); } nssv_constexpr size_type find_last_of( CharT const * s, size_type pos = npos ) const // (4) { return find_last_of( basic_string_view( s ), pos ); } // find_first_not_of(), 4x: nssv_constexpr size_type find_first_not_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1) { return pos >= size() ? npos : to_pos( std::find_if( cbegin() + pos, cend(), not_in_view( v ) ) ); } nssv_constexpr size_type find_first_not_of( CharT c, size_type pos = 0 ) const nssv_noexcept // (2) { return find_first_not_of( basic_string_view( &c, 1 ), pos ); } nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos, size_type count ) const // (3) { return find_first_not_of( basic_string_view( s, count ), pos ); } nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos = 0 ) const // (4) { return find_first_not_of( basic_string_view( s ), pos ); } // find_last_not_of(), 4x: nssv_constexpr size_type find_last_not_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1) { return empty() ? npos : pos >= size() ? find_last_not_of( v, size() - 1 ) : to_pos( std::find_if( const_reverse_iterator( cbegin() + pos + 1 ), crend(), not_in_view( v ) ) ); } nssv_constexpr size_type find_last_not_of( CharT c, size_type pos = npos ) const nssv_noexcept // (2) { return find_last_not_of( basic_string_view( &c, 1 ), pos ); } nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos, size_type count ) const // (3) { return find_last_not_of( basic_string_view( s, count ), pos ); } nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos = npos ) const // (4) { return find_last_not_of( basic_string_view( s ), pos ); } // Constants: #if nssv_CPP17_OR_GREATER static nssv_constexpr size_type npos = size_type(-1); #elif nssv_CPP11_OR_GREATER enum : size_type { npos = size_type(-1) }; #else enum { npos = size_type(-1) }; #endif private: struct not_in_view { const basic_string_view v; nssv_constexpr not_in_view( basic_string_view v ) : v( v ) {} nssv_constexpr bool operator()( CharT c ) const { return npos == v.find_first_of( c ); } }; nssv_constexpr size_type to_pos( const_iterator it ) const { return it == cend() ? npos : size_type( it - cbegin() ); } nssv_constexpr size_type to_pos( const_reverse_iterator it ) const { return it == crend() ? npos : size_type( crend() - it - 1 ); } nssv_constexpr const_reference data_at( size_type pos ) const { #if nssv_BETWEEN( nssv_COMPILER_GNUC_VERSION, 1, 500 ) return data_[pos]; #else return assert( pos < size() ), data_[pos]; #endif } private: const_pointer data_; size_type size_; public: #if nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS template< class Allocator > basic_string_view( std::basic_string const & s ) nssv_noexcept : data_( s.data() ) , size_( s.size() ) {} #if nssv_HAVE_EXPLICIT_CONVERSION template< class Allocator > explicit operator std::basic_string() const { return to_string( Allocator() ); } #endif // nssv_HAVE_EXPLICIT_CONVERSION #if nssv_CPP11_OR_GREATER template< class Allocator = std::allocator > std::basic_string to_string( Allocator const & a = Allocator() ) const { return std::basic_string( begin(), end(), a ); } #else std::basic_string to_string() const { return std::basic_string( begin(), end() ); } template< class Allocator > std::basic_string to_string( Allocator const & a ) const { return std::basic_string( begin(), end(), a ); } #endif // nssv_CPP11_OR_GREATER #endif // nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS }; // // Non-member functions: // // 24.4.3 Non-member comparison functions: // lexicographically compare two string views (function template): template< class CharT, class Traits > nssv_constexpr bool operator== ( basic_string_view lhs, basic_string_view rhs ) nssv_noexcept { return lhs.compare( rhs ) == 0 ; } template< class CharT, class Traits > nssv_constexpr bool operator!= ( basic_string_view lhs, basic_string_view rhs ) nssv_noexcept { return lhs.compare( rhs ) != 0 ; } template< class CharT, class Traits > nssv_constexpr bool operator< ( basic_string_view lhs, basic_string_view rhs ) nssv_noexcept { return lhs.compare( rhs ) < 0 ; } template< class CharT, class Traits > nssv_constexpr bool operator<= ( basic_string_view lhs, basic_string_view rhs ) nssv_noexcept { return lhs.compare( rhs ) <= 0 ; } template< class CharT, class Traits > nssv_constexpr bool operator> ( basic_string_view lhs, basic_string_view rhs ) nssv_noexcept { return lhs.compare( rhs ) > 0 ; } template< class CharT, class Traits > nssv_constexpr bool operator>= ( basic_string_view lhs, basic_string_view rhs ) nssv_noexcept { return lhs.compare( rhs ) >= 0 ; } // Let S be basic_string_view, and sv be an instance of S. // Implementations shall provide sufficient additional overloads marked // constexpr and noexcept so that an object t with an implicit conversion // to S can be compared according to Table 67. #if nssv_CPP11_OR_GREATER && ! nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 100, 141 ) #define nssv_BASIC_STRING_VIEW_I(T,U) typename std::decay< basic_string_view >::type #if nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 140, 150 ) # define nssv_MSVC_ORDER(x) , int=x #else # define nssv_MSVC_ORDER(x) /*, int=x*/ #endif // == template< class CharT, class Traits nssv_MSVC_ORDER(1) > nssv_constexpr bool operator==( basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs ) nssv_noexcept { return lhs.compare( rhs ) == 0; } template< class CharT, class Traits nssv_MSVC_ORDER(2) > nssv_constexpr bool operator==( nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs ) nssv_noexcept { return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; } // != template< class CharT, class Traits nssv_MSVC_ORDER(1) > nssv_constexpr bool operator!= ( basic_string_view < CharT, Traits > lhs, nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept { return lhs.size() != rhs.size() || lhs.compare( rhs ) != 0 ; } template< class CharT, class Traits nssv_MSVC_ORDER(2) > nssv_constexpr bool operator!= ( nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, basic_string_view < CharT, Traits > rhs ) nssv_noexcept { return lhs.compare( rhs ) != 0 ; } // < template< class CharT, class Traits nssv_MSVC_ORDER(1) > nssv_constexpr bool operator< ( basic_string_view < CharT, Traits > lhs, nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept { return lhs.compare( rhs ) < 0 ; } template< class CharT, class Traits nssv_MSVC_ORDER(2) > nssv_constexpr bool operator< ( nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, basic_string_view < CharT, Traits > rhs ) nssv_noexcept { return lhs.compare( rhs ) < 0 ; } // <= template< class CharT, class Traits nssv_MSVC_ORDER(1) > nssv_constexpr bool operator<= ( basic_string_view < CharT, Traits > lhs, nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept { return lhs.compare( rhs ) <= 0 ; } template< class CharT, class Traits nssv_MSVC_ORDER(2) > nssv_constexpr bool operator<= ( nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, basic_string_view < CharT, Traits > rhs ) nssv_noexcept { return lhs.compare( rhs ) <= 0 ; } // > template< class CharT, class Traits nssv_MSVC_ORDER(1) > nssv_constexpr bool operator> ( basic_string_view < CharT, Traits > lhs, nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept { return lhs.compare( rhs ) > 0 ; } template< class CharT, class Traits nssv_MSVC_ORDER(2) > nssv_constexpr bool operator> ( nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, basic_string_view < CharT, Traits > rhs ) nssv_noexcept { return lhs.compare( rhs ) > 0 ; } // >= template< class CharT, class Traits nssv_MSVC_ORDER(1) > nssv_constexpr bool operator>= ( basic_string_view < CharT, Traits > lhs, nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept { return lhs.compare( rhs ) >= 0 ; } template< class CharT, class Traits nssv_MSVC_ORDER(2) > nssv_constexpr bool operator>= ( nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, basic_string_view < CharT, Traits > rhs ) nssv_noexcept { return lhs.compare( rhs ) >= 0 ; } #undef nssv_MSVC_ORDER #undef nssv_BASIC_STRING_VIEW_I #endif // nssv_CPP11_OR_GREATER // 24.4.4 Inserters and extractors: namespace detail { template< class Stream > void write_padding( Stream & os, std::streamsize n ) { for ( std::streamsize i = 0; i < n; ++i ) os.rdbuf()->sputc( os.fill() ); } template< class Stream, class View > Stream & write_to_stream( Stream & os, View const & sv ) { typename Stream::sentry sentry( os ); if ( !os ) return os; const std::streamsize length = static_cast( sv.length() ); // Whether, and how, to pad: const bool pad = ( length < os.width() ); const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right; if ( left_pad ) write_padding( os, os.width() - length ); // Write span characters: os.rdbuf()->sputn( sv.begin(), length ); if ( pad && !left_pad ) write_padding( os, os.width() - length ); // Reset output stream width: os.width( 0 ); return os; } } // namespace detail template< class CharT, class Traits > std::basic_ostream & operator<<( std::basic_ostream& os, basic_string_view sv ) { return detail::write_to_stream( os, sv ); } // Several typedefs for common character types are provided: typedef basic_string_view string_view; typedef basic_string_view wstring_view; #if nssv_HAVE_WCHAR16_T typedef basic_string_view u16string_view; typedef basic_string_view u32string_view; #endif }} // namespace nonstd::sv_lite // // 24.4.6 Suffix for basic_string_view literals: // #if nssv_HAVE_USER_DEFINED_LITERALS namespace nonstd { nssv_inline_ns namespace literals { nssv_inline_ns namespace string_view_literals { #if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } #endif // nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS #if nssv_CONFIG_USR_SV_OPERATOR nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } #endif // nssv_CONFIG_USR_SV_OPERATOR }}} // namespace nonstd::literals::string_view_literals #endif // // Extensions for std::string: // #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS namespace nonstd { namespace sv_lite { // Exclude MSVC 14 (19.00): it yields ambiguous to_string(): #if nssv_CPP11_OR_GREATER && nssv_COMPILER_MSVC_VERSION != 140 template< class CharT, class Traits, class Allocator = std::allocator > std::basic_string to_string( basic_string_view v, Allocator const & a = Allocator() ) { return std::basic_string( v.begin(), v.end(), a ); } #else template< class CharT, class Traits > std::basic_string to_string( basic_string_view v ) { return std::basic_string( v.begin(), v.end() ); } template< class CharT, class Traits, class Allocator > std::basic_string to_string( basic_string_view v, Allocator const & a ) { return std::basic_string( v.begin(), v.end(), a ); } #endif // nssv_CPP11_OR_GREATER template< class CharT, class Traits, class Allocator > basic_string_view to_string_view( std::basic_string const & s ) { return basic_string_view( s.data(), s.size() ); } }} // namespace nonstd::sv_lite #endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS // // make types and algorithms available in namespace nonstd: // namespace nonstd { using sv_lite::basic_string_view; using sv_lite::string_view; using sv_lite::wstring_view; #if nssv_HAVE_WCHAR16_T using sv_lite::u16string_view; #endif #if nssv_HAVE_WCHAR32_T using sv_lite::u32string_view; #endif // literal "sv" using sv_lite::operator==; using sv_lite::operator!=; using sv_lite::operator<; using sv_lite::operator<=; using sv_lite::operator>; using sv_lite::operator>=; using sv_lite::operator<<; #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS using sv_lite::to_string; using sv_lite::to_string_view; #endif } // namespace nonstd // 24.4.5 Hash support (C++11): // Note: The hash value of a string view object is equal to the hash value of // the corresponding string object. #if nssv_HAVE_STD_HASH #include namespace std { template<> struct hash< nonstd::string_view > { public: std::size_t operator()( nonstd::string_view v ) const nssv_noexcept { return std::hash()( std::string( v.data(), v.size() ) ); } }; template<> struct hash< nonstd::wstring_view > { public: std::size_t operator()( nonstd::wstring_view v ) const nssv_noexcept { return std::hash()( std::wstring( v.data(), v.size() ) ); } }; template<> struct hash< nonstd::u16string_view > { public: std::size_t operator()( nonstd::u16string_view v ) const nssv_noexcept { return std::hash()( std::u16string( v.data(), v.size() ) ); } }; template<> struct hash< nonstd::u32string_view > { public: std::size_t operator()( nonstd::u32string_view v ) const nssv_noexcept { return std::hash()( std::u32string( v.data(), v.size() ) ); } }; } // namespace std #endif // nssv_HAVE_STD_HASH nssv_RESTORE_WARNINGS() #endif // nssv_HAVE_STD_STRING_VIEW #endif // NONSTD_SV_LITE_H_INCLUDED #endif namespace csv { #ifdef _MSC_VER #pragma region Compatibility Macros #endif /** * @def IF_CONSTEXPR * Expands to `if constexpr` in C++17 and `if` otherwise * * @def CONSTEXPR_VALUE * Expands to `constexpr` in C++17 and `const` otherwise. * Mainly used for global variables. * * @def CONSTEXPR * Expands to `constexpr` in decent compilers and `inline` otherwise. * Intended for functions and methods. */ #define STATIC_ASSERT(x) static_assert(x, "Assertion failed") #ifdef CSV_HAS_CXX17 /** @typedef string_view * The string_view class used by this library. */ using string_view = std::string_view; #else /** @typedef string_view * The string_view class used by this library. */ using string_view = nonstd::string_view; #endif #ifdef CSV_HAS_CXX17 #define IF_CONSTEXPR if constexpr #define CONSTEXPR_VALUE constexpr #define CONSTEXPR_17 constexpr #else #define IF_CONSTEXPR if #define CONSTEXPR_VALUE const #define CONSTEXPR_17 inline #endif #ifdef CSV_HAS_CXX14 template using enable_if_t = std::enable_if_t; #define CONSTEXPR_14 constexpr #define CONSTEXPR_VALUE_14 constexpr #else template using enable_if_t = typename std::enable_if::type; #define CONSTEXPR_14 inline #define CONSTEXPR_VALUE_14 const #endif #ifdef CSV_HAS_CXX17 template using invoke_result_t = typename std::invoke_result::type; #else template using invoke_result_t = typename std::result_of::type; #endif // Resolves g++ bug with regard to constexpr methods. // Keep this gated to C++17+, since C++11/14 pedantic mode rejects constexpr // non-static members when the enclosing class is non-literal. // See: https://stackoverflow.com/questions/36489369/constexpr-non-static-member-function-with-non-constexpr-constructor-gcc-clang-d #if defined(__GNUC__) && !defined(__clang__) #if defined(CSV_HAS_CXX17) && (((__GNUC__ == 7) && (__GNUC_MINOR__ >= 2)) || (__GNUC__ >= 8)) #define CONSTEXPR constexpr #endif #else #ifdef CSV_HAS_CXX17 #define CONSTEXPR constexpr #endif #endif #ifndef CONSTEXPR #define CONSTEXPR inline #endif #ifdef _MSC_VER #pragma endregion #endif namespace internals { // PAGE_SIZE macro could be already defined by the host system. #if defined(PAGE_SIZE) #undef PAGE_SIZE #endif // Get operating system specific details #if defined(_WIN32) inline int getpagesize() { _SYSTEM_INFO sys_info = {}; GetSystemInfo(&sys_info); return std::max(sys_info.dwPageSize, sys_info.dwAllocationGranularity); } const int PAGE_SIZE = getpagesize(); #elif defined(__linux__) const int PAGE_SIZE = getpagesize(); #else /** Size of a memory page in bytes. Used by * csv::internals::CSVFieldArray when allocating blocks. */ const int PAGE_SIZE = 4096; #endif /** Chunk size for lazy-loading large CSV files * * The worker thread reads this many bytes at a time (10MB). * * CRITICAL INVARIANT: Field boundaries at chunk transitions must be preserved. * Bug #280 was caused by fields spanning chunk boundaries being corrupted. * * @note Tests must write >10MB of data to cross chunk boundaries * @see basic_csv_parser.cpp MmapParser::next() for chunk transition logic */ constexpr size_t ITERATION_CHUNK_SIZE = 10000000; // 10MB template inline bool is_equal(T a, T b, T epsilon = 0.001) { /** Returns true if two floating point values are about the same */ static_assert(std::is_floating_point::value, "T must be a floating point type."); return std::abs(a - b) < epsilon; } /** @typedef ParseFlags * An enum used for describing the significance of each character * with respect to CSV parsing * * @see quote_escape_flag */ enum class ParseFlags { QUOTE_ESCAPE_QUOTE = 0, /**< A quote inside or terminating a quote_escaped field */ QUOTE = 2 | 1, /**< Characters which may signify a quote escape */ NOT_SPECIAL = 4, /**< Characters with no special meaning or escaped delimiters and newlines */ DELIMITER = 4 | 2, /**< Characters which signify a new field */ NEWLINE = 4 | 2 | 1 /**< Characters which signify a new row */ }; /** Transform the ParseFlags given the context of whether or not the current * field is quote escaped */ constexpr ParseFlags quote_escape_flag(ParseFlags flag, bool quote_escape) noexcept { return (ParseFlags)((int)flag & ~((int)ParseFlags::QUOTE * quote_escape)); } // Assumed to be true by parsing functions: allows for testing // if an item is DELIMITER or NEWLINE with a >= statement STATIC_ASSERT(ParseFlags::DELIMITER < ParseFlags::NEWLINE); /** Optimizations for reducing branching in parsing loop * * Idea: The meaning of all non-quote characters changes depending * on whether or not the parser is in a quote-escaped mode (0 or 1) */ STATIC_ASSERT(quote_escape_flag(ParseFlags::NOT_SPECIAL, false) == ParseFlags::NOT_SPECIAL); STATIC_ASSERT(quote_escape_flag(ParseFlags::QUOTE, false) == ParseFlags::QUOTE); STATIC_ASSERT(quote_escape_flag(ParseFlags::DELIMITER, false) == ParseFlags::DELIMITER); STATIC_ASSERT(quote_escape_flag(ParseFlags::NEWLINE, false) == ParseFlags::NEWLINE); STATIC_ASSERT(quote_escape_flag(ParseFlags::NOT_SPECIAL, true) == ParseFlags::NOT_SPECIAL); STATIC_ASSERT(quote_escape_flag(ParseFlags::QUOTE, true) == ParseFlags::QUOTE_ESCAPE_QUOTE); STATIC_ASSERT(quote_escape_flag(ParseFlags::DELIMITER, true) == ParseFlags::NOT_SPECIAL); STATIC_ASSERT(quote_escape_flag(ParseFlags::NEWLINE, true) == ParseFlags::NOT_SPECIAL); /** An array which maps ASCII chars to a parsing flag */ using ParseFlagMap = std::array; /** An array which maps ASCII chars to a flag indicating if it is whitespace */ using WhitespaceMap = std::array; } /** Integer indicating a requested column wasn't found. */ constexpr int CSV_NOT_FOUND = -1; /** Offset to convert char into array index. */ constexpr unsigned CHAR_OFFSET = std::numeric_limits::is_signed ? 128 : 0; } #if (defined(__AVX2__) || defined(__SSE2__)) && !defined(CSV_NO_SIMD) #include // _tzcnt_u32 in GCC/Clang headers is __attribute__(__target__("bmi")), which // requires -mbmi at the call site. __builtin_ctz has no such restriction and // emits BSF/TZCNT as the optimizer sees fit. MSVC's _tzcnt_u32 has no // equivalent restriction, so keep it there. # ifdef _MSC_VER # define CSV_TZCNT32(x) _tzcnt_u32(x) # else # define CSV_TZCNT32(x) static_cast(__builtin_ctz(x)) # endif #endif namespace csv { namespace internals { // Precomputed SIMD broadcast vectors for the four CSV sentinel bytes. // Constructed once per parser instance and passed by const-ref into // find_next_non_special, amortizing broadcast cost across every field // scan — meaningful for CSVs with many short fields. // // When no_quote mode is active, set quote_char = delimiter so that // quote bytes are not mistakenly treated as sentinels (they are // NOT_SPECIAL in that mode and must not cause SIMD to stop early). struct SentinelVecs { SentinelVecs() noexcept : SentinelVecs(',', '"') {} SentinelVecs(char delimiter, char quote_char) noexcept { #if defined(__AVX2__) && !defined(CSV_NO_SIMD) v_delim = _mm256_set1_epi8(delimiter); v_quote = _mm256_set1_epi8(quote_char); v_lf = _mm256_set1_epi8('\n'); v_cr = _mm256_set1_epi8('\r'); #elif defined(__SSE2__) && !defined(CSV_NO_SIMD) v_delim = _mm_set1_epi8(delimiter); v_quote = _mm_set1_epi8(quote_char); v_lf = _mm_set1_epi8('\n'); v_cr = _mm_set1_epi8('\r'); #else (void)delimiter; (void)quote_char; #endif } #if defined(__AVX2__) && !defined(CSV_NO_SIMD) __m256i v_delim, v_quote, v_lf, v_cr; #elif defined(__SSE2__) && !defined(CSV_NO_SIMD) __m128i v_delim, v_quote, v_lf, v_cr; #endif }; // Free function — easy to unit test independently of IBasicCSVParser. // // SIMD-only fast-forward: skips pos forward past any bytes that are // definitely not one of the four CSV sentinel characters. Stops as // soon as a sentinel byte is found OR fewer bytes remain than one // SIMD lane. The caller is responsible for the scalar tail loop using // compound_parse_flag, which correctly handles quote_escape state. // // State-agnostic by design: stops conservatively at any sentinel byte // regardless of quote_escape. Inside a quoted field, delimiter and // newline bytes are NOT_SPECIAL under compound_parse_flag, so the // outer DFA loop re-enters parse_field immediately at zero cost. inline size_t find_next_non_special( csv::string_view data, size_t pos, const SentinelVecs& sentinels ) noexcept { #if defined(__AVX2__) && !defined(CSV_NO_SIMD) while (pos + 32 <= data.size()) { __m256i bytes = _mm256_loadu_si256(reinterpret_cast(data.data() + pos)); __m256i special = _mm256_cmpeq_epi8(bytes, sentinels.v_delim); special = _mm256_or_si256(special, _mm256_cmpeq_epi8(bytes, sentinels.v_quote)); special = _mm256_or_si256(special, _mm256_cmpeq_epi8(bytes, sentinels.v_lf)); special = _mm256_or_si256(special, _mm256_cmpeq_epi8(bytes, sentinels.v_cr)); int mask = _mm256_movemask_epi8(special); if (mask != 0) return pos + CSV_TZCNT32(static_cast(mask)); pos += 32; } #elif defined(__SSE2__) && !defined(CSV_NO_SIMD) while (pos + 16 <= data.size()) { __m128i bytes = _mm_loadu_si128(reinterpret_cast(data.data() + pos)); __m128i special = _mm_cmpeq_epi8(bytes, sentinels.v_delim); special = _mm_or_si128(special, _mm_cmpeq_epi8(bytes, sentinels.v_quote)); special = _mm_or_si128(special, _mm_cmpeq_epi8(bytes, sentinels.v_lf)); special = _mm_or_si128(special, _mm_cmpeq_epi8(bytes, sentinels.v_cr)); int mask = _mm_movemask_epi8(special); if (mask != 0) return pos + CSV_TZCNT32(static_cast(mask)); pos += 16; } #else (void)data; (void)sentinels; #endif return pos; } } } #include #include #include #include #include /** @file * Defines an object used to store CSV format settings */ #include #include #include #include namespace csv { namespace internals { class IBasicCSVParser; } class CSVReader; /** Determines how to handle rows that are shorter or longer than the majority */ enum class VariableColumnPolicy { THROW = -1, IGNORE_ROW = 0, KEEP = 1 }; /** Determines how column name lookups are performed */ enum class ColumnNamePolicy { EXACT = 0, /**< Case-sensitive match (default) */ CASE_INSENSITIVE = 1 /**< Case-insensitive match */ }; /** Stores the inferred format of a CSV file. */ struct CSVGuessResult { char delim; int header_row; }; /** Stores information about how to parse a CSV file. * Can be used to construct a csv::CSVReader. */ class CSVFormat { public: /** Settings for parsing a RFC 4180 CSV file */ CSVFormat() = default; /** Sets the delimiter of the CSV file * * @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap */ CSVFormat& delimiter(char delim); /** Sets a list of potential delimiters * * @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap * @param[in] delim An array of possible delimiters to try parsing the CSV with */ CSVFormat& delimiter(const std::vector & delim); /** Sets the whitespace characters to be trimmed * * @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap * @param[in] ws An array of whitespace characters that should be trimmed */ CSVFormat& trim(const std::vector & ws); /** Sets the quote character * * @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap */ CSVFormat& quote(char quote); /** Sets the column names. * * @note Unsets any values set by header_row() */ CSVFormat& column_names(const std::vector& names); /** Sets the header row * * @note Unsets any values set by column_names() */ CSVFormat& header_row(int row); /** Tells the parser that this CSV has no header row * * @note Equivalent to `header_row(-1)` * */ CSVFormat& no_header() { this->header_row(-1); return *this; } /** Turn quoting on or off */ CSVFormat& quote(bool use_quote) { this->no_quote = !use_quote; return *this; } /** Tells the parser how to handle columns of a different length than the others */ CONSTEXPR_14 CSVFormat& variable_columns(VariableColumnPolicy policy = VariableColumnPolicy::IGNORE_ROW) { this->variable_column_policy = policy; return *this; } /** Tells the parser how to handle columns of a different length than the others */ CONSTEXPR_14 CSVFormat& variable_columns(bool policy) { this->variable_column_policy = (VariableColumnPolicy)policy; return *this; } /** Sets the column name lookup policy. * * @param[in] policy Use ColumnNamePolicy::CASE_INSENSITIVE to allow * case-insensitive column lookups via CSVRow::operator[] * and CSVReader::index_of(). */ CONSTEXPR_14 CSVFormat& column_names_policy(ColumnNamePolicy policy) { this->_column_name_policy = policy; return *this; } /** Sets the chunk size used when reading the CSV * * @param[in] size Chunk size in bytes (minimum: 10MB = ITERATION_CHUNK_SIZE) * @throws std::invalid_argument if size < ITERATION_CHUNK_SIZE * * Use this when constructing a CSVReader from a filename and individual rows * may exceed the default 10MB chunk size. The value is passed to CSVReader at * construction time, before any data is read. */ CSVFormat& chunk_size(size_t size); #ifndef DOXYGEN_SHOULD_SKIP_THIS char get_delim() const { // This error should never be received by end users. if (this->possible_delimiters.size() > 1) { throw std::runtime_error("There is more than one possible delimiter."); } return this->possible_delimiters.at(0); } CONSTEXPR bool is_quoting_enabled() const { return !this->no_quote; } CONSTEXPR char get_quote_char() const { return this->quote_char; } CONSTEXPR int get_header() const { return this->header; } std::vector get_possible_delims() const { return this->possible_delimiters; } std::vector get_trim_chars() const { return this->trim_chars; } CONSTEXPR VariableColumnPolicy get_variable_column_policy() const { return this->variable_column_policy; } CONSTEXPR ColumnNamePolicy get_column_name_policy() const { return this->_column_name_policy; } CONSTEXPR size_t get_chunk_size() const { return this->_chunk_size; } #endif /** CSVFormat for guessing the delimiter */ CSV_INLINE static CSVFormat guess_csv() { CSVFormat format; format.delimiter({ ',', '|', '\t', ';', '^' }) .quote('"') .header_row(0); return format; } bool guess_delim() { return this->possible_delimiters.size() > 1; } friend CSVReader; friend internals::IBasicCSVParser; private: /**< Throws an error if delimiters and trim characters overlap */ void assert_no_char_overlap(); /**< Set of possible delimiters */ std::vector possible_delimiters = { ',' }; /**< Set of whitespace characters to trim */ std::vector trim_chars = {}; /**< Row number with columns (ignored if col_names is non-empty) */ int header = 0; /**< Whether or not to use quoting */ bool no_quote = false; /**< Quote character */ char quote_char = '"'; /**< Should be left empty unless file doesn't include header */ std::vector col_names = {}; /**< Allow variable length columns? */ VariableColumnPolicy variable_column_policy = VariableColumnPolicy::IGNORE_ROW; /**< Column name lookup policy */ ColumnNamePolicy _column_name_policy = ColumnNamePolicy::EXACT; /**< Chunk size for reading; passed to CSVReader at construction time */ size_t _chunk_size = internals::ITERATION_CHUNK_SIZE; }; } namespace csv { namespace internals { struct ColNames; using ColNamesPtr = std::shared_ptr; /** @struct ColNames * A data structure for handling column name information. * * These are created by CSVReader and passed (via smart pointer) * to CSVRow objects it creates, thus * allowing for indexing by column name. */ struct ColNames { public: ColNames() = default; ColNames(const std::vector& names) { set_col_names(names); } std::vector get_col_names() const; void set_col_names(const std::vector&); int index_of(csv::string_view) const; /** Sets the column name lookup policy. * Must be called before set_col_names() for CI policy to take effect. */ void set_policy(csv::ColumnNamePolicy policy); bool empty() const noexcept { return this->col_names.empty(); } size_t size() const noexcept; /** Retrieve column name by index. Throws if index is out of bounds. */ const std::string& operator[](size_t i) const; private: std::vector col_names; std::unordered_map col_pos; csv::ColumnNamePolicy _policy = csv::ColumnNamePolicy::EXACT; }; } } /** @file * Defines the data type used for storing information about a CSV row */ #include #include #include // For CSVField #include // For CSVField #if !defined(CSV_ENABLE_THREADS) || CSV_ENABLE_THREADS #include #endif #include #include #include #include #ifdef CSV_HAS_CXX20 #include #endif /** @file * @brief Implements data type parsing functionality */ #include #include #include #include namespace csv { /** Enumerates the different CSV field types that are * recognized by this library * * @note Overflowing integers will be stored and classified as doubles. * @note Unlike previous releases, integer enums here are platform agnostic. */ enum class DataType { UNKNOWN = -1, CSV_NULL, /**< Empty string */ CSV_STRING, /**< Non-numeric string */ CSV_INT8, /**< 8-bit integer */ CSV_INT16, /**< 16-bit integer (short on MSVC/GCC) */ CSV_INT32, /**< 32-bit integer (int on MSVC/GCC) */ CSV_INT64, /**< 64-bit integer (long long on MSVC/GCC) */ CSV_BIGINT, /**< Value too big to fit in a 64-bit in */ CSV_DOUBLE /**< Floating point value */ }; static_assert(DataType::CSV_STRING < DataType::CSV_INT8, "String type should come before numeric types."); static_assert(DataType::CSV_INT8 < DataType::CSV_INT64, "Smaller integer types should come before larger integer types."); static_assert(DataType::CSV_INT64 < DataType::CSV_DOUBLE, "Integer types should come before floating point value types."); namespace internals { /** Compute 10 to the power of n. * Only integral exponents are supported; fractional exponents * are never needed since CSV scientific notation exponents are * always integers (enforced by the CSV_INT8..CSV_INT64 guard * in _process_potential_exponential before calling this). */ template CSV_CONST CONSTEXPR_14 long double pow10(const T& n) noexcept { static_assert(std::is_integral::value, "pow10 only supports integral exponents"); long double multiplicand = n > 0 ? 10 : 0.1, ret = 1; // Make all numbers positive T iterations = n > 0 ? n : -n; for (T i = 0; i < iterations; i++) { ret *= multiplicand; } return ret; } /** Compute 10 to the power of n */ template<> CSV_CONST CONSTEXPR_14 long double pow10(const unsigned& n) noexcept { long double multiplicand = n > 0 ? 10 : 0.1, ret = 1; for (unsigned i = 0; i < n; i++) { ret *= multiplicand; } return ret; } #ifndef DOXYGEN_SHOULD_SKIP_THIS /** Private site-indexed array mapping byte sizes to an integer size enum */ constexpr DataType int_type_arr[8] = { DataType::CSV_INT8, // 1 DataType::CSV_INT16, // 2 DataType::UNKNOWN, DataType::CSV_INT32, // 4 DataType::UNKNOWN, DataType::UNKNOWN, DataType::UNKNOWN, DataType::CSV_INT64 // 8 }; template inline DataType type_num() { static_assert(std::is_integral::value, "T should be an integral type."); static_assert(sizeof(T) <= 8, "Byte size must be no greater than 8."); return int_type_arr[sizeof(T) - 1]; } template<> inline DataType type_num() { return DataType::CSV_DOUBLE; } template<> inline DataType type_num() { return DataType::CSV_DOUBLE; } template<> inline DataType type_num() { return DataType::CSV_DOUBLE; } template<> inline DataType type_num() { return DataType::CSV_NULL; } template<> inline DataType type_num() { return DataType::CSV_STRING; } CONSTEXPR_14 DataType data_type(csv::string_view in, long double* const out = nullptr, const char decimalsymbol = '.'); #endif /** Given a byte size, return the largest number than can be stored in * an integer of that size * * Note: Provides a platform-agnostic way of mapping names like "long int" to * byte sizes */ template CONSTEXPR_14 long double get_int_max() { static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, "Bytes must be a power of 2 below 8."); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4127) #endif IF_CONSTEXPR (sizeof(signed char) == Bytes) { return (long double)std::numeric_limits::max(); } else IF_CONSTEXPR (sizeof(short) == Bytes) { return (long double)std::numeric_limits::max(); } else IF_CONSTEXPR (sizeof(int) == Bytes) { return (long double)std::numeric_limits::max(); } else IF_CONSTEXPR (sizeof(long int) == Bytes) { return (long double)std::numeric_limits::max(); } else { return (long double)std::numeric_limits::max(); } #ifdef _MSC_VER #pragma warning(pop) #endif } /** Given a byte size, return the largest number than can be stored in * an unsigned integer of that size */ template CONSTEXPR_14 long double get_uint_max() { static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, "Bytes must be a power of 2 below 8."); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4127) #endif IF_CONSTEXPR(sizeof(unsigned char) == Bytes) { return (long double)std::numeric_limits::max(); } else IF_CONSTEXPR(sizeof(unsigned short) == Bytes) { return (long double)std::numeric_limits::max(); } else IF_CONSTEXPR(sizeof(unsigned int) == Bytes) { return (long double)std::numeric_limits::max(); } else IF_CONSTEXPR(sizeof(unsigned long int) == Bytes) { return (long double)std::numeric_limits::max(); } else { return (long double)std::numeric_limits::max(); } #ifdef _MSC_VER #pragma warning(pop) #endif } /** Largest number that can be stored in a 8-bit integer */ CONSTEXPR_VALUE_14 long double CSV_INT8_MAX = get_int_max<1>(); /** Largest number that can be stored in a 16-bit integer */ CONSTEXPR_VALUE_14 long double CSV_INT16_MAX = get_int_max<2>(); /** Largest number that can be stored in a 32-bit integer */ CONSTEXPR_VALUE_14 long double CSV_INT32_MAX = get_int_max<4>(); /** Largest number that can be stored in a 64-bit integer */ CONSTEXPR_VALUE_14 long double CSV_INT64_MAX = get_int_max<8>(); /** Largest number that can be stored in a 8-bit ungisned integer */ CONSTEXPR_VALUE_14 long double CSV_UINT8_MAX = get_uint_max<1>(); /** Largest number that can be stored in a 16-bit unsigned integer */ CONSTEXPR_VALUE_14 long double CSV_UINT16_MAX = get_uint_max<2>(); /** Largest number that can be stored in a 32-bit unsigned integer */ CONSTEXPR_VALUE_14 long double CSV_UINT32_MAX = get_uint_max<4>(); /** Largest number that can be stored in a 64-bit unsigned integer */ CONSTEXPR_VALUE_14 long double CSV_UINT64_MAX = get_uint_max<8>(); /** Given a pointer to the start of what is start of * the exponential part of a number written (possibly) in scientific notation * parse the exponent */ CSV_PRIVATE CONSTEXPR_14 DataType _process_potential_exponential( csv::string_view exponential_part, const long double& coeff, long double * const out) { long double exponent = 0; auto result = data_type(exponential_part, &exponent); // Exponents in scientific notation should not be decimal numbers if (result >= DataType::CSV_INT8 && result < DataType::CSV_DOUBLE) { if (out) *out = coeff * pow10(static_cast(exponent)); return DataType::CSV_DOUBLE; } return DataType::CSV_STRING; } /** Given the absolute value of an integer, determine what numeric type * it fits in */ CSV_PRIVATE CSV_PURE CONSTEXPR_14 DataType _determine_integral_type(const long double& number) noexcept { // We can assume number is always non-negative assert(number >= 0); if (number <= internals::CSV_INT8_MAX) return DataType::CSV_INT8; else if (number <= internals::CSV_INT16_MAX) return DataType::CSV_INT16; else if (number <= internals::CSV_INT32_MAX) return DataType::CSV_INT32; else if (number <= internals::CSV_INT64_MAX) return DataType::CSV_INT64; else // Conversion to long long will cause an overflow return DataType::CSV_BIGINT; } /** Distinguishes numeric from other text values. Used by various * type casting functions, like csv_parser::CSVReader::read_row() * * #### Rules * - Leading and trailing whitespace ("padding") ignored * - A string of just whitespace is NULL * * @param[in] in String value to be examined * @param[out] out Pointer to long double where results of numeric parsing * get stored * @param[in] decimalSymbol the character separating integral and decimal part, * defaults to '.' if omitted */ CONSTEXPR_14 DataType data_type(csv::string_view in, long double* const out, const char decimalSymbol) { // Empty string --> NULL if (in.size() == 0) return DataType::CSV_NULL; bool ws_allowed = true, dot_allowed = true, digit_allowed = true, is_negative = false, has_digit = false, prob_float = false; unsigned places_after_decimal = 0; long double integral_part = 0, decimal_part = 0; for (size_t i = 0, ilen = in.size(); i < ilen; i++) { const char& current = in[i]; switch (current) { case ' ': if (!ws_allowed) { if (isdigit(in[i - 1])) { digit_allowed = false; ws_allowed = true; } else { // Ex: '510 123 4567' return DataType::CSV_STRING; } } break; case '+': if (!ws_allowed) { return DataType::CSV_STRING; } break; case '-': if (!ws_allowed) { // Ex: '510-123-4567' return DataType::CSV_STRING; } is_negative = true; break; // case decimalSymbol: not allowed because decimalSymbol is not a literal, // it is handled in the default block case 'e': case 'E': // Process scientific notation if (prob_float || (i && i + 1 < ilen && isdigit(in[i - 1]))) { size_t exponent_start_idx = i + 1; prob_float = true; // Strip out plus sign if (in[i + 1] == '+') { exponent_start_idx++; } return _process_potential_exponential( in.substr(exponent_start_idx), is_negative ? -(integral_part + decimal_part) : integral_part + decimal_part, out ); } return DataType::CSV_STRING; break; default: short digit = static_cast(current - '0'); if (digit >= 0 && digit <= 9) { // Process digit has_digit = true; if (!digit_allowed) return DataType::CSV_STRING; else if (ws_allowed) // Ex: '510 456' ws_allowed = false; // Build current number if (prob_float) decimal_part += digit / pow10(++places_after_decimal); else integral_part = (integral_part * 10) + digit; } // case decimalSymbol: not allowed because decimalSymbol is not a literal. else if (dot_allowed && current == decimalSymbol) { dot_allowed = false; prob_float = true; } else { return DataType::CSV_STRING; } } } // No non-numeric/non-whitespace characters found if (has_digit) { long double number = integral_part + decimal_part; if (out) { *out = is_negative ? -number : number; } return prob_float ? DataType::CSV_DOUBLE : _determine_integral_type(number); } // Just whitespace return DataType::CSV_NULL; } } } /** @file * @brief Implements Functions related to hexadecimal parsing */ #include #include namespace csv { namespace internals { template bool try_parse_hex(csv::string_view sv, T& parsedValue) { static_assert(std::is_integral::value, "try_parse_hex only works with integral types (int, long, long long, etc.)"); size_t start = 0, end = 0; // Trim out whitespace chars for (; start < sv.size() && sv[start] == ' '; start++); for (end = start; end < sv.size() && sv[end] != ' '; end++); T value_ = 0; size_t digits = (end - start); size_t base16_exponent = digits - 1; if (digits == 0) return false; for (const auto& ch : sv.substr(start, digits)) { int digit = 0; switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': digit = static_cast(ch - '0'); break; case 'a': case 'A': digit = 10; break; case 'b': case 'B': digit = 11; break; case 'c': case 'C': digit = 12; break; case 'd': case 'D': digit = 13; break; case 'e': case 'E': digit = 14; break; case 'f': case 'F': digit = 15; break; default: return false; } value_ += digit * (T)pow(16, (double)base16_exponent); base16_exponent--; } parsedValue = value_; return true; } } } /** @file * @brief Internal data structures for CSV parsing * * This file contains the low-level structures used by the parser to store * CSV data before it's exposed through the public CSVRow/CSVField API. * * Data flow: Parser → RawCSVData → CSVRow → CSVField */ #include #include #if !defined(CSV_ENABLE_THREADS) || CSV_ENABLE_THREADS #include #endif #include #include #include namespace csv { namespace internals { /** A barebones class used for describing CSV fields */ struct RawCSVField { RawCSVField() = default; RawCSVField(size_t _start, size_t _length, bool _double_quote = false) noexcept { start = _start; length = _length; has_double_quote = _double_quote; } /** The start of the field, relative to the beginning of the row */ size_t start; /** The length of the row, ignoring quote escape characters */ size_t length; /** Whether or not the field contains an escaped quote */ bool has_double_quote; }; /** A class used for efficiently storing RawCSVField objects and expanding as necessary * * @par Implementation * Stores fields in page-aligned chunks (~170 fields/chunk) via a vector of * unique_ptr: * - This design provides better cache locality when accessing sequential fields in a row * as well as much lower memory allocation overhead. * - The unique_ptr ensures STL container does not invalidate pointers to fields when resizing, * which is critical to ensure memory safety and correctness of the parser. * * @par Thread Safety * Cross-thread visibility is provided by the records queue mutex in * ThreadSafeDeque: the writer enqueues a RawCSVData only after all fields are * written, and the reader dequeues it only after the mutex unlock/lock pair, * which is a full happens-before edge. No additional atomics are needed here. * * @par Historical Bug (Issue #278, fixed Feb 2026) * Move constructor previously left _back pointing to moved-from buffer memory, causing * memory corruption on next emplace_back(). Fixed by recalculating _back from * _owned_blocks after move. */ class RawCSVFieldList { public: /** Construct a RawCSVFieldList which allocates blocks of a certain size */ RawCSVFieldList(size_t single_buffer_capacity = (size_t)(internals::PAGE_SIZE / sizeof(RawCSVField))) : _single_buffer_capacity(single_buffer_capacity) { const size_t max_fields = internals::ITERATION_CHUNK_SIZE + 1; const size_t block_capacity = (max_fields + _single_buffer_capacity - 1) / _single_buffer_capacity; _owned_blocks.reserve(block_capacity); this->allocate(); } // No copy constructor RawCSVFieldList(const RawCSVFieldList& other) = delete; // CSVFieldArrays may be moved RawCSVFieldList(RawCSVFieldList&& other) noexcept: _single_buffer_capacity(other._single_buffer_capacity) { this->_owned_blocks = std::move(other._owned_blocks); _current_buffer_size = other._current_buffer_size; _current_block = other._current_block; // Recalculate _back pointer to point into OUR blocks, not the moved-from ones if (!this->_owned_blocks.empty()) { _back = this->_owned_blocks[_current_block].get() + _current_buffer_size; } else { _back = nullptr; } // Invalidate moved-from state to prevent use-after-move bugs other._back = nullptr; other._current_buffer_size = 0; other._current_block = 0; } template void emplace_back(Args&&... args) { if (this->_current_buffer_size == this->_single_buffer_capacity) { this->allocate(); } assert(_back != nullptr); *(_back++) = RawCSVField(std::forward(args)...); _current_buffer_size++; } size_t size() const noexcept { return this->_current_buffer_size + (_current_block * this->_single_buffer_capacity); } /** Access a field by its index. This allows CSVRow objects to access fields * without knowing internal implementation details of RawCSVFieldList. */ RawCSVField& operator[](size_t n) const; private: const size_t _single_buffer_capacity; /** Owned field-storage blocks; pre-reserved to avoid reallocation. */ std::vector> _owned_blocks = {}; /** Number of items in the current block */ size_t _current_buffer_size = 0; /** Current block index */ size_t _current_block = 0; /** Pointer to the next empty field slot in the current block */ RawCSVField* _back = nullptr; /** Allocate a new page of memory */ void allocate(); }; /** A class for storing raw CSV data and associated metadata * * This structure is the bridge between the parser thread and the main thread. * Parser populates fields, data, and parse_flags; main thread reads via CSVRow. */ struct RawCSVData { std::shared_ptr _data = nullptr; csv::string_view data = ""; internals::RawCSVFieldList fields; /** Cached unescaped field values for fields with escaped quotes. * Thread-safe lazy initialization using double-check locking. * Lock is only held during rare concurrent initialization; reads are lock-free. */ std::unordered_map double_quote_fields = {}; #if CSV_ENABLE_THREADS mutable std::mutex double_quote_init_lock; ///< Protects lazy initialization only #endif internals::ColNamesPtr col_names = nullptr; internals::ParseFlagMap parse_flags; internals::WhitespaceMap ws_flags; /** True when at least one whitespace trim character is configured. * Used by get_field_impl() to skip trim work in the common no-trim case. */ bool has_ws_trimming = false; }; using RawCSVDataPtr = std::shared_ptr; } } #if CSV_ENABLE_THREADS #define CSV_INIT_WITH_OPTIONAL_DCL(data_ref, value_ref, ...) \ do { \ if ((value_ref).empty()) { \ std::lock_guard lock((data_ref).double_quote_init_lock); \ if ((value_ref).empty()) { \ __VA_ARGS__ \ } \ } \ } while (0) #else #define CSV_INIT_WITH_OPTIONAL_DCL(data_ref, value_ref, ...) \ do { \ (void)(data_ref); \ if ((value_ref).empty()) { \ __VA_ARGS__ \ } \ } while (0) #endif namespace csv { namespace internals { class IBasicCSVParser; static const std::string ERROR_NAN = "Not a number."; static const std::string ERROR_OVERFLOW = "Overflow error."; static const std::string ERROR_FLOAT_TO_INT = "Attempted to convert a floating point value to an integral type."; static const std::string ERROR_NEG_TO_UNSIGNED = "Negative numbers cannot be converted to unsigned types."; std::string json_escape_string(csv::string_view s) noexcept; // Inside CSVField::get() or wherever you materialize the value csv::string_view get_trimmed(csv::string_view sv, const WhitespaceMap& ws_flags) noexcept; } /** * @class CSVField * @brief Data type representing individual CSV values. * CSVFields can be obtained by using CSVRow::operator[] */ class CSVField { public: /** Constructs a CSVField from a string_view */ constexpr explicit CSVField(csv::string_view _sv) noexcept : sv(_sv) {} operator std::string() const { return std::string(this->sv); } /** Returns the value casted to the requested type, performing type checking before. * * \par Valid options for T * - std::string or csv::string_view * - signed integral types (signed char, short, int, long int, long long int) * - floating point types (float, double, long double) * - unsigned integers are not supported at this time, but may be in a later release * * \par Invalid conversions * - Converting non-numeric values to any numeric type * - Converting floating point values to integers * - Converting a large integer to a smaller type that will not hold it * * @note This method is capable of parsing scientific E-notation. * See [this page](md_docs_source_scientific_notation.html) * for more details. * * @throws std::runtime_error Thrown if an invalid conversion is performed. * * @warning Currently, conversions to floating point types are not * checked for loss of precision * * @warning Any string_views returned are only guaranteed to be valid * if the parent CSVRow is still alive. If you are concerned * about object lifetimes, then grab a std::string or a * numeric value. * */ template T get() { IF_CONSTEXPR(std::is_arithmetic::value) { // Note: this->type() also converts the CSV value to float if (this->type() <= DataType::CSV_STRING) { throw std::runtime_error(internals::ERROR_NAN); } } IF_CONSTEXPR(std::is_integral::value) { // Note: this->is_float() also converts the CSV value to float if (this->is_float()) { throw std::runtime_error(internals::ERROR_FLOAT_TO_INT); } IF_CONSTEXPR(std::is_unsigned::value) { if (this->value < 0) { throw std::runtime_error(internals::ERROR_NEG_TO_UNSIGNED); } } } // Allow fallthrough from previous if branch IF_CONSTEXPR(!std::is_floating_point::value) { IF_CONSTEXPR(std::is_unsigned::value) { // Quick hack to perform correct unsigned integer boundary checks if (this->value > internals::get_uint_max()) { throw std::runtime_error(internals::ERROR_OVERFLOW); } } else if (internals::type_num() < this->_type) { throw std::runtime_error(internals::ERROR_OVERFLOW); } } return static_cast(this->value); } /** Attempts to retrieve the value as the requested type without throwing exceptions. * * @param[out] out Output parameter that receives the converted value if successful * @return true if conversion succeeded, false otherwise * * \par Valid options for T * - std::string or csv::string_view * - signed integral types (signed char, short, int, long int, long long int) * - floating point types (float, double, long double) * - unsigned integers are not supported at this time, but may be in a later release * * \par When conversion fails (returns false) * - Converting non-numeric values to any numeric type * - Converting floating point values to integers * - Converting a large integer to a smaller type that will not hold it * - Converting negative values to unsigned types * * @note This method is capable of parsing scientific E-notation. * * @warning Currently, conversions to floating point types are not * checked for loss of precision * * @warning Any string_views returned are only guaranteed to be valid * if the parent CSVRow is still alive. * * Example: * @code * int value; * if (field.try_get(value)) { * // Use value safely * } else { * // Handle conversion failure * } * @endcode */ template bool try_get(T& out) noexcept { IF_CONSTEXPR(std::is_arithmetic::value) { // Check if value is numeric if (this->type() <= DataType::CSV_STRING) { return false; } } IF_CONSTEXPR(std::is_integral::value) { // Check for float-to-int conversion if (this->is_float()) { return false; } IF_CONSTEXPR(std::is_unsigned::value) { if (this->value < 0) { return false; } } } // Check for overflow IF_CONSTEXPR(!std::is_floating_point::value) { IF_CONSTEXPR(std::is_unsigned::value) { if (this->value > internals::get_uint_max()) { return false; } } else if (internals::type_num() < this->_type) { return false; } } out = static_cast(this->value); return true; } /** Parse a hexadecimal value, returning false if the value is not hex. * @tparam T An integral type (int, long, long long, etc.) */ template bool try_parse_hex(T& parsedValue) { static_assert(std::is_integral::value, "try_parse_hex only works with integral types (int, long, long long, etc.)"); return internals::try_parse_hex(this->sv, parsedValue); } /** Attempts to parse a decimal (or integer) value using the given symbol, * returning `true` if the value is numeric. * * @note This method also updates this field's type * */ bool try_parse_decimal(long double& dVal, const char decimalSymbol = '.'); /** Compares the contents of this field to a numeric value. If this * field does not contain a numeric value, then all comparisons return * false. * * @note Floating point values are considered equal if they are within * `0.000001` of each other. * * @warning Multiple numeric comparisons involving the same field can * be done more efficiently by calling the CSVField::get<>() method. * * @sa csv::CSVField::operator==(const char * other) * @sa csv::CSVField::operator==(csv::string_view other) */ template CONSTEXPR_14 bool operator==(T other) const noexcept { static_assert(std::is_arithmetic::value, "T should be a numeric value."); if (this->_type != DataType::UNKNOWN) { if (this->_type == DataType::CSV_STRING) { return false; } return internals::is_equal(value, static_cast(other), 0.000001L); } long double out = 0; if (internals::data_type(this->sv, &out) == DataType::CSV_STRING) { return false; } return internals::is_equal(out, static_cast(other), 0.000001L); } /** Return a string view over the field's contents */ CONSTEXPR csv::string_view get_sv() const noexcept { return this->sv; } /** Returns true if field is an empty string or string of whitespace characters */ CONSTEXPR_14 bool is_null() noexcept { return type() == DataType::CSV_NULL; } /** Returns true if field is a non-numeric, non-empty string */ CONSTEXPR_14 bool is_str() noexcept { return type() == DataType::CSV_STRING; } /** Returns true if field is an integer or float */ CONSTEXPR_14 bool is_num() noexcept { return type() >= DataType::CSV_INT8; } /** Returns true if field is an integer */ CONSTEXPR_14 bool is_int() noexcept { return (type() >= DataType::CSV_INT8) && (type() <= DataType::CSV_INT64); } /** Returns true if field is a floating point value */ CONSTEXPR_14 bool is_float() noexcept { return type() == DataType::CSV_DOUBLE; } /** Return the type of the underlying CSV data */ CONSTEXPR_14 DataType type() noexcept { this->get_value(); return _type; } private: long double value = 0; /**< Cached numeric value */ csv::string_view sv = ""; /**< A pointer to this field's text */ DataType _type = DataType::UNKNOWN; /**< Cached data type value */ CONSTEXPR_14 void get_value() noexcept { /* Check to see if value has been cached previously, if not * evaluate it */ if ((int)_type < 0) { this->_type = internals::data_type(this->sv, &this->value); } } }; /** Data structure for representing CSV rows */ class CSVRow { public: friend internals::IBasicCSVParser; CSVRow() = default; /** Construct a CSVRow from a RawCSVDataPtr */ CSVRow(internals::RawCSVDataPtr _data) : data(_data) {} CSVRow(internals::RawCSVDataPtr _data, size_t _data_start, size_t _field_bounds) : data(_data), data_start(_data_start), fields_start(_field_bounds) {} CSVRow(internals::RawCSVDataPtr _data, size_t _data_start, size_t _field_bounds, size_t _row_length) : data(_data), data_start(_data_start), fields_start(_field_bounds), row_length(_row_length) {} /** Indicates whether row is empty or not */ CONSTEXPR bool empty() const noexcept { return this->size() == 0; } /** Return the number of fields in this row */ CONSTEXPR size_t size() const noexcept { return row_length; } /** @name Value Retrieval */ ///@{ CSVField operator[](size_t n) const; CSVField operator[](const std::string&) const; std::string to_json(const std::vector& subset = {}) const; std::string to_json_array(const std::vector& subset = {}) const; /** Retrieve this row's associated column names */ std::vector get_col_names() const { return this->data->col_names->get_col_names(); } /** Convert this CSVRow into an unordered map. * The keys are the column names and the values are the corresponding field values. */ std::unordered_map to_unordered_map() const; /** Convert this CSVRow into an unordered map. * The keys are the column names and the values are the corresponding field values. * * @param[in] subset Vector of column names to include in the map. */ std::unordered_map to_unordered_map( const std::vector& subset ) const; #ifdef CSV_HAS_CXX20 /** Convert this CSVRow into a std::ranges::input_range of string_views. */ auto to_sv_range() const { return std::views::iota(size_t{0}, this->size()) | std::views::transform([this](size_t i) { return this->get_field(i); }); } #endif /** Convert this row into a `std::vector`. * * This conversion is primarily intended for write-side workflows, such as * reordering or selecting columns before forwarding the row to `CSVWriter`. * * @note This is less efficient than indexed access via `operator[]` because * it materializes all fields as owning strings. */ operator std::vector() const; ///@} /** A random access iterator over the contents of a CSV row. * Each iterator points to a CSVField. */ class iterator { public: #ifndef DOXYGEN_SHOULD_SKIP_THIS using value_type = CSVField; using difference_type = int; using pointer = std::shared_ptr; using reference = CSVField & ; using iterator_category = std::random_access_iterator_tag; #endif iterator(const CSVRow*, int i); reference operator*() const; pointer operator->() const; iterator operator++(int); iterator& operator++(); iterator operator--(int); iterator& operator--(); iterator operator+(difference_type n) const; iterator operator-(difference_type n) const; /** Two iterators are equal if they point to the same field */ CONSTEXPR bool operator==(const iterator& other) const noexcept { return this->i == other.i; }; CONSTEXPR bool operator!=(const iterator& other) const noexcept { return !operator==(other); } #ifndef NDEBUG friend CSVRow; #endif private: const CSVRow * daddy = nullptr; // Pointer to parent internals::RawCSVDataPtr data = nullptr; // Keep data alive for lifetime of iterator std::shared_ptr field = nullptr; // Current field pointed at int i = 0; // Index of current field }; /** A reverse iterator over the contents of a CSVRow. */ using reverse_iterator = std::reverse_iterator; /** @name Iterators * @brief Each iterator points to a CSVField object. */ ///@{ iterator begin() const; iterator end() const noexcept; reverse_iterator rbegin() const noexcept; reverse_iterator rend() const; ///@} private: /** Shared implementation for field access (handles quoting and caching). */ inline csv::string_view get_field_impl(size_t index, const internals::RawCSVDataPtr& _data) const { using internals::ParseFlags; if (index >= this->size()) throw std::runtime_error("Index out of bounds."); const size_t field_index = this->fields_start + index; auto field = _data->fields[field_index]; auto field_str = csv::string_view(_data->data).substr(this->data_start + field.start, field.length); if (field.has_double_quote) { auto& value = _data->double_quote_fields[field_index]; CSV_INIT_WITH_OPTIONAL_DCL((*_data), value, bool prev_ch_quote = false; for (size_t i = 0; i < field.length; i++) { if (_data->parse_flags[field_str[i] + CHAR_OFFSET] == ParseFlags::QUOTE) { if (prev_ch_quote) { prev_ch_quote = false; continue; } else { prev_ch_quote = true; } } value += field_str[i]; } ); if (_data->has_ws_trimming) return internals::get_trimmed(csv::string_view(value), _data->ws_flags); return value; } else if (_data->has_ws_trimming) { field_str = internals::get_trimmed(field_str, _data->ws_flags); } return field_str; } /** Retrieve a string view corresponding to the specified index */ csv::string_view get_field(size_t index) const; /** Iterator-safe field access using explicit data pointer * (prevents accessing freed data when CSVRow is reassigned) */ csv::string_view get_field_safe(size_t index, internals::RawCSVDataPtr _data) const; internals::RawCSVDataPtr data; /** Where in RawCSVData.data we start */ size_t data_start = 0; /** Where in the RawCSVDataPtr.fields array we start */ size_t fields_start = 0; /** How many columns this row spans */ size_t row_length = 0; }; #ifdef _MSC_VER #pragma region CSVField::get Specializations #endif /** Retrieve this field's original string */ template<> inline std::string CSVField::get() { return std::string(this->sv); } /** Retrieve a view over this field's string * * @warning This string_view is only guaranteed to be valid as long as this * CSVRow is still alive. */ template<> CONSTEXPR_14 csv::string_view CSVField::get() { return this->sv; } /** Retrieve this field's value as a long double */ template<> CONSTEXPR_14 long double CSVField::get() { if (!is_num()) throw std::runtime_error(internals::ERROR_NAN); return this->value; } /** Non-throwing retrieval of field as std::string */ template<> inline bool CSVField::try_get(std::string& out) noexcept { out = std::string(this->sv); return true; } /** Non-throwing retrieval of field as csv::string_view */ template<> CONSTEXPR_14 bool CSVField::try_get(csv::string_view& out) noexcept { out = this->sv; return true; } /** Non-throwing retrieval of field as long double */ template<> CONSTEXPR_14 bool CSVField::try_get(long double& out) noexcept { if (!is_num()) return false; out = this->value; return true; } #ifdef _MSC_VER #pragma endregion CSVField::get Specializations #endif /** Compares the contents of this field to a string */ template<> CONSTEXPR bool CSVField::operator==(const char * other) const noexcept { return this->sv == other; } /** Compares the contents of this field to a string */ template<> CONSTEXPR bool CSVField::operator==(csv::string_view other) const noexcept { return this->sv == other; } } #undef CSV_INIT_WITH_OPTIONAL_DCL /** @file * @brief Shared contracts for row deque implementations */ #if CSV_ENABLE_THREADS /** @file * @brief Thread-safe deque for producer-consumer patterns * * Generic container used for cross-thread communication in the CSV parser. * Parser thread pushes rows, main thread pops them. * * Design notes: see THREADSAFE_DEQUE_DESIGN.md for protocol details, * invariants, and producer/consumer timing diagrams. */ #include #include #include #include namespace csv { namespace internals { /** A std::deque wrapper which allows multiple read and write threads to concurrently * access it along with providing read threads the ability to wait for the deque * to become populated. * * Concurrency strategy: writer-side mutations (push_back/pop_front) are locked; * hot-path flags (empty/is_waitable) are atomic; operator[] and iterators are * not synchronized and must not run concurrently with writers. */ template class ThreadSafeDeque { public: ThreadSafeDeque(size_t notify_size = 100) : _notify_size(notify_size) {} ThreadSafeDeque(const ThreadSafeDeque& other) { this->data = other.data; this->_notify_size = other._notify_size; this->_is_empty.store(other._is_empty.load(std::memory_order_acquire), std::memory_order_release); } ThreadSafeDeque(const std::deque& source) : ThreadSafeDeque() { this->data = source; this->_is_empty.store(source.empty(), std::memory_order_release); } bool empty() const noexcept { return this->_is_empty.load(std::memory_order_acquire); } T& front() noexcept { std::lock_guard lock{ this->_lock }; return this->data.front(); } /** NOTE: operator[] is not synchronized. * Only call when no concurrent push_back/pop_front can occur. * std::deque can reallocate its internal map on push_back, which * makes concurrent operator[] access undefined behavior. */ T& operator[](size_t n) { return this->data[n]; } void push_back(T&& item) { std::lock_guard lock{ this->_lock }; this->data.push_back(std::move(item)); this->_is_empty.store(false, std::memory_order_release); if (this->data.size() >= _notify_size) { this->_cond.notify_all(); } } T pop_front() noexcept { std::lock_guard lock{ this->_lock }; T item = std::move(data.front()); data.pop_front(); if (this->data.empty()) { this->_is_empty.store(true, std::memory_order_release); } return item; } /** Returns true if a thread is actively pushing items to this deque */ bool is_waitable() const noexcept { return this->_is_waitable.load(std::memory_order_acquire); } void wait() { if (!is_waitable()) { return; } std::unique_lock lock{ this->_lock }; this->_cond.wait(lock, [this] { return this->data.size() >= _notify_size || !this->is_waitable(); }); lock.unlock(); } size_t size() const noexcept { std::lock_guard lock{ this->_lock }; return this->data.size(); } typename std::deque::iterator begin() noexcept { return this->data.begin(); } typename std::deque::iterator end() noexcept { return this->data.end(); } /** Tell listeners that this deque is actively being pushed to */ void notify_all() { std::lock_guard lock{ this->_lock }; this->_is_waitable.store(true, std::memory_order_release); this->_cond.notify_all(); } void kill_all() { std::lock_guard lock{ this->_lock }; this->_is_waitable.store(false, std::memory_order_release); this->_cond.notify_all(); } private: std::atomic _is_empty{ true }; // Lock-free empty() check std::atomic _is_waitable{ false }; // Lock-free is_waitable() check size_t _notify_size; mutable std::mutex _lock; std::condition_variable _cond; std::deque data; }; } } #else /** @file * @brief Single-threaded row deque implementation */ #include #include namespace csv { namespace internals { template class SingleThreadDeque { public: SingleThreadDeque(size_t notify_size = 100) : _notify_size(notify_size) {} SingleThreadDeque(const SingleThreadDeque& other) { this->data = other.data; this->_notify_size = other._notify_size; this->_is_empty = other._is_empty; this->_is_waitable = other._is_waitable; } SingleThreadDeque(const std::deque& source) : SingleThreadDeque() { this->data = source; this->_is_empty = source.empty(); } bool empty() const noexcept { return this->_is_empty; } T& front() noexcept { return this->data.front(); } T& operator[](size_t n) { return this->data[n]; } void push_back(T&& item) { this->data.push_back(std::move(item)); this->_is_empty = false; } T pop_front() noexcept { T item = std::move(data.front()); data.pop_front(); if (this->data.empty()) { this->_is_empty = true; } return item; } bool is_waitable() const noexcept { return this->_is_waitable; } void wait() { // No-op in single-thread mode. } size_t size() const noexcept { return this->data.size(); } typename std::deque::iterator begin() noexcept { return this->data.begin(); } typename std::deque::iterator end() noexcept { return this->data.end(); } void notify_all() { this->_is_waitable = true; } void kill_all() { this->_is_waitable = false; } private: bool _is_empty = true; bool _is_waitable = false; size_t _notify_size; std::deque data; }; } } #endif #include #include #include #ifdef CSV_HAS_CXX20 #include #endif namespace csv { namespace internals { #if !CSV_ENABLE_THREADS template using ThreadSafeDeque = SingleThreadDeque; #endif #ifdef CSV_HAS_CXX20 template concept RowDequeLike = requires(Q q, const Q cq, T item, size_t n) { { Q(100) }; { q.push_back(std::move(item)) } -> std::same_as; { q.pop_front() } -> std::same_as; { cq.empty() } -> std::same_as; { cq.is_waitable() } -> std::same_as; { q.wait() } -> std::same_as; { q.notify_all() } -> std::same_as; { q.kill_all() } -> std::same_as; { q.front() } -> std::same_as; { q[n] } -> std::same_as; { cq.size() } -> std::same_as; { q.begin() }; { q.end() }; }; #if CSV_ENABLE_THREADS static_assert(RowDequeLike, int>, "ThreadSafeDeque must satisfy RowDequeLike contract"); #else static_assert(RowDequeLike, int>, "SingleThreadDeque must satisfy RowDequeLike contract"); static_assert(RowDequeLike, int>, "Selected ThreadSafeDeque alias must satisfy RowDequeLike contract"); #endif #endif } } namespace csv { namespace internals { constexpr const int UNINITIALIZED_FIELD = -1; /** Helper constexpr function to initialize an array with all the elements set to value */ template CSV_CONST CONSTEXPR_17 OutArray arrayToDefault(T&& value) { OutArray a {}; for (auto& e : a) e = value; return a; } /** Create a vector v where each index i corresponds to the * ASCII number for a character and, v[i + 128] labels it according to * the CSVReader::ParseFlags enum */ CSV_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter) { auto ret = arrayToDefault(ParseFlags::NOT_SPECIAL); ret[delimiter + CHAR_OFFSET] = ParseFlags::DELIMITER; ret['\r' + CHAR_OFFSET] = ParseFlags::NEWLINE; ret['\n' + CHAR_OFFSET] = ParseFlags::NEWLINE; return ret; } /** Create a vector v where each index i corresponds to the * ASCII number for a character and, v[i + 128] labels it according to * the CSVReader::ParseFlags enum */ CSV_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter, char quote_char) { std::array ret = make_parse_flags(delimiter); ret[quote_char + CHAR_OFFSET] = ParseFlags::QUOTE; return ret; } inline char infer_delimiter(const ParseFlagMap& parse_flags) noexcept { for (int i = 0; i < 256; ++i) { char ch = static_cast(i); if (parse_flags[ch + CHAR_OFFSET] == ParseFlags::DELIMITER) { return ch; } } return ','; } // fallback is returned when no QUOTE flag exists in parse_flags (e.g. no_quote mode). // Pass the delimiter so SIMD stops there instead of on a byte that is NOT_SPECIAL. inline char infer_quote_char(const ParseFlagMap& parse_flags, char fallback = '"') noexcept { for (int i = 0; i < 256; ++i) { char ch = static_cast(i); if (parse_flags[ch + CHAR_OFFSET] == ParseFlags::QUOTE) { return ch; } } return fallback; } /** Create a vector v where each index i corresponds to the * ASCII number for a character c and, v[i + 128] is true if * c is a whitespace character */ CSV_CONST CONSTEXPR_17 WhitespaceMap make_ws_flags(const char* ws_chars, size_t n_chars) { auto ret = arrayToDefault(false); for (size_t j = 0; j < n_chars; j++) { ret[ws_chars[j] + CHAR_OFFSET] = true; } return ret; } inline WhitespaceMap make_ws_flags(const std::vector& flags) { return make_ws_flags(flags.data(), flags.size()); } CSV_INLINE size_t get_file_size(csv::string_view filename); CSV_INLINE std::string get_csv_head(csv::string_view filename); } /** Standard type for storing collection of rows */ using RowCollection = internals::ThreadSafeDeque; namespace internals { /** Abstract base class which provides CSV parsing logic. * * Concrete implementations may customize this logic across * different input sources, such as memory mapped files, stringstreams, * etc... */ class IBasicCSVParser { public: IBasicCSVParser() = default; IBasicCSVParser(const CSVFormat&, const ColNamesPtr&); IBasicCSVParser( const ParseFlagMap& parse_flags, const WhitespaceMap& ws_flags ) : parse_flags_(parse_flags), ws_flags_(ws_flags) { const char d = internals::infer_delimiter(parse_flags); simd_sentinels_ = SentinelVecs(d, internals::infer_quote_char(parse_flags, d)); has_ws_trimming_ = std::any_of(ws_flags.begin(), ws_flags.end(), [](bool b) { return b; }); } virtual ~IBasicCSVParser() {} /** Whether or not we have reached the end of source */ bool eof() { return this->eof_; } /** Parse the next block of data */ virtual void next(size_t bytes) = 0; /** Indicate the last block of data has been parsed */ void end_feed(); CONSTEXPR_17 ParseFlags parse_flag(const char ch) const noexcept { return parse_flags_.data()[ch + CHAR_OFFSET]; } CONSTEXPR_17 ParseFlags compound_parse_flag(const char ch) const noexcept { return quote_escape_flag(parse_flag(ch), this->quote_escape_); } /** Whether or not this CSV has a UTF-8 byte order mark */ CONSTEXPR bool utf8_bom() const { return this->utf8_bom_; } void set_output(RowCollection& rows) { this->records_ = &rows; } protected: /** @name Current Parser State */ ///@{ CSVRow current_row_; RawCSVDataPtr data_ptr_ = nullptr; ColNamesPtr col_names_ = nullptr; RawCSVFieldList* fields_ = nullptr; int field_start_ = UNINITIALIZED_FIELD; size_t field_length_ = 0; /** Precomputed SIMD broadcast vectors for find_next_non_special */ SentinelVecs simd_sentinels_; /** An array where the (i + 128)th slot gives the ParseFlags for ASCII character i */ ParseFlagMap parse_flags_; ///@} /** @name Current Stream/File State */ ///@{ bool eof_ = false; /** The size of the incoming CSV */ size_t source_size_ = 0; ///@} /** Whether or not source needs to be read in chunks */ CONSTEXPR bool no_chunk() const { return this->source_size_ < ITERATION_CHUNK_SIZE; } /** Parse the current chunk of data * * * @returns How many character were read that are part of complete rows */ size_t parse(); /** Create a new RawCSVDataPtr for a new chunk of data */ void reset_data_ptr(); private: /** An array where the (i + 128)th slot determines whether ASCII character i should * be trimmed */ WhitespaceMap ws_flags_; /** True when at least one whitespace trim character is configured. * Used to skip trim loops entirely in the common no-trim case. */ bool has_ws_trimming_ = false; bool quote_escape_ = false; bool field_has_double_quote_ = false; /** Where we are in the current data block */ size_t data_pos_ = 0; /** Whether or not an attempt to find Unicode BOM has been made */ bool unicode_bom_scan_ = false; bool utf8_bom_ = false; /** Where complete rows should be pushed to */ RowCollection* records_ = nullptr; CONSTEXPR_17 bool ws_flag(const char ch) const noexcept { return ws_flags_.data()[ch + CHAR_OFFSET]; } size_t& current_row_start() { return this->current_row_.data_start; } void parse_field() noexcept; /** Finish parsing the current field */ void push_field(); /** Finish parsing the current row */ void push_row(); /** Handle possible Unicode byte order mark */ void trim_utf8_bom(); }; /** Read up to 500KB from a stream without rewinding. * * Replaces the old get_csv_head(TStream&) which required seekg/tellg. * Works with any std::istream, including non-seekable sources such as * pipes and decompression filters. */ template::value, int> = 0> std::string read_head_buffer(TStream& source) { const size_t limit = 500000; std::string buf(limit, '\0'); source.read(&buf[0], (std::streamsize)limit); buf.resize(static_cast(source.gcount())); return buf; } /** Read the first 500KB of a CSV file */ CSV_INLINE std::string get_csv_head(csv::string_view filename, size_t file_size); /** A class for parsing CSV data from any std::istream, including * non-seekable sources such as pipes and decompression filters. * * @par Chunk boundary handling * parse() returns the byte offset of the start of the last incomplete * row in the current chunk (the "remainder"). Rather than seeking back * to re-read those bytes (which requires a seekable stream), they are * saved in `leftover_` and prepended to the next chunk. This is * semantically identical to the old seek-back approach but works on * any istream and avoids the syscall overhead of seekg(). * * @par Head buffer * init_from_stream() reads a head buffer for format guessing before * constructing this parser. That buffer is passed in as the initial * `leftover_`, so its bytes are fed into the first chunk as if they had * just been read from the stream. */ template class StreamParser: public IBasicCSVParser { using RowCollection = ThreadSafeDeque; public: StreamParser(TStream& source, const CSVFormat& format, const ColNamesPtr& col_names = nullptr, std::string head = {} ) : IBasicCSVParser(format, col_names), leftover_(std::move(head)), source_(source) {} StreamParser( TStream& source, internals::ParseFlagMap parse_flags, internals::WhitespaceMap ws_flags) : IBasicCSVParser(parse_flags, ws_flags), source_(source) {} ~StreamParser() {} void next(size_t bytes = ITERATION_CHUNK_SIZE) override { if (this->eof()) return; // Reset parser state this->field_start_ = UNINITIALIZED_FIELD; this->field_length_ = 0; this->reset_data_ptr(); this->data_ptr_->_data = std::make_shared(); auto& chunk = *static_cast(this->data_ptr_->_data.get()); // Prepend leftover bytes from the previous chunk's incomplete // trailing row, then read the next block from the stream. // Uses a raw buffer to avoid std::string::resize() zero-fill // on the full 10MB chunk size (critical for tiny inputs). chunk = std::move(leftover_); std::unique_ptr buf(new char[bytes]); source_.read(buf.get(), (std::streamsize)bytes); const size_t n = static_cast(source_.gcount()); if (n > 0) chunk.append(buf.get(), n); // Check for real I/O errors only (bad bit indicates unrecoverable error). // failbit alone is not fatal - it's set on EOF or when requesting bytes // beyond available data, which is normal behavior for stringstreams. if (source_.bad()) { throw std::runtime_error("StreamParser read failure"); } // Create string_view this->data_ptr_->data = chunk; // Parse this->current_row_ = CSVRow(this->data_ptr_); size_t remainder = this->parse(); if (source_.eof() || chunk.empty()) { this->eof_ = true; this->end_feed(); } else { // Save the tail bytes that begin an incomplete row so they // are prepended to the next chunk (see class-level comment). leftover_ = chunk.substr(remainder); } } private: // Bytes from the previous chunk that form the start of an incomplete // row, plus the initial head buffer on the first call. std::string leftover_; TStream& source_; }; #if !defined(__EMSCRIPTEN__) /** Parser for memory-mapped files * * @par Implementation * This class constructs moving windows over a file to avoid * creating massive memory maps which may require more RAM * than the user has available. It contains logic to automatically * re-align each memory map to the beginning of a CSV row. * */ class MmapParser : public IBasicCSVParser { public: MmapParser(csv::string_view filename, const CSVFormat& format, const ColNamesPtr& col_names = nullptr ) : IBasicCSVParser(format, col_names) { this->_filename = filename.data(); this->source_size_ = get_file_size(filename); }; ~MmapParser() {} void next(size_t bytes) override; private: std::string _filename; size_t mmap_pos = 0; }; #endif } } /** The all encompassing namespace */ namespace csv { /** Stuff that is generally not of interest to end-users */ namespace internals { std::string format_row(const std::vector& row, csv::string_view delim = ", "); std::vector _get_col_names( csv::string_view head, const CSVFormat format = CSVFormat::guess_csv()); struct GuessScore { double score; size_t header; }; CSV_INLINE GuessScore calculate_score(csv::string_view head, const CSVFormat& format); CSVGuessResult _guess_format(csv::string_view head, const std::vector& delims = { ',', '|', '\t', ';', '^', '~' }); } std::vector get_col_names( csv::string_view filename, const CSVFormat format = CSVFormat::guess_csv()); /** @brief Guess the delimiter and header row of a CSV file * * @param[in] filename Path to CSV file * @param[in] delims Candidate delimiters to test * @return CSVGuessResult containing the detected delimiter and header row index * * **Heuristic:** For each candidate delimiter, calculate a score based on * the most common row length (mode). The delimiter with the highest score wins. * * **Header Detection:** * - If the first row has >= columns than the mode, it's treated as the header * - Otherwise, the first row with the mode length is treated as the header * * This approach handles: * - Headers with trailing delimiters or optional columns (wider than data rows) * - Comment lines before the actual header (first row shorter than mode) * - Standard CSVs where first row is the header * * @note Score = (row_length × count_of_rows_with_that_length) */ CSVGuessResult guess_format(csv::string_view filename, const std::vector& delims = { ',', '|', '\t', ';', '^', '~' }); /** @class CSVReader * @brief Main class for parsing CSVs from files and in-memory sources * * All rows are compared to the column names for length consistency * - By default, rows that are too short or too long are dropped * - Custom behavior can be defined by overriding bad_row_handler in a subclass * * **Streaming semantics:** CSVReader is a single-pass streaming reader. Every read * operation — read_row(), the iterator interface — pulls rows permanently * from the internal queue. Rows consumed by one interface are not visible to another. * There is no rewind or seek. * * **Ownership and sharing:** CSVReader is non-copyable and move-enabled. It manages * live parsing state (worker thread, internal queue, and optional owned stream), so * ownership transfer should be explicit. To share or transfer a reader, wrap it in a * `std::unique_ptr`: * @code{.cpp} * auto reader = std::make_unique("data.csv"); * process(std::move(reader)); // transfer ownership * @endcode */ class CSVReader { public: /** * An input iterator capable of handling large files. * @note Created by CSVReader::begin() and CSVReader::end(). * * @par Iterating over a file * @snippet tests/test_csv_iterator.cpp CSVReader Iterator 1 * * @par Using with `` library * @snippet tests/test_csv_iterator.cpp CSVReader Iterator 2 * * @warning STREAMING CONSTRAINT - DO NOT ATTEMPT TO CACHE ALL DATA * This iterator is intentionally std::input_iterator_tag (single-pass) to support * streaming large CSV files that may exceed available RAM (e.g., 50+ GB files). * * @par CRITICAL DESIGN CONSTRAINT: * - The underlying RawCSVData chunks are automatically freed as the iterator advances * - Only the CURRENT row's data is kept alive (via CSVRow's RawCSVDataPtr member) * - Previous chunks are freed to allow unlimited file sizes with bounded memory * * @par WHY FORWARD ITERATOR IS NOT POSSIBLE: * - ForwardIterator requires multi-pass guarantees (can hold multiple valid positions) * - Supporting this would require caching ALL RawCSVDataPtr chunks in the iterator * - This defeats the streaming purpose: a 50 GB CSV would require 50+ GB of RAM * - The entire library design depends on automatic chunk cleanup for memory efficiency * * @par IMPLICATIONS FOR ALGORITHM USE: * - Algorithms requiring ForwardIterator (std::max_element, std::sort, etc.) may * appear to work in tests with small files, but will cause heap-use-after-free * when the algorithm tries to access iterators pointing to freed chunks * - CORRECT approach: Copy rows to std::vector first, then use algorithms * - Example: auto rows = std::vector(reader.begin(), reader.end()); * auto max_row = std::max_element(rows.begin(), rows.end(), ...); * * @par FOR AI AGENTS AND MAINTAINERS: * If you encounter heap-use-after-free with ForwardIterator algorithms, the solution * is NOT to cache all RawCSVDataPtr chunks - this violates the fundamental streaming * architecture. Instead, document the limitation or provide vector-based workarounds. */ class iterator { public: #ifndef DOXYGEN_SHOULD_SKIP_THIS using value_type = CSVRow; using difference_type = std::ptrdiff_t; using pointer = CSVRow * ; using reference = CSVRow & ; using iterator_category = std::input_iterator_tag; #endif iterator() = default; iterator(CSVReader* reader) : daddy(reader) {} iterator(CSVReader*, CSVRow&&); /** Access the CSVRow held by the iterator */ CONSTEXPR_14 reference operator*() { return this->row; } CONSTEXPR_14 reference operator*() const { return const_cast(this->row); } /** Return a pointer to the CSVRow the iterator has stopped at */ CONSTEXPR_14 pointer operator->() { return &(this->row); } CONSTEXPR_14 pointer operator->() const { return const_cast(&(this->row)); } iterator& operator++(); /**< Pre-increment iterator */ iterator operator++(int); /**< Post-increment iterator */ /** Returns true if iterators were constructed from the same CSVReader * and point to the same row */ CONSTEXPR bool operator==(const iterator& other) const noexcept { return (this->daddy == other.daddy) && (this->i == other.i); } CONSTEXPR bool operator!=(const iterator& other) const noexcept { return !operator==(other); } private: CSVReader * daddy = nullptr; // Pointer to parent CSVRow row; // Current row size_t i = 0; // Index of current row }; /** @name Constructors * Constructors for iterating over large files and parsing in-memory sources. */ ///@{ /** @brief Construct CSVReader from filename. * * Native builds use CODE PATH 1 of 2: MmapParser with mio for maximum performance. * Emscripten builds fall back to the stream-based implementation because mmap is unavailable. * * @note On native builds, bugs can exist in this path independently of the stream path * @note When writing tests that validate I/O behavior, test both filename and stream constructors * @see StreamParser for the stream-based alternative */ CSVReader(csv::string_view filename, CSVFormat format = CSVFormat::guess_csv()); /** @brief Construct CSVReader from std::istream * * Uses StreamParser. On native builds this is CODE PATH 2 of 2 and remains independent * from the filename-based mmap path. On Emscripten, the filename constructor also funnels * through this implementation. * * @tparam TStream An input stream deriving from `std::istream` * @note Delimiter/header guessing is still available by default via CSVFormat::guess_csv(). * For deterministic parsing of known dialects, pass an explicit CSVFormat. * @note On native builds, tests that validate I/O behavior should cover both constructors * @see MmapParser for the memory-mapped alternative */ template::value, int> = 0> CSVReader(TStream &source, CSVFormat format = CSVFormat::guess_csv()) : _format(format) { this->init_from_stream(source, format); } /** @brief Construct CSVReader from an owned std::istream * * This is an opt-in safety switch for stream lifetime management. * CSVReader takes ownership and guarantees the stream outlives parsing. */ CSVReader(std::unique_ptr source, const CSVFormat& format = CSVFormat::guess_csv()) : _format(format), owned_stream(std::move(source)) { if (!this->owned_stream) { throw std::invalid_argument("CSVReader requires a non-null stream"); } this->init_from_stream(*this->owned_stream, format); } ///@} CSVReader(const CSVReader&) = delete; ///< Not copyable CSVReader& operator=(const CSVReader&) = delete; ///< Not copyable /** Move constructor. * * Required so C++11 builds can return CSVReader by value from helpers like * csv::parse()/csv::parse_unsafe(), where copy elision is not guaranteed. * * Any active worker on the source is joined before moving parser state to * avoid a thread continuing to run against the source object's address. */ CSVReader(CSVReader&& other) noexcept : _format(std::move(other._format)), col_names(std::move(other.col_names)), parser(std::move(other.parser)), records(std::move(other.records)), owned_stream(std::move(other.owned_stream)), n_cols(other.n_cols), _n_rows(other._n_rows), header_trimmed(other.header_trimmed), _chunk_size(other._chunk_size), _read_requested(other._read_requested), read_csv_exception(other.take_read_csv_exception()) { #if CSV_ENABLE_THREADS if (other.read_csv_worker.joinable()) { other.read_csv_worker.join(); } #endif other.n_cols = 0; other._n_rows = 0; other.header_trimmed = false; other._read_requested = false; other._chunk_size = internals::ITERATION_CHUNK_SIZE; } /** Move assignment. * * Joins active workers on both sides before transferring parser state. */ CSVReader& operator=(CSVReader&& other) noexcept { if (this == &other) { return *this; } #if CSV_ENABLE_THREADS if (this->read_csv_worker.joinable()) { this->read_csv_worker.join(); } if (other.read_csv_worker.joinable()) { other.read_csv_worker.join(); } #endif this->_format = std::move(other._format); this->col_names = std::move(other.col_names); this->parser = std::move(other.parser); this->records = std::move(other.records); this->owned_stream = std::move(other.owned_stream); this->n_cols = other.n_cols; this->_n_rows = other._n_rows; this->header_trimmed = other.header_trimmed; this->_chunk_size = other._chunk_size; this->_read_requested = other._read_requested; this->read_csv_exception = other.take_read_csv_exception(); other.n_cols = 0; other._n_rows = 0; other.header_trimmed = false; other._read_requested = false; other._chunk_size = internals::ITERATION_CHUNK_SIZE; return *this; } ~CSVReader() { #if CSV_ENABLE_THREADS if (this->read_csv_worker.joinable()) { this->read_csv_worker.join(); } #endif } /** @name Retrieving CSV Rows */ ///@{ bool read_row(CSVRow &row); iterator begin(); CSV_CONST iterator end() const noexcept; /** Returns true if we have reached end of file */ bool eof() const noexcept { return this->parser->eof(); } ///@} /** @name CSV Metadata */ ///@{ CSVFormat get_format() const; std::vector get_col_names() const; int index_of(csv::string_view col_name) const; ///@} /** @name CSV Metadata: Attributes */ ///@{ /** Whether or not the file or stream contains valid CSV rows, * not including the header. * * @note Gives an accurate answer regardless of when it is called. * */ CONSTEXPR bool empty() const noexcept { return this->n_rows() == 0; } /** Retrieves the number of rows that have been read so far */ CONSTEXPR size_t n_rows() const noexcept { return this->_n_rows; } /** Whether or not CSV was prefixed with a UTF-8 bom */ bool utf8_bom() const noexcept { return this->parser->utf8_bom(); } ///@} protected: /** * \defgroup csv_internal CSV Parser Internals * @brief Internals of CSVReader. Only maintainers and those looking to * extend the parser should read this. * @{ */ /** Sets this reader's column names and associated data */ void set_col_names(const std::vector&); /** @name CSV Settings **/ ///@{ CSVFormat _format; ///@} /** @name Parser State */ ///@{ /** Pointer to a object containing column information */ internals::ColNamesPtr col_names = std::make_shared(); /** Helper class which actually does the parsing */ std::unique_ptr parser = nullptr; /** Queue of parsed CSV rows */ std::unique_ptr records{new RowCollection(100)}; /** * Optional owned stream used by two paths: * 1) Emscripten filename-constructor fallback to stream parsing * 2) Opt-in ownership constructor taking std::unique_ptr */ std::unique_ptr owned_stream = nullptr; size_t n_cols = 0; /**< The number of columns in this CSV */ size_t _n_rows = 0; /**< How many rows (minus header) have been read so far */ /** @name Multi-Threaded File Reading Functions */ ///@{ bool read_csv(size_t bytes = internals::ITERATION_CHUNK_SIZE); ///@} /**@}*/ private: /** Whether or not rows before header were trimmed */ bool header_trimmed = false; /** @name Multi-Threaded File Reading: Flags and State */ ///@{ #if CSV_ENABLE_THREADS std::thread read_csv_worker; /**< Worker thread for read_csv() */ #endif size_t _chunk_size = internals::ITERATION_CHUNK_SIZE; /**< Current chunk size in bytes */ bool _read_requested = false; /**< Flag to detect infinite read loops (Issue #218) */ ///@} /** If the worker thread throws, store it here and rethrow on the consumer thread. */ std::exception_ptr read_csv_exception = nullptr; #if CSV_ENABLE_THREADS std::mutex read_csv_exception_lock; #endif void set_read_csv_exception(std::exception_ptr eptr) { #if CSV_ENABLE_THREADS std::lock_guard lock(this->read_csv_exception_lock); #endif this->read_csv_exception = std::move(eptr); } std::exception_ptr take_read_csv_exception() { #if CSV_ENABLE_THREADS std::lock_guard lock(this->read_csv_exception_lock); #endif auto eptr = this->read_csv_exception; this->read_csv_exception = nullptr; return eptr; } void rethrow_read_csv_exception_if_any() { if (auto eptr = this->take_read_csv_exception()) { std::rethrow_exception(eptr); } } template::value, int> = 0> void init_from_stream(TStream& source, CSVFormat format) { // Read a head buffer without rewinding. Works with non-seekable streams // (pipes, decompression filters). The buffer is passed to StreamParser // as its initial leftover_ so those bytes are parsed as the first chunk. auto head = internals::read_head_buffer(source); using Parser = internals::StreamParser; // Apply chunk size from format before any reading occurs this->_chunk_size = format.get_chunk_size(); if (format.guess_delim()) { auto guess_result = internals::_guess_format(head, format.possible_delimiters); format.delimiter(guess_result.delim); // Only override header if user hasn't explicitly called no_header() // Note: column_names() also sets header=-1, but it populates col_names, // so we can distinguish: no_header() means header=-1 && col_names.empty() if (format.header != -1 || !format.col_names.empty()) { format.header = guess_result.header_row; } this->_format = format; } if (!format.col_names.empty()) { this->set_col_names(format.col_names); } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4316) #endif this->parser = std::unique_ptr( new Parser(source, format, col_names, std::move(head))); // For C++11 #ifdef _MSC_VER #pragma warning(pop) #endif this->initial_read(); } /** Read initial chunk to get metadata */ void initial_read() { #if CSV_ENABLE_THREADS this->read_csv_worker = std::thread(&CSVReader::read_csv, this, this->_chunk_size); this->read_csv_worker.join(); #else this->read_csv(this->_chunk_size); #endif this->rethrow_read_csv_exception_if_any(); } void trim_header(); }; } namespace csv { namespace internals { template class is_hashable { private: template static auto test(int) -> decltype( std::hash{}(std::declval()), std::true_type{} ); template static std::false_type test(...); public: static constexpr bool value = decltype(test(0))::value; }; template class is_equality_comparable { private: template static auto test(int) -> decltype( std::declval() == std::declval(), std::true_type{} ); template static std::false_type test(...); public: static constexpr bool value = decltype(test(0))::value; }; } /** Allows configuration of DataFrame behavior. */ class DataFrameOptions { public: DataFrameOptions() = default; /** Policy for handling duplicate keys when creating a keyed DataFrame */ enum class DuplicateKeyPolicy { THROW, // Throw an error if a duplicate key is encountered OVERWRITE, // Overwrite the existing value with the new value KEEP_FIRST // Ignore the new value and keep the existing value }; DataFrameOptions& set_duplicate_key_policy(DuplicateKeyPolicy value) { this->duplicate_key_policy = value; return *this; } DuplicateKeyPolicy get_duplicate_key_policy() const { return this->duplicate_key_policy; } DataFrameOptions& set_key_column(const std::string& value) { this->key_column = value; return *this; } const std::string& get_key_column() const { return this->key_column; } DataFrameOptions& set_throw_on_missing_key(bool value) { this->throw_on_missing_key = value; return *this; } bool get_throw_on_missing_key() const { return this->throw_on_missing_key; } private: std::string key_column; DuplicateKeyPolicy duplicate_key_policy = DuplicateKeyPolicy::OVERWRITE; /** Whether to throw an error if a key column value is missing when creating a keyed DataFrame */ bool throw_on_missing_key = true; }; /** * Proxy class that wraps a CSVRow and intercepts field access to check for edits. * Provides transparent access to both original and edited cell values. */ template class DataFrameRow { public: /** Default constructor (creates an unbound proxy). */ DataFrameRow() : row(nullptr), row_edits(nullptr), key_ptr(nullptr) {} /** Construct a DataFrameRow wrapper. */ DataFrameRow( const CSVRow* _row, const std::unordered_map* _edits, const KeyType* _key ) : row(_row), row_edits(_edits), key_ptr(_key) {} /** * Access a field by column name, checking edits first. * * @param col Column name * @return CSVField representing the field value (edited if present, otherwise original) */ CSVField operator[](const std::string& col) const { // Find column index by searching column names auto col_names = row->get_col_names(); auto it = std::find(col_names.begin(), col_names.end(), col); if (it == col_names.end()) { // Column not found, let row handle the error return (*row)[col]; } size_t col_index = std::distance(col_names.begin(), it); if (row_edits) { auto edit_it = row_edits->find(col_index); if (edit_it != row_edits->end()) { return CSVField(csv::string_view(edit_it->second)); } } return (*row)[col]; } /** Access a field by position (positional access never checks edits). */ CSVField operator[](size_t n) const { return (*row)[n]; } /** Get the number of fields in the row. */ size_t size() const { return row->size(); } /** Check if the row is empty. */ bool empty() const { return row->empty(); } /** Get column names. */ std::vector get_col_names() const { return row->get_col_names(); } /** Get the underlying CSVRow for compatibility. */ const CSVRow& get_underlying_row() const { return *row; } /** Get the key for this row (only valid for keyed DataFrames). */ const KeyType& get_key() const { return *key_ptr; } /** Convert to vector of strings for CSVWriter compatibility. */ operator std::vector() const { std::vector result; result.reserve(row->size()); for (size_t i = 0; i < row->size(); i++) { // Check if this column has an edit if (row_edits) { auto it = row_edits->find(i); if (it != row_edits->end()) { result.push_back(it->second); continue; } } // Use original value result.push_back((*row)[i].get()); } return result; } /** Convert to JSON. */ std::string to_json(const std::vector& subset = {}) const { return row->to_json(subset); } /** Convert to JSON array. */ std::string to_json_array(const std::vector& subset = {}) const { return row->to_json_array(subset); } #ifdef CSV_HAS_CXX20 /** Convert this DataFrameRow into a std::ranges::input_range of string_views, * respecting the sparse overlay (edited values take precedence). */ auto to_sv_range() const { return std::views::iota(size_t{0}, this->size()) | std::views::transform([this](size_t i) { // Check if this column has an edit if (row_edits) { auto it = row_edits->find(i); if (it != row_edits->end()) { return csv::string_view(it->second); } } // Use original value return this->get_underlying_row().get_field(i); }); } #endif private: const CSVRow* row; const std::unordered_map* row_edits; const KeyType* key_ptr; }; template class DataFrame { public: /** Type alias for internal row storage: pair of key and CSVRow. */ using row_entry = std::pair; /** Row-wise iterator over DataFrameRow entries. Provides access to rows with edit support. */ class iterator { public: using value_type = DataFrameRow; using difference_type = std::ptrdiff_t; using pointer = const DataFrameRow*; using reference = const DataFrameRow&; using iterator_category = std::random_access_iterator_tag; iterator() = default; iterator( typename std::vector::iterator it, const std::unordered_map>* edits ) : iter(it), edits_map(edits) {} reference operator*() const { const std::unordered_map* row_edits = nullptr; if (edits_map) { auto it = edits_map->find(iter->first); if (it != edits_map->end()) { row_edits = &it->second; } } cached_row = DataFrameRow(&iter->second, row_edits, &iter->first); return cached_row; } pointer operator->() const { // Ensure cached_row is populated operator*(); return &cached_row; } iterator& operator++() { ++iter; return *this; } iterator operator++(int) { auto tmp = *this; ++iter; return tmp; } iterator& operator--() { --iter; return *this; } iterator operator--(int) { auto tmp = *this; --iter; return tmp; } iterator operator+(difference_type n) const { return iterator(iter + n, edits_map); } iterator operator-(difference_type n) const { return iterator(iter - n, edits_map); } difference_type operator-(const iterator& other) const { return iter - other.iter; } bool operator==(const iterator& other) const { return iter == other.iter; } bool operator!=(const iterator& other) const { return iter != other.iter; } private: typename std::vector::iterator iter; const std::unordered_map>* edits_map = nullptr; mutable DataFrameRow cached_row; }; /** Row-wise const iterator over DataFrameRow entries. Provides read-only access to rows with edit support. */ class const_iterator { public: using value_type = DataFrameRow; using difference_type = std::ptrdiff_t; using pointer = const DataFrameRow*; using reference = const DataFrameRow&; using iterator_category = std::random_access_iterator_tag; const_iterator() = default; const_iterator( typename std::vector::const_iterator it, const std::unordered_map>* edits ) : iter(it), edits_map(edits) {} reference operator*() const { const std::unordered_map* row_edits = nullptr; if (edits_map) { auto it = edits_map->find(iter->first); if (it != edits_map->end()) { row_edits = &it->second; } } cached_row = DataFrameRow(&iter->second, row_edits, &iter->first); return cached_row; } pointer operator->() const { // Ensure cached_row is populated operator*(); return &cached_row; } const_iterator& operator++() { ++iter; return *this; } const_iterator operator++(int) { auto tmp = *this; ++iter; return tmp; } const_iterator& operator--() { --iter; return *this; } const_iterator operator--(int) { auto tmp = *this; --iter; return tmp; } const_iterator operator+(difference_type n) const { return const_iterator(iter + n, edits_map); } const_iterator operator-(difference_type n) const { return const_iterator(iter - n, edits_map); } difference_type operator-(const const_iterator& other) const { return iter - other.iter; } bool operator==(const const_iterator& other) const { return iter == other.iter; } bool operator!=(const const_iterator& other) const { return iter != other.iter; } private: typename std::vector::const_iterator iter; const std::unordered_map>* edits_map = nullptr; mutable DataFrameRow cached_row; }; static_assert( internals::is_hashable::value, "DataFrame requires KeyType to be hashable (std::hash specialization required)." ); static_assert( internals::is_equality_comparable::value, "DataFrame requires KeyType to be equality comparable (operator== required)." ); static_assert( std::is_default_constructible::value, "DataFrame requires KeyType to be default-constructible." ); using DuplicateKeyPolicy = DataFrameOptions::DuplicateKeyPolicy; /** Construct an empty DataFrame. */ DataFrame() = default; /** * Construct an unkeyed DataFrame from a CSV reader. * Rows are accessible by position only. */ explicit DataFrame(CSVReader& reader) { this->init_unkeyed_from_reader(reader); } /** * Construct a keyed DataFrame from a CSV reader with options. * * @param reader CSV reader to consume * @param options Configuration including key column and duplicate policies * @throws std::runtime_error if key column is empty or not found */ explicit DataFrame(CSVReader& reader, const DataFrameOptions& options) { this->init_from_reader(reader, options); } /** * Construct a keyed DataFrame directly from a CSV file. * * @param filename Path to the CSV file * @param options Configuration including key column and duplicate policies * @param format CSV format specification (defaults to auto-detection) * @throws std::runtime_error if key column is empty or not found */ DataFrame( csv::string_view filename, const DataFrameOptions& options, CSVFormat format = CSVFormat::guess_csv() ) { CSVReader reader(filename, format); this->init_from_reader(reader, options); } /** * Construct a keyed DataFrame using a column name as the key. * * @param reader CSV reader to consume * @param _key_column Name of the column to use as the key * @param policy How to handle duplicate keys (default: OVERWRITE) * @param throw_on_missing_key Whether to throw if a key value cannot be parsed (default: true) * @throws std::runtime_error if key column is empty or not found */ DataFrame( CSVReader& reader, const std::string& _key_column, DuplicateKeyPolicy policy = DuplicateKeyPolicy::OVERWRITE, bool throw_on_missing_key = true ) : DataFrame( reader, DataFrameOptions() .set_key_column(_key_column) .set_duplicate_key_policy(policy) .set_throw_on_missing_key(throw_on_missing_key) ) {} /** * Construct a keyed DataFrame using a custom key function. * * @param reader CSV reader to consume * @param key_func Function that extracts a key from each row * @param policy How to handle duplicate keys (default: OVERWRITE) * @throws std::runtime_error if policy is THROW and duplicate keys are encountered */ template< typename KeyFunc, typename ResultType = invoke_result_t, csv::enable_if_t::value, int> = 0 > DataFrame( CSVReader& reader, KeyFunc key_func, DuplicateKeyPolicy policy = DuplicateKeyPolicy::OVERWRITE ) : col_names_(reader.get_col_names()) { this->is_keyed = true; this->build_from_key_function(reader, key_func, policy); } /** * Construct a keyed DataFrame using a custom key function with options. * * @param reader CSV reader to consume * @param key_func Function that extracts a key from each row * @param options Configuration for duplicate key policy */ template< typename KeyFunc, typename ResultType = invoke_result_t, csv::enable_if_t::value, int> = 0 > DataFrame( CSVReader& reader, KeyFunc key_func, const DataFrameOptions& options ) : DataFrame(reader, key_func, options.get_duplicate_key_policy()) {} /** Get the number of rows in the DataFrame. */ size_t size() const noexcept { return rows.size(); } /** Check if the DataFrame is empty (has no rows). */ bool empty() const noexcept { return rows.empty(); } /** Get the number of rows in the DataFrame. Alias for size(). */ size_t n_rows() const noexcept { return rows.size(); } /** Get the number of columns in the DataFrame. */ size_t n_cols() const noexcept { return col_names_.size(); } /** * Check if a column exists in the DataFrame. * * @param name Column name to check * @return true if the column exists, false otherwise */ bool has_column(const std::string& name) const { return std::find(col_names_.begin(), col_names_.end(), name) != col_names_.end(); } /** * Get the index of a column by name. * * @param name Column name to find * @return Column index (0-based) or CSV_NOT_FOUND if not found */ int index_of(const std::string& name) const { auto it = std::find(col_names_.begin(), col_names_.end(), name); if (it == col_names_.end()) return CSV_NOT_FOUND; return static_cast(std::distance(col_names_.begin(), it)); } /** Get the column names in order. */ const std::vector& columns() const noexcept { return col_names_; } /** Get the name of the key column (empty string if unkeyed). */ const std::string& key_name() const noexcept { return key_column; } /** * Access a row by position (unchecked). * * @note Disabled when KeyType is an integral type to prevent ambiguity with * operator[](const KeyType&). Use iloc() for positional access on * integer-keyed DataFrames. * * @param i Row index (0-based) * @return DataFrameRow proxy with edit support * @throws std::out_of_range if index is out of bounds (via std::vector::at) */ template::value, int> = 0> DataFrameRow operator[](size_t i) { static_assert(std::is_same::value, "Do not explicitly instantiate this template. Use iloc() for positional access."); return this->iloc(i); } /** Access a row by position (unchecked, const version). * Disabled when KeyType is an integral type — use iloc() instead. */ template::value, int> = 0> DataFrameRow operator[](size_t i) const { static_assert(std::is_same::value, "Do not explicitly instantiate this template. Use iloc() for positional access."); return this->iloc(i); } /** * Access a row by position with bounds checking. * * @param i Row index (0-based) * @return DataFrameRow proxy with edit support * @throws std::out_of_range if index is out of bounds */ DataFrameRow at(size_t i) { const std::unordered_map* row_edits = nullptr; if (is_keyed) { auto it = edits.find(rows.at(i).first); if (it != edits.end()) row_edits = &it->second; } return DataFrameRow(&rows.at(i).second, row_edits, &rows.at(i).first); } /** Access a row by position with bounds checking (const version). */ DataFrameRow at(size_t i) const { const std::unordered_map* row_edits = nullptr; if (is_keyed) { auto it = edits.find(rows.at(i).first); if (it != edits.end()) row_edits = &it->second; } return DataFrameRow(&rows.at(i).second, row_edits, &rows.at(i).first); } /** * Access a row by its key. * * @param key The row key to look up * @return DataFrameRow proxy with edit support * @throws std::runtime_error if the DataFrame was not created with a key column * @throws std::out_of_range if the key is not found */ DataFrameRow operator[](const KeyType& key) { this->require_keyed_frame(); auto position = this->position_of(key); const std::unordered_map* row_edits = nullptr; auto it = edits.find(key); if (it != edits.end()) row_edits = &it->second; return DataFrameRow(&rows[position].second, row_edits, &rows[position].first); } /** Access a row by its key (const version). */ DataFrameRow operator[](const KeyType& key) const { this->require_keyed_frame(); auto position = this->position_of(key); const std::unordered_map* row_edits = nullptr; auto it = edits.find(key); if (it != edits.end()) row_edits = &it->second; return DataFrameRow(&rows[position].second, row_edits, &rows[position].first); } /** * Access a row by position (iloc-style, pandas naming). * * @param i Row index (0-based) * @return DataFrameRow proxy with edit support * @throws std::out_of_range if index is out of bounds */ DataFrameRow iloc(size_t i) { const std::unordered_map* row_edits = nullptr; if (is_keyed) { auto it = edits.find(rows.at(i).first); if (it != edits.end()) row_edits = &it->second; } return DataFrameRow(&rows.at(i).second, row_edits, &rows.at(i).first); } /** Access a row by position (const version). */ DataFrameRow iloc(size_t i) const { const std::unordered_map* row_edits = nullptr; if (is_keyed) { auto it = edits.find(rows.at(i).first); if (it != edits.end()) row_edits = &it->second; } return DataFrameRow(&rows.at(i).second, row_edits, &rows.at(i).first); } /** * Attempt to access a row by position without throwing. * * @param i Row index (0-based) * @param out Output parameter that receives the DataFrameRow if found * @return true if the row exists, false otherwise */ bool try_get(size_t i, DataFrameRow& out) { if (i >= rows.size()) { return false; } const std::unordered_map* row_edits = nullptr; if (is_keyed) { auto it = edits.find(rows[i].first); if (it != edits.end()) row_edits = &it->second; } out = DataFrameRow(&rows[i].second, row_edits, &rows[i].first); return true; } /** Attempt to access a row by position without throwing (const version). */ bool try_get(size_t i, DataFrameRow& out) const { if (i >= rows.size()) { return false; } const std::unordered_map* row_edits = nullptr; if (is_keyed) { auto it = edits.find(rows[i].first); if (it != edits.end()) row_edits = &it->second; } out = DataFrameRow(&rows[i].second, row_edits, &rows[i].first); return true; } /** * Get the key for a row at a given position. * * @param i Row index (0-based) * @return Reference to the key * @throws std::runtime_error if the DataFrame was not created with a key column * @throws std::out_of_range if index is out of bounds */ const KeyType& key_at(size_t i) const { this->require_keyed_frame(); return rows.at(i).first; } /** * Check if a key exists in the DataFrame. * * @param key The key to check * @return true if the key exists, false otherwise * @throws std::runtime_error if the DataFrame was not created with a key column */ bool contains(const KeyType& key) const { this->require_keyed_frame(); this->ensure_key_index(); return key_index->find(key) != key_index->end(); } /** * Access a row by its key with bounds checking. * * @param key The row key to look up * @return DataFrameRow proxy with edit support * @throws std::runtime_error if the DataFrame was not created with a key column * @throws std::out_of_range if the key is not found */ DataFrameRow at(const KeyType& key) { this->require_keyed_frame(); auto position = this->position_of(key); const std::unordered_map* row_edits = nullptr; auto it = edits.find(key); if (it != edits.end()) row_edits = &it->second; return DataFrameRow(&rows.at(position).second, row_edits, &rows.at(position).first); } /** Access a row by its key with bounds checking (const version). */ DataFrameRow at(const KeyType& key) const { this->require_keyed_frame(); auto position = this->position_of(key); const std::unordered_map* row_edits = nullptr; auto it = edits.find(key); if (it != edits.end()) row_edits = &it->second; return DataFrameRow(&rows.at(position).second, row_edits, &rows.at(position).first); } /** * Attempt to access a row by key without throwing. * * @param key The row key to look up * @param out Output parameter that receives the DataFrameRow if found * @return true if the key exists, false otherwise * @throws std::runtime_error if the DataFrame was not created with a key column */ bool try_get(const KeyType& key, DataFrameRow& out) { this->require_keyed_frame(); this->ensure_key_index(); auto it = key_index->find(key); if (it == key_index->end()) { return false; } const std::unordered_map* row_edits = nullptr; auto edit_it = edits.find(key); if (edit_it != edits.end()) row_edits = &edit_it->second; out = DataFrameRow(&rows[it->second].second, row_edits, &rows[it->second].first); return true; } /** Attempt to access a row by key without throwing (const version). */ bool try_get(const KeyType& key, DataFrameRow& out) const { this->require_keyed_frame(); this->ensure_key_index(); auto it = key_index->find(key); if (it == key_index->end()) { return false; } const std::unordered_map* row_edits = nullptr; auto edit_it = edits.find(key); if (edit_it != edits.end()) row_edits = &edit_it->second; out = DataFrameRow(&rows[it->second].second, row_edits, &rows[it->second].first); return true; } /** * Get a cell value as a string, accounting for edits. * * @param key The row key * @param column The column name * @return Cell value as a string (edited value if present, otherwise original) * @throws std::runtime_error if the DataFrame was not created with a key column * @throws std::out_of_range if the key is not found */ std::string get(const KeyType& key, const std::string& column) const { this->require_keyed_frame(); auto col_names = (*this)[key].get_col_names(); auto col_it = std::find(col_names.begin(), col_names.end(), column); if (col_it == col_names.end()) { throw std::out_of_range("Column '" + column + "' not found"); } size_t col_idx = std::distance(col_names.begin(), col_it); auto row_edits = this->edits.find(key); if (row_edits != this->edits.end()) { auto value = row_edits->second.find(col_idx); if (value != row_edits->second.end()) { return value->second; } } return (*this)[key][column].template get(); } /** * Set a cell value (stored in edit overlay). * * @param key The row key * @param column The column name * @param value The new value as a string * @throws std::runtime_error if the DataFrame was not created with a key column * @throws std::out_of_range if the key is not found */ void set(const KeyType& key, const std::string& column, const std::string& value) { this->require_keyed_frame(); size_t row_idx = this->position_of(key); // Find column index auto col_names = rows[row_idx].second.get_col_names(); auto it = std::find(col_names.begin(), col_names.end(), column); if (it == col_names.end()) { throw std::out_of_range("Column '" + column + "' not found"); } size_t col_idx = std::distance(col_names.begin(), it); edits[key][col_idx] = value; } /** * Remove a row by its key. * * @param key The row key to remove * @return true if the row was removed, false if not found * @throws std::runtime_error if the DataFrame was not created with a key column */ bool erase_row(const KeyType& key) { this->require_keyed_frame(); this->ensure_key_index(); auto it = key_index->find(key); if (it == key_index->end()) { return false; } rows.erase(rows.begin() + it->second); edits.erase(key); this->invalidate_key_index(); return true; } /** * Remove a row by its position. * * @param i Row index (0-based) * @return true if the row was removed, false if index out of bounds */ bool erase_row_at(size_t i) { if (i >= rows.size()) return false; if (is_keyed) edits.erase(rows[i].first); rows.erase(rows.begin() + i); this->invalidate_key_index(); return true; } /** * Set a cell value by position (stored in edit overlay). * * @param i Row index (0-based) * @param column The column name * @param value The new value as a string * @throws std::runtime_error if the DataFrame was not created with a key column * @throws std::out_of_range if index is out of bounds */ void set_at(size_t i, const std::string& column, const std::string& value) { if (!is_keyed) { throw std::runtime_error("This DataFrame was created without a key column."); } if (i >= rows.size()) { throw std::out_of_range("Row index out of bounds."); } // Find column index auto col_names = rows[i].second.get_col_names(); auto it = std::find(col_names.begin(), col_names.end(), column); if (it == col_names.end()) { throw std::out_of_range("Column '" + column + "' not found"); } size_t col_idx = std::distance(col_names.begin(), it); edits[rows[i].first][col_idx] = value; } /** * Extract all values from a column with type conversion. * Accounts for edited values in the overlay. * * @tparam T Target type for conversion (default: std::string) * @param name Column name * @return Vector of values converted to type T * @throws std::runtime_error if column is not found */ template std::vector column(const std::string& name) const { auto col_it = std::find(col_names_.begin(), col_names_.end(), name); if (col_it == col_names_.end()) { throw std::runtime_error("Column not found: " + name); } size_t col_idx = std::distance(col_names_.begin(), col_it); std::vector values; values.reserve(rows.size()); for (const auto& entry : rows) { auto row_edits = this->edits.find(entry.first); if (row_edits != this->edits.end()) { auto value = row_edits->second.find(col_idx); if (value != row_edits->second.end()) { // Reuse CSVField parsing/validation on edited string values. CSVField edited_field(csv::string_view(value->second)); values.push_back(edited_field.template get()); continue; } } values.push_back(entry.second[name].template get()); } return values; } /** * Group row positions using an arbitrary grouping function. * * @tparam GroupFunc Callable that takes a CSVRow and returns a hashable key * @param group_func Function to extract group key from each row * @return Map of group key -> vector of row indices belonging to that group */ template< typename GroupFunc, typename GroupKey = invoke_result_t, csv::enable_if_t< internals::is_hashable::value && internals::is_equality_comparable::value, int > = 0 > std::unordered_map> group_by(GroupFunc group_func) const { std::unordered_map> grouped; for (size_t i = 0; i < rows.size(); i++) { GroupKey group_key = group_func(rows[i].second); grouped[group_key].push_back(i); } return grouped; } /** * Group row positions by the value of a column. * * @param name Column to group by * @param use_edits If true, use edited values when present (default: true) * @return Map of column value -> vector of row indices with that value * @throws std::runtime_error if column is not found */ std::unordered_map> group_by( const std::string& name, bool use_edits = true ) const { auto col_it = std::find(col_names_.begin(), col_names_.end(), name); if (col_it == col_names_.end()) { throw std::runtime_error("Column not found: " + name); } size_t col_idx = std::distance(col_names_.begin(), col_it); std::unordered_map> grouped; for (size_t i = 0; i < rows.size(); i++) { std::string group_key; bool has_group_key = false; if (use_edits) { auto row_edits = this->edits.find(rows[i].first); if (row_edits != this->edits.end()) { auto edited_value = row_edits->second.find(col_idx); if (edited_value != row_edits->second.end()) { group_key = edited_value->second; has_group_key = true; } } } if (!has_group_key) { group_key = rows[i].second[name].template get(); } grouped[group_key].push_back(i); } return grouped; } /** Get iterator to the first row. */ iterator begin() { return iterator(rows.begin(), is_keyed ? &edits : nullptr); } /** Get iterator past the last row. */ iterator end() { return iterator(rows.end(), is_keyed ? &edits : nullptr); } /** Get const iterator to the first row. */ const_iterator begin() const { return const_iterator(rows.begin(), is_keyed ? &edits : nullptr); } /** Get const iterator past the last row. */ const_iterator end() const { return const_iterator(rows.end(), is_keyed ? &edits : nullptr); } /** Get const iterator to the first row (explicit). */ const_iterator cbegin() const { return const_iterator(rows.begin(), is_keyed ? &edits : nullptr); } /** Get const iterator past the last row (explicit). */ const_iterator cend() const { return const_iterator(rows.end(), is_keyed ? &edits : nullptr); } private: /** Name of the key column (empty if unkeyed). */ std::string key_column; /** Whether this DataFrame was created with a key. */ bool is_keyed = false; /** Column names in order. */ std::vector col_names_; /** Internal storage: vector of (key, row) pairs. */ std::vector rows; /** Lazily-built index mapping keys to row positions (mutable for const methods). */ mutable std::unique_ptr> key_index; /** * Edit overlay: key -> column -> value. * Sparse storage for cell modifications without mutating original row data. */ std::unordered_map> edits; /** Initialize an unkeyed DataFrame from a CSV reader. */ void init_unkeyed_from_reader(CSVReader& reader) { this->col_names_ = reader.get_col_names(); for (auto& row : reader) { rows.push_back(row_entry{KeyType(), row}); } } /** Initialize a keyed DataFrame from a CSV reader using column-based key extraction. */ void init_from_reader(CSVReader& reader, const DataFrameOptions& options) { this->is_keyed = true; this->key_column = options.get_key_column(); this->col_names_ = reader.get_col_names(); if (key_column.empty()) { throw std::runtime_error("Key column cannot be empty."); } if (std::find(col_names_.begin(), col_names_.end(), key_column) == col_names_.end()) { throw std::runtime_error("Key column not found: " + key_column); } const bool throw_on_missing_key = options.get_throw_on_missing_key(); this->build_from_key_function( reader, [this, throw_on_missing_key](const CSVRow& row) -> KeyType { try { return row[this->key_column].template get(); } catch (const std::exception& e) { if (throw_on_missing_key) { throw std::runtime_error("Error retrieving key column value: " + std::string(e.what())); } return KeyType(); } }, options.get_duplicate_key_policy() ); } /** Build keyed DataFrame using a custom key extraction function. */ template void build_from_key_function( CSVReader& reader, KeyFunc key_func, DuplicateKeyPolicy policy ) { std::unordered_map key_to_pos; for (auto& row : reader) { KeyType key = key_func(row); auto existing = key_to_pos.find(key); if (existing != key_to_pos.end()) { if (policy == DuplicateKeyPolicy::THROW) { throw std::runtime_error("Duplicate key encountered."); } if (policy == DuplicateKeyPolicy::OVERWRITE) { rows[existing->second].second = row; } continue; } rows.push_back(row_entry{key, row}); key_to_pos[key] = rows.size() - 1; } } /** Validate that this DataFrame was created with a key column. */ void require_keyed_frame() const { if (!is_keyed) { throw std::runtime_error("This DataFrame was created without a key column."); } } /** Invalidate the lazy key index after structural changes. */ void invalidate_key_index() { key_index.reset(); } /** Build the key index if it doesn't exist (lazy initialization). */ void ensure_key_index() const { if (key_index) { return; } key_index = std::unique_ptr>( new std::unordered_map() ); for (size_t i = 0; i < rows.size(); i++) { (*key_index)[rows[i].first] = i; } } /** Find the position of a key in the rows vector. */ size_t position_of(const KeyType& key) const { this->ensure_key_index(); auto it = key_index->find(key); if (it == key_index->end()) { throw std::out_of_range("Key not found."); } return it->second; } }; } /** @file * Calculates statistics from CSV files */ #include #include #include namespace csv { /** Class for calculating statistics from CSV files and in-memory sources * * **Example** * \include programs/csv_stats.cpp * */ class CSVStat { public: using FreqCount = std::unordered_map; using TypeCount = std::unordered_map; std::vector get_mean() const; std::vector get_variance() const; std::vector get_mins() const; std::vector get_maxes() const; std::vector get_counts() const; std::vector get_dtypes() const; std::vector get_col_names() const { return this->reader.get_col_names(); } CSVStat(csv::string_view filename, CSVFormat format = CSVFormat::guess_csv()); CSVStat(std::stringstream& source, CSVFormat format = CSVFormat()); private: // An array of rolling averages // Each index corresponds to the rolling mean for the column at said index std::vector rolling_means; std::vector rolling_vars; std::vector mins; std::vector maxes; std::vector counts; std::vector dtypes; std::vector n; // Statistic calculators void variance(const long double&, const size_t&); void count(CSVField&, const size_t&); void min_max(const long double&, const size_t&); void dtype(CSVField&, const size_t&); void calc(); void calc_chunk(); void calc_worker(const size_t&); CSVReader reader; std::deque records = {}; }; } #include #include #include namespace csv { namespace internals { /** * streambuf adapter over csv::string_view with no data copy. * * The underlying memory must remain valid and immutable for the entire * lifetime of this stream object. */ class StringViewStreamBuf : public std::streambuf { public: explicit StringViewStreamBuf(csv::string_view view) { char* begin = const_cast(view.data()); char* end = begin + view.size(); this->setg(begin, begin, end); } protected: std::streamsize xsgetn(char* s, std::streamsize count) override { const std::streamsize avail = this->egptr() - this->gptr(); const std::streamsize n = std::min(avail, count); if (n > 0) { std::memcpy(s, this->gptr(), static_cast(n)); this->gbump(static_cast(n)); } return n; } pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in) override { if (!(which & std::ios_base::in)) { return pos_type(off_type(-1)); } const auto begin = this->eback(); const auto curr = this->gptr(); const auto end = this->egptr(); off_type base = 0; if (dir == std::ios_base::beg) { base = 0; } else if (dir == std::ios_base::cur) { base = static_cast(curr - begin); } else if (dir == std::ios_base::end) { base = static_cast(end - begin); } else { return pos_type(off_type(-1)); } const off_type next = base + off; const off_type size = static_cast(end - begin); if (next < 0 || next > size) { return pos_type(off_type(-1)); } this->setg(begin, begin + next, end); return pos_type(next); } pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in) override { return this->seekoff(off_type(pos), std::ios_base::beg, which); } }; /** * Lightweight istream over csv::string_view with zero copy. * * WARNING: The caller is responsible for ensuring the backing memory * outlives this stream and any CSVReader parsing it. */ class StringViewStream : public std::istream { public: explicit StringViewStream(csv::string_view view) : std::istream(nullptr), _buf(view) { this->rdbuf(&_buf); } StringViewStream(const StringViewStream&) = delete; StringViewStream(StringViewStream&&) = delete; StringViewStream& operator=(const StringViewStream&) = delete; StringViewStream& operator=(StringViewStream&&) = delete; private: StringViewStreamBuf _buf; }; } } #include #include #include namespace csv { /** Returned by get_file_info() */ struct CSVFileInfo { std::string filename; /**< Filename */ std::vector col_names; /**< CSV column names */ char delim; /**< Delimiting character */ size_t n_rows; /**< Number of rows in a file */ size_t n_cols; /**< Number of columns in a CSV */ }; /** @name Shorthand Parsing Functions * @brief Convenience functions for parsing small strings */ ///@{ CSVReader operator ""_csv(const char*, size_t); CSVReader operator ""_csv_no_header(const char*, size_t); /** Parse CSV from a string view, copying the input into an owned buffer. * * Safe for any string_view regardless of the caller's ownership of the * underlying memory. */ CSVReader parse(csv::string_view in, CSVFormat format = CSVFormat::guess_csv()); /** Parse CSV from an in-memory view with zero copy. * * WARNING: Non-owning path. The caller must ensure `in`'s backing memory * remains valid and immutable while the reader may request additional rows * from the source stream. * * Already materialized CSVRows remain safe because parsed chunk data is * owned by RawCSVData, so make sure you grab all the CSVRows you need * before the underlying string is destroyed. */ CSVReader parse_unsafe(csv::string_view in, CSVFormat format = CSVFormat::guess_csv()); CSVReader parse_no_header(csv::string_view in); ///@} /** @name Utility Functions */ ///@{ std::unordered_map csv_data_types(const std::string&); CSVFileInfo get_file_info(const std::string& filename); int get_col_pos(csv::string_view filename, csv::string_view col_name, const CSVFormat& format = CSVFormat::guess_csv()); ///@} } /** @file * A standalone header file for writing delimiter-separated files */ #include #include #include #ifdef CSV_HAS_CXX20 #include #endif #include #include #include #include #include namespace csv { namespace internals { static int DECIMAL_PLACES = 5; /** * Calculate the absolute value of a number */ template inline T csv_abs(T x) { return abs(x); } template<> inline int csv_abs(int x) { return abs(x); } template<> inline long int csv_abs(long int x) { return labs(x); } template<> inline long long int csv_abs(long long int x) { return llabs(x); } template<> inline float csv_abs(float x) { return fabsf(x); } template<> inline double csv_abs(double x) { return fabs(x); } template<> inline long double csv_abs(long double x) { return fabsl(x); } /** * Calculate the number of digits in a number */ template< typename T, csv::enable_if_t::value, int> = 0 > int num_digits(T x) { x = csv_abs(x); int digits = 0; while (x >= 1) { x /= 10; digits++; } return digits; } /** to_string() for unsigned integers */ template::value, int> = 0> inline std::string to_string(T value) { std::string digits_reverse = ""; if (value == 0) return "0"; while (value > 0) { digits_reverse += (char)('0' + (value % 10)); value /= 10; } return std::string(digits_reverse.rbegin(), digits_reverse.rend()); } /** to_string() for signed integers */ template< typename T, csv::enable_if_t::value && std::is_signed::value, int> = 0 > inline std::string to_string(T value) { if (value >= 0) return to_string((size_t)value); return "-" + to_string((size_t)(value * -1)); } /** to_string() for floating point numbers */ template< typename T, csv::enable_if_t::value, int> = 0 > inline std::string to_string(T value) { #ifdef __clang__ return std::to_string(value); #else // TODO: Figure out why the below code doesn't work on clang std::string result = ""; T integral_part; T fractional_part = std::abs(std::modf(value, &integral_part)); integral_part = std::abs(integral_part); // Integral part if (value < 0) result = "-"; if (integral_part == 0) { result += "0"; } else { for (int n_digits = num_digits(integral_part); n_digits > 0; n_digits --) { int digit = (int)(std::fmod(integral_part, pow10(n_digits)) / pow10(n_digits - 1)); result += (char)('0' + digit); } } // Decimal part result += "."; if (fractional_part > 0) { fractional_part *= (T)(pow10(DECIMAL_PLACES)); for (int n_digits = DECIMAL_PLACES; n_digits > 0; n_digits--) { int digit = (int)(std::fmod(fractional_part, pow10(n_digits)) / pow10(n_digits - 1)); result += (char)('0' + digit); } } else { result += "0"; } return result; #endif } } /** Sets how many places after the decimal will be written for floating point numbers * * @param precision Number of decimal places */ #ifndef __clang__ inline static void set_decimal_places(int precision) { internals::DECIMAL_PLACES = precision; } #endif namespace internals { /** SFINAE trait: detects if a type is iterable (has std::begin/end). */ template struct is_iterable : std::false_type {}; template struct is_iterable::type> { private: template static auto test(int) -> decltype( std::begin(std::declval()), std::end(std::declval()), std::true_type{} ); template static std::false_type test(...); public: static constexpr bool value = decltype(test(0))::value; }; /** SFINAE trait: detects if a type is a std::tuple. */ template struct is_tuple : std::false_type {}; template struct is_tuple::type> { private: template static auto test(int) -> decltype(std::tuple_size::value, std::true_type{}); template static std::false_type test(...); public: static constexpr bool value = decltype(test(0))::value; }; } /** @name CSV Writing */ ///@{ /** * Class for writing delimiter separated values files * * To write formatted strings, one should * -# Initialize a DelimWriter with respect to some output stream * -# Call write_row() on std::vectors of unformatted text * * @tparam OutputStream The output stream, e.g. `std::ofstream`, `std::stringstream` * @tparam Delim The delimiter character * @tparam Quote The quote character * @tparam Flush True: flush after every writing function, * false: you need to flush explicitly if needed. * In both cases the destructor will flush. * * @par Hint * Use the aliases csv::CSVWriter to write CSV * formatted strings and csv::TSVWriter * to write tab separated strings * * @par Example w/ std::vector, std::deque, std::list * @snippet test_write_csv.cpp CSV Writer Example * * @par Example w/ std::tuple * @snippet test_write_csv.cpp CSV Writer Tuple Example */ template class DelimWriter { public: /** Construct a DelimWriter over the specified output stream * * @param _out Stream to write to * @param _quote_minimal Limit field quoting to only when necessary */ DelimWriter(OutputStream& _out, bool _quote_minimal = true) : out(&_out), quote_minimal(_quote_minimal) {} /** Construct a DelimWriter over the file * * @param[out] filename File to write to */ template::value, int> = 0> DelimWriter(const std::string& filename, bool _quote_minimal = true) : owned_out(new std::ofstream(filename, std::ios::out)), out(owned_out.get()), quote_minimal(_quote_minimal) { if (!owned_out->is_open()) throw std::runtime_error("Failed to open file for writing: " + filename); } DelimWriter(const DelimWriter&) = delete; DelimWriter& operator=(const DelimWriter&) = delete; DelimWriter(DelimWriter&& other) noexcept : owned_out(std::move(other.owned_out)), out(other.out), quote_minimal(other.quote_minimal) { if (owned_out) { out = owned_out.get(); } other.out = nullptr; other.quote_minimal = true; } DelimWriter& operator=(DelimWriter&& other) noexcept { if (this == &other) return *this; owned_out = std::move(other.owned_out); out = other.out; quote_minimal = other.quote_minimal; if (owned_out) { out = owned_out.get(); } other.out = nullptr; other.quote_minimal = true; return *this; } /** Destructor will flush remaining data * */ ~DelimWriter() { if (out) out->flush(); } /** Write a C-style array of strings as one delimited row. * * @tparam T Element type (typically std::string or csv::string_view) * @tparam N Array size (deduced) * @param record Array of strings * @return The current DelimWriter instance */ template DelimWriter& operator<<(const T (&record)[N]) { write_range_impl(record); return *this; } /** Write a std::array of strings as one delimited row. * * @tparam T Element type (typically std::string or csv::string_view) * @tparam N Array size (deduced) * @param record std::array of strings * @return The current DelimWriter instance */ template DelimWriter& operator<<(const std::array& record) { write_range_impl(record); return *this; } #ifdef CSV_HAS_CXX20 /** Write a range of string-like fields as one delimited row. * * Accepts any input_range whose elements are convertible to csv::string_view. * This includes std::vector, std::vector, * std::array, C++20 views, etc. */ template DelimWriter& operator<<(Range&& container) requires std::ranges::input_range && std::convertible_to, csv::string_view> { write_range_impl(container); return *this; } #else /** Write a range of string-like fields as one delimited row. * * Accepts any input_range whose elements are convertible to csv::string_view. * This includes std::vector, std::vector, * std::array, C++20 views, etc. */ template typename std::enable_if< internals::is_iterable::value && !internals::is_tuple::value && !std::is_same::value && !std::is_same::value, DelimWriter& >::type operator<<(const Range& record) { write_range_impl(record); return *this; } #endif /** @copydoc operator<< */ template DelimWriter& operator<<(const std::tuple& record) { this->write_tuple<0, T...>(record); return *this; } /** Flushes the written data * */ void flush() { out->flush(); } private: /** Helper to write a range of values, handling first element undelimited, * rest prefixed with delimiter. Inlines aggressively across both C++20 and * C++11 operator<< entry points. */ template inline void write_range_impl(const Range& record) { auto it = std::begin(record); auto end = std::end(record); if (it != end) { (*out) << csv_escape(*it); ++it; } for (; it != end; ++it) { (*out) << Delim << csv_escape(*it); } end_out(); } template< typename T, csv::enable_if_t< !std::is_convertible::value && !std::is_convertible::value , int> = 0 > std::string csv_escape(T in) { return internals::to_string(in); } template< typename T, csv::enable_if_t< std::is_convertible::value || std::is_convertible::value , int> = 0 > std::string csv_escape(T in) { IF_CONSTEXPR(std::is_convertible::value) { return _csv_escape(in); } else { return _csv_escape(std::string(in)); } } std::string _csv_escape(csv::string_view in) { /** Format a string to be RFC 4180-compliant * @param[in] in String to be CSV-formatted * @param[out] quote_minimal Only quote fields if necessary. * If False, everything is quoted. */ // Do we need a quote escape bool quote_escape = false; for (auto ch : in) { if (ch == Quote || ch == Delim || ch == '\r' || ch == '\n') { quote_escape = true; break; } } if (!quote_escape) { if (quote_minimal) return std::string(in); else { std::string ret(1, Quote); ret += in.data(); ret += Quote; return ret; } } // Start initial quote escape sequence std::string ret(1, Quote); for (auto ch: in) { if (ch == Quote) ret += std::string(2, Quote); else ret += ch; } // Finish off quote escape ret += Quote; return ret; } /** Recurisve template for writing std::tuples */ template typename std::enable_if::type write_tuple(const std::tuple& record) { (*out) << csv_escape(std::get(record)); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4127) #endif IF_CONSTEXPR (Index + 1 < sizeof...(T)) (*out) << Delim; #ifdef _MSC_VER #pragma warning(pop) #endif this->write_tuple(record); } /** Base case for writing std::tuples */ template typename std::enable_if::type write_tuple(const std::tuple& record) { (void)record; end_out(); } /** Ends a line in 'out' and flushes, if Flush is true.*/ void end_out() { (*out) << '\n'; IF_CONSTEXPR(Flush) out->flush(); } /** * An owned output stream, if the writer owns it. * May be null if the writer does not own its output stream, i.e. * if it was initialized with an output stream reference instead of a filename. */ std::unique_ptr owned_out; /** Pointer to the output stream (which may or may not be owned by this writer). */ OutputStream* out; bool quote_minimal; }; /** An alias for csv::DelimWriter for writing standard CSV files * * @sa csv::DelimWriter::operator<<() * * @note Use `csv::make_csv_writer()` to in instatiate this class over * an actual output stream. */ template using CSVWriter = DelimWriter; /** Class for writing tab-separated values files * * @sa csv::DelimWriter::write_row() * @sa csv::DelimWriter::operator<<() * * @note Use `csv::make_tsv_writer()` to in instatiate this class over * an actual output stream. */ template using TSVWriter = DelimWriter; /** Return a csv::CSVWriter over the output stream */ template inline CSVWriter make_csv_writer(OutputStream& out, bool quote_minimal=true) { return CSVWriter(out, quote_minimal); } /** Return a buffered csv::CSVWriter over the output stream (does not auto flush) */ template inline CSVWriter make_csv_writer_buffered(OutputStream& out, bool quote_minimal=true) { return CSVWriter(out, quote_minimal); } /** Return a csv::TSVWriter over the output stream */ template inline TSVWriter make_tsv_writer(OutputStream& out, bool quote_minimal=true) { return TSVWriter(out, quote_minimal); } /** Return a buffered csv::TSVWriter over the output stream (does not auto flush) */ template inline TSVWriter make_tsv_writer_buffered(OutputStream& out, bool quote_minimal=true) { return TSVWriter(out, quote_minimal); } ///@} } /** @file * Fast CSVWriter overloads for CSVRow and DataFrame. */ #ifdef CSV_HAS_CXX20 namespace csv { template DelimWriter& operator<< (DelimWriter& writer, const CSVRow& row) { return writer << row.to_sv_range(); } /** Overload for writing a DataFrameRow (respects sparse overlay edits). */ template DelimWriter& operator<< (DelimWriter& writer, const DataFrameRow& row) { return writer << row.to_sv_range(); } } #endif /** @file * Defines an object used to store CSV format settings */ #include #include namespace csv { CSV_INLINE CSVFormat& CSVFormat::delimiter(char delim) { this->possible_delimiters = { delim }; this->assert_no_char_overlap(); return *this; } CSV_INLINE CSVFormat& CSVFormat::delimiter(const std::vector & delim) { this->possible_delimiters = delim; this->assert_no_char_overlap(); return *this; } CSV_INLINE CSVFormat& CSVFormat::quote(char quote) { this->no_quote = false; this->quote_char = quote; this->assert_no_char_overlap(); return *this; } CSV_INLINE CSVFormat& CSVFormat::trim(const std::vector & chars) { this->trim_chars = chars; this->assert_no_char_overlap(); return *this; } CSV_INLINE CSVFormat& CSVFormat::column_names(const std::vector& names) { this->col_names = names; this->header = -1; return *this; } CSV_INLINE CSVFormat& CSVFormat::header_row(int row) { if (row < 0) this->variable_column_policy = VariableColumnPolicy::KEEP; this->header = row; this->col_names = {}; return *this; } CSV_INLINE CSVFormat& CSVFormat::chunk_size(size_t size) { if (size < internals::ITERATION_CHUNK_SIZE) { throw std::invalid_argument( "Chunk size must be at least " + std::to_string(internals::ITERATION_CHUNK_SIZE) + " bytes (10MB). Provided: " + std::to_string(size) ); } this->_chunk_size = size; return *this; } CSV_INLINE void CSVFormat::assert_no_char_overlap() { auto delims = std::set( this->possible_delimiters.begin(), this->possible_delimiters.end()), trims = std::set( this->trim_chars.begin(), this->trim_chars.end()); // Stores intersection of possible delimiters and trim characters std::vector intersection = {}; // Find which characters overlap, if any std::set_intersection( delims.begin(), delims.end(), trims.begin(), trims.end(), std::back_inserter(intersection)); // Make sure quote character is not contained in possible delimiters // or whitespace characters if (delims.find(this->quote_char) != delims.end() || trims.find(this->quote_char) != trims.end()) { intersection.push_back(this->quote_char); } if (!intersection.empty()) { std::string err_msg = "There should be no overlap between the quote character, " "the set of possible delimiters " "and the set of whitespace characters. Offending characters: "; // Create a pretty error message with the list of overlapping // characters for (size_t i = 0; i < intersection.size(); i++) { err_msg += "'"; err_msg += intersection[i]; err_msg += "'"; if (i + 1 < intersection.size()) err_msg += ", "; } throw std::runtime_error(err_msg + '.'); } } } /** @file * Defines an input iterator for csv::CSVReader */ namespace csv { /** Return an iterator to the first row in the reader */ CSV_INLINE CSVReader::iterator CSVReader::begin() { CSVRow row; if (!this->read_row(row)) { return this->end(); } return CSVReader::iterator(this, std::move(row)); } /** A placeholder for the imaginary past the end row in a CSV. * Attempting to deference this will lead to bad things. */ CSV_INLINE CSV_CONST CSVReader::iterator CSVReader::end() const noexcept { return CSVReader::iterator(); } CSV_INLINE CSVReader::iterator::iterator(CSVReader* _daddy, CSVRow&& _row) : daddy(_daddy) { row = std::move(_row); } /** Advance the iterator by one row. If this CSVReader has an * associated file, then the iterator will lazily pull more data from * that file until the end of file is reached. * * @note This iterator does **not** block the thread responsible for parsing CSV. * */ CSV_INLINE CSVReader::iterator& CSVReader::iterator::operator++() { if (!daddy->read_row(this->row)) { this->daddy = nullptr; // this == end() } return *this; } /** Post-increment iterator */ CSV_INLINE CSVReader::iterator CSVReader::iterator::operator++(int) { auto temp = *this; if (!daddy->read_row(this->row)) { this->daddy = nullptr; // this == end() } return temp; } } /** @file * Implements JSON serialization abilities */ namespace csv { /* The implementations for json_extra_space() and json_escape_string() were modified from source code for JSON for Modern C++. The respective license is below: The code is licensed under the [MIT License](http://opensource.org/licenses/MIT): Copyright © 2013-2015 Niels Lohmann. 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. */ namespace internals { /*! @brief calculates the extra space to escape a JSON string @param[in] s the string to escape @return the number of characters required to escape string @a s @complexity Linear in the length of string @a s. */ static std::size_t json_extra_space(csv::string_view& s) noexcept { std::size_t result = 0; for (const auto& c : s) { switch (c) { case '"': case '\\': case '\b': case '\f': case '\n': case '\r': case '\t': { // from c (1 byte) to \x (2 bytes) result += 1; break; } default: { if (c >= 0x00 && c <= 0x1f) { // from c (1 byte) to \uxxxx (6 bytes) result += 5; } break; } } } return result; } CSV_INLINE std::string json_escape_string(csv::string_view s) noexcept { const auto space = json_extra_space(s); if (space == 0) { return std::string(s); } // create a result string of necessary size size_t result_size = s.size() + space; std::string result(result_size, '\\'); std::size_t pos = 0; for (const auto& c : s) { switch (c) { // quotation mark (0x22) case '"': { result[pos + 1] = '"'; pos += 2; break; } // reverse solidus (0x5c) case '\\': { // nothing to change pos += 2; break; } // backspace (0x08) case '\b': { result[pos + 1] = 'b'; pos += 2; break; } // formfeed (0x0c) case '\f': { result[pos + 1] = 'f'; pos += 2; break; } // newline (0x0a) case '\n': { result[pos + 1] = 'n'; pos += 2; break; } // carriage return (0x0d) case '\r': { result[pos + 1] = 'r'; pos += 2; break; } // horizontal tab (0x09) case '\t': { result[pos + 1] = 't'; pos += 2; break; } default: { if (c >= 0x00 && c <= 0x1f) { // print character c as \uxxxx snprintf(&result[pos + 1], result_size - pos - 1, "u%04x", int(c)); pos += 6; // overwrite trailing null character result[pos] = '\\'; } else { // all other characters are added as-is result[pos++] = c; } break; } } } return result; } } /** Convert a CSV row to a JSON object, i.e. * `{"col1":"value1","col2":"value2"}` * * @note All strings are properly escaped. Numeric values are not quoted. * @param[in] subset A subset of columns to contain in the JSON. * Leave empty for original columns. */ CSV_INLINE std::string CSVRow::to_json(const std::vector& subset) const { std::vector col_names = subset; if (subset.empty()) { col_names = this->data ? this->get_col_names() : std::vector({}); } const size_t _n_cols = col_names.size(); std::string ret = "{"; for (size_t i = 0; i < _n_cols; i++) { auto& col = col_names[i]; auto field = this->operator[](col); // TODO: Possible performance enhancements by caching escaped column names ret += '"' + internals::json_escape_string(col) + "\":"; // Add quotes around strings but not numbers if (field.is_num()) ret += internals::json_escape_string(field.get()); else ret += '"' + internals::json_escape_string(field.get()) + '"'; // Do not add comma after last string if (i + 1 < _n_cols) ret += ','; } ret += '}'; return ret; } /** Convert a CSV row to a JSON array, i.e. * `["value1","value2",...]` * * @note All strings are properly escaped. Numeric values are not quoted. * @param[in] subset A subset of columns to contain in the JSON. * Leave empty for all columns. */ CSV_INLINE std::string CSVRow::to_json_array(const std::vector& subset) const { std::vector col_names = subset; if (subset.empty()) col_names = this->data ? this->get_col_names() : std::vector({}); const size_t _n_cols = col_names.size(); std::string ret = "["; for (size_t i = 0; i < _n_cols; i++) { auto field = this->operator[](col_names[i]); // Add quotes around strings but not numbers if (field.is_num()) ret += internals::json_escape_string(field.get()); else ret += '"' + internals::json_escape_string(field.get()) + '"'; // Do not add comma after last string if (i + 1 < _n_cols) ret += ','; } ret += ']'; return ret; } } #include #include #include namespace csv { /** Shorthand function for parsing an in-memory CSV string. * * Copies the input into an owned stringstream, so the caller's backing * memory may be freed immediately after this call returns. * * @return A collection of CSVRow objects * * @par Example * @snippet tests/test_read_csv.cpp Parse Example */ CSV_INLINE CSVReader parse(csv::string_view in, CSVFormat format) { std::unique_ptr ss(new std::stringstream(std::string(in))); return CSVReader(std::move(ss), format); } /** Parse CSV from an in-memory view with zero copy. * * Creates a non-owning stream adapter over the provided string_view. * The caller is responsible for keeping backing memory valid and immutable * while CSVReader may request additional rows. * * Already materialized CSVRows remain safe because parsed chunk data is * owned by RawCSVData. * * @return A collection of CSVRow objects */ CSV_INLINE CSVReader parse_unsafe(csv::string_view in, CSVFormat format) { std::unique_ptr stream(new internals::StringViewStream(in)); return CSVReader(std::move(stream), format); } /** Parses a CSV string with no headers * * @return A collection of CSVRow objects */ CSV_INLINE CSVReader parse_no_header(csv::string_view in) { CSVFormat format; format.header_row(-1); return parse(in, format); } /** Parse a RFC 4180 CSV string, returning a collection * of CSVRow objects. * * String literals have static storage duration, so the zero-copy path is * safe here. * * @par Example * @snippet tests/test_read_csv.cpp Escaped Comma * */ CSV_INLINE CSVReader operator ""_csv(const char* in, size_t n) { return parse_unsafe(csv::string_view(in, n)); } /** A shorthand for csv::parse_no_header(). * * String literals have static storage duration, so the zero-copy path is * safe here. */ CSV_INLINE CSVReader operator ""_csv_no_header(const char* in, size_t n) { CSVFormat format; format.header_row(-1); return parse_unsafe(csv::string_view(in, n), format); } /** * Find the position of a column in a CSV file or CSV_NOT_FOUND otherwise * * @param[in] filename Path to CSV file * @param[in] col_name Column whose position we should resolve * @param[in] format Format of the CSV file */ CSV_INLINE int get_col_pos( csv::string_view filename, csv::string_view col_name, const CSVFormat& format) { CSVReader reader(filename, format); return reader.index_of(col_name); } /** Get basic information about a CSV file * @include programs/csv_info.cpp */ CSV_INLINE CSVFileInfo get_file_info(const std::string& filename) { CSVReader reader(filename); CSVFormat format = reader.get_format(); for (auto it = reader.begin(); it != reader.end(); ++it); CSVFileInfo info = { filename, reader.get_col_names(), format.get_delim(), reader.n_rows(), reader.get_col_names().size() }; return info; } } /** @file * @brief Defines functionality needed for basic CSV parsing */ namespace csv { namespace internals { CSV_INLINE std::string format_row(const std::vector& row, csv::string_view delim) { /** Print a CSV row */ std::stringstream ret; for (size_t i = 0; i < row.size(); i++) { ret << row[i]; if (i + 1 < row.size()) ret << delim; else ret << '\n'; } ret.flush(); return ret.str(); } /** Return a CSV's column names * * @param[in] filename Path to CSV file * @param[in] format Format of the CSV file * */ CSV_INLINE std::vector _get_col_names(csv::string_view head, CSVFormat format) { // Parse the CSV auto trim_chars = format.get_trim_chars(); std::stringstream source(head.data()); RowCollection rows; StreamParser parser(source, format); parser.set_output(rows); parser.next(); return CSVRow(std::move(rows[format.get_header()])); } CSV_INLINE GuessScore calculate_score(csv::string_view head, const CSVFormat& format) { // Frequency counter of row length std::unordered_map row_tally = { { 0, 0 } }; // Map row lengths to row num where they first occurred std::unordered_map row_when = { { 0, 0 } }; // Parse the CSV std::stringstream source(head.data()); RowCollection rows; StreamParser parser(source, format); parser.set_output(rows); parser.next(); for (size_t i = 0; i < rows.size(); i++) { auto& row = rows[i]; // Ignore zero-length rows if (row.size() > 0) { if (row_tally.find(row.size()) != row_tally.end()) { row_tally[row.size()]++; } else { row_tally[row.size()] = 1; row_when[row.size()] = i; } } } double final_score = 0; size_t header_row = 0; size_t mode_row_length = 0; // Final score is equal to the largest // row size times rows of that size for (auto& pair : row_tally) { auto row_size = pair.first; auto row_count = pair.second; double score = (double)(row_size * row_count); if (score > final_score) { final_score = score; mode_row_length = row_size; header_row = row_when[row_size]; } } // Heuristic: If first row has >= columns than mode, use it as header // This handles headers with optional columns, trailing delimiters, etc. // while still supporting CSVs with comment lines before the header size_t first_row_length = rows.size() > 0 ? rows[0].size() : 0; if (first_row_length >= mode_row_length && first_row_length > 0) { header_row = 0; } return { final_score, header_row }; } /** Guess the delimiter used by a delimiter-separated values file */ CSV_INLINE CSVGuessResult _guess_format(csv::string_view head, const std::vector& delims) { /** For each delimiter, find out which row length was most common (mode). * The delimiter with the highest score (row_length × count) wins. * * Header detection: If first row has >= columns than mode, use row 0. * Otherwise use the first row with the mode length. * * See csv::guess_format() public API documentation for detailed heuristic explanation. */ CSVFormat format; size_t max_score = 0, header = 0; char current_delim = delims[0]; for (char cand_delim : delims) { auto result = calculate_score(head, format.delimiter(cand_delim)); if ((size_t)result.score > max_score) { max_score = (size_t)result.score; current_delim = cand_delim; header = result.header; } } return { current_delim, (int)header }; } } /** Return a CSV's column names * * @param[in] filename Path to CSV file * @param[in] format Format of the CSV file * */ CSV_INLINE std::vector get_col_names(csv::string_view filename, CSVFormat format) { auto head = internals::get_csv_head(filename); /** Guess delimiter and header row */ if (format.guess_delim()) { auto guess_result = guess_format(filename, format.get_possible_delims()); format.delimiter(guess_result.delim).header_row(guess_result.header_row); } return internals::_get_col_names(head, format); } /** Guess the delimiter used by a delimiter-separated values file */ CSV_INLINE CSVGuessResult guess_format(csv::string_view filename, const std::vector& delims) { auto head = internals::get_csv_head(filename); return internals::_guess_format(head, delims); } /** Reads an arbitrarily large CSV file using memory-mapped IO. * * **Details:** Reads the first block of a CSV file synchronously to get information * such as column names and delimiting character. * * @param[in] filename Path to CSV file * @param[in] format Format of the CSV file * * \snippet tests/test_read_csv.cpp CSVField Example * */ CSV_INLINE CSVReader::CSVReader(csv::string_view filename, CSVFormat format) : _format(format) { #if defined(__EMSCRIPTEN__) this->owned_stream = std::unique_ptr( new std::ifstream(std::string(filename), std::ios::binary) ); if (!(*this->owned_stream)) { throw std::runtime_error("Cannot open file " + std::string(filename)); } this->init_from_stream(*this->owned_stream, format); #else auto head = internals::get_csv_head(filename); using Parser = internals::MmapParser; // Apply chunk size from format before any reading occurs this->_chunk_size = format.get_chunk_size(); /** Guess delimiter and header row */ if (format.guess_delim()) { auto guess_result = internals::_guess_format(head, format.possible_delimiters); format.delimiter(guess_result.delim); // Only override header if user hasn't explicitly called no_header() // Note: column_names() also sets header=-1, but it populates col_names, // so we can distinguish: no_header() means header=-1 && col_names.empty() if (format.header != -1 || !format.col_names.empty()) { format.header = guess_result.header_row; } this->_format = format; } if (!format.col_names.empty()) this->set_col_names(format.col_names); this->parser = std::unique_ptr(new Parser(filename, format, this->col_names)); // For C++11 this->initial_read(); #endif } /** Return the format of the original raw CSV */ CSV_INLINE CSVFormat CSVReader::get_format() const { CSVFormat new_format = this->_format; // Since users are normally not allowed to set // column names and header row simulatenously, // we will set the backing variables directly here new_format.col_names = this->col_names->get_col_names(); new_format.header = this->_format.header; return new_format; } /** Return the CSV's column names as a vector of strings. */ CSV_INLINE std::vector CSVReader::get_col_names() const { if (this->col_names) { return this->col_names->get_col_names(); } return std::vector(); } /** Return the index of the column name if found or * csv::CSV_NOT_FOUND otherwise. */ CSV_INLINE int CSVReader::index_of(csv::string_view col_name) const { return this->col_names->index_of(col_name); } CSV_INLINE void CSVReader::trim_header() { if (!this->header_trimmed) { for (int i = 0; i <= this->_format.header && !this->records->empty(); i++) { if (i == this->_format.header && this->col_names->empty()) { this->set_col_names(this->records->pop_front()); } else { this->records->pop_front(); } } this->header_trimmed = true; } } /** * @param[in] names Column names */ CSV_INLINE void CSVReader::set_col_names(const std::vector& names) { this->col_names->set_policy(this->_format.get_column_name_policy()); this->col_names->set_col_names(names); this->n_cols = names.size(); } /** * Read a chunk of CSV data. * * @note This method is meant to be run on its own thread. Only one `read_csv()` thread * should be active at a time. * * @param[in] bytes Number of bytes to read. * * @see CSVReader::read_csv_worker * @see CSVReader::read_row() */ CSV_INLINE bool CSVReader::read_csv(size_t bytes) { // WORKER THREAD FUNCTION: Runs asynchronously to read CSV chunks // // Threading model: // 1. notify_all() - signals read_row() that worker is active // 2. parser->next() - reads and parses bytes (10MB chunks) // 3. kill_all() - signals read_row() that worker is done // // Exception handling: Exceptions thrown here MUST propagate to the calling // thread via std::exception_ptr. Bug #282 fixed cases where exceptions were // swallowed, causing std::terminate() instead of proper error handling. // Tell read_row() to listen for CSV rows this->records->notify_all(); try { this->parser->set_output(*this->records); this->parser->next(bytes); if (!this->header_trimmed) { this->trim_header(); } } catch (...) { // Never allow exceptions to escape the worker thread, or std::terminate will be invoked. // Store the exception and rethrow from the consumer thread (read_row / iterator). this->set_read_csv_exception(std::current_exception()); } // Tell read_row() to stop waiting this->records->kill_all(); return true; } /** * Retrieve rows as CSVRow objects, returning true if more rows are available. * * @par Performance Notes * - Reads chunks of data that are csv::internals::ITERATION_CHUNK_SIZE bytes large at a time * - For performance details, read the documentation for CSVRow and CSVField. * * @param[out] row The variable where the parsed row will be stored * @see CSVRow, CSVField * * **Example:** * \snippet tests/test_read_csv.cpp CSVField Example * */ CSV_INLINE bool CSVReader::read_row(CSVRow &row) { while (true) { if (this->records->empty()) { #if CSV_ENABLE_THREADS if (this->records->is_waitable()) { // Reading thread is currently active => wait for it to populate records this->records->wait(); continue; } #endif // Reading thread is not active #if CSV_ENABLE_THREADS if (this->read_csv_worker.joinable()) this->read_csv_worker.join(); #endif // If the worker thread failed, rethrow the error here this->rethrow_read_csv_exception_if_any(); if (this->parser->eof()) // End of file and no more records return false; // Detect infinite loop: a previous read was requested but records are still empty. // This fires when a single row spans more than 2 × _chunk_size bytes: // - chunk N fills without finding '\n' → _read_requested set to true // - chunk N+1 also fills without '\n' → guard fires here // Default _chunk_size is ITERATION_CHUNK_SIZE (10 MB), so the threshold is // rows > 20 MB. Use CSVFormat::chunk_size() to raise the limit. if (this->_read_requested && this->records->empty()) { throw std::runtime_error( "End of file not reached and no more records parsed. " "This likely indicates a CSV row larger than the chunk size of " + std::to_string(this->_chunk_size) + " bytes. " "Use CSVFormat::chunk_size() to increase the chunk size." ); } #if CSV_ENABLE_THREADS // Start another reading thread. // Mark as waitable before starting the thread to avoid a race where // read_row() observes is_waitable()==false immediately after thread creation. this->records->notify_all(); this->read_csv_worker = std::thread(&CSVReader::read_csv, this, this->_chunk_size); #else // Single-threaded mode parses synchronously on the caller thread. this->read_csv(this->_chunk_size); this->rethrow_read_csv_exception_if_any(); #endif this->_read_requested = true; continue; } else if (this->records->front().size() != this->n_cols && this->_format.variable_column_policy != VariableColumnPolicy::KEEP) { auto errored_row = this->records->pop_front(); if (this->_format.variable_column_policy == VariableColumnPolicy::THROW) { if (errored_row.size() < this->n_cols) throw std::runtime_error("Line too short " + internals::format_row(errored_row)); throw std::runtime_error("Line too long " + internals::format_row(errored_row)); } } else { row = this->records->pop_front(); this->_n_rows++; this->_read_requested = false; // Reset flag on successful read return true; } } return false; } } /** @file * Calculates statistics from CSV files */ #include #if CSV_ENABLE_THREADS #include #endif namespace csv { /** Calculate statistics for an arbitrarily large file. When this constructor * is called, CSVStat will process the entire file iteratively. Once finished, * methods like get_mean(), get_counts(), etc... can be used to retrieve statistics. */ CSV_INLINE CSVStat::CSVStat(csv::string_view filename, CSVFormat format) : reader(filename, format) { this->calc(); } /** Calculate statistics for a CSV stored in a std::stringstream */ CSV_INLINE CSVStat::CSVStat(std::stringstream& stream, CSVFormat format) : reader(stream, format) { this->calc(); } /** Return current means */ CSV_INLINE std::vector CSVStat::get_mean() const { std::vector ret; for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->rolling_means[i]); } return ret; } /** Return current variances */ CSV_INLINE std::vector CSVStat::get_variance() const { std::vector ret; for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->rolling_vars[i]/(this->n[i] - 1)); } return ret; } /** Return current mins */ CSV_INLINE std::vector CSVStat::get_mins() const { std::vector ret; for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->mins[i]); } return ret; } /** Return current maxes */ CSV_INLINE std::vector CSVStat::get_maxes() const { std::vector ret; for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->maxes[i]); } return ret; } /** Get counts for each column */ CSV_INLINE std::vector CSVStat::get_counts() const { std::vector ret; for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->counts[i]); } return ret; } /** Get data type counts for each column */ CSV_INLINE std::vector CSVStat::get_dtypes() const { std::vector ret; for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->dtypes[i]); } return ret; } CSV_INLINE void CSVStat::calc_chunk() { /** Only create stats counters the first time **/ if (dtypes.empty()) { /** Go through all records and calculate specified statistics */ for (size_t i = 0; i < this->get_col_names().size(); i++) { dtypes.push_back({}); counts.push_back({}); rolling_means.push_back(0); rolling_vars.push_back(0); mins.push_back(NAN); maxes.push_back(NAN); n.push_back(0); } } #if CSV_ENABLE_THREADS // Start threads std::vector pool; for (size_t i = 0; i < this->get_col_names().size(); i++) pool.push_back(std::thread(&CSVStat::calc_worker, this, i)); // Block until done for (auto& th : pool) th.join(); #else for (size_t i = 0; i < this->get_col_names().size(); i++) { this->calc_worker(i); } #endif this->records.clear(); } CSV_INLINE void CSVStat::calc() { constexpr size_t CALC_CHUNK_SIZE = 5000; for (auto& row : reader) { this->records.push_back(std::move(row)); /** Chunk rows */ if (this->records.size() == CALC_CHUNK_SIZE) { calc_chunk(); } } if (!this->records.empty()) { calc_chunk(); } } CSV_INLINE void CSVStat::calc_worker(const size_t &i) { /** Worker thread for CSVStat::calc() which calculates statistics for one column. * * @param[in] i Column index */ auto current_record = this->records.begin(); for (size_t processed = 0; current_record != this->records.end(); processed++) { if (current_record->size() == this->get_col_names().size()) { auto current_field = (*current_record)[i]; // Optimization: Don't count() if there's too many distinct values in the first 1000 rows if (processed < 1000 || this->counts[i].size() <= 500) this->count(current_field, i); this->dtype(current_field, i); // Numeric Stuff if (current_field.is_num()) { long double x_n = current_field.get(); // This actually calculates mean AND variance this->variance(x_n, i); this->min_max(x_n, i); } } else if (this->reader.get_format().get_variable_column_policy() == VariableColumnPolicy::THROW) { throw std::runtime_error("Line has different length than the others " + internals::format_row(*current_record)); } ++current_record; } } CSV_INLINE void CSVStat::dtype(CSVField& data, const size_t &i) { /** Given a record update the type counter * @param[in] record Data observation * @param[out] i The column index that should be updated */ auto type = data.type(); if (this->dtypes[i].find(type) != this->dtypes[i].end()) { // Increment count this->dtypes[i][type]++; } else { // Initialize count this->dtypes[i].insert(std::make_pair(type, 1)); } } CSV_INLINE void CSVStat::count(CSVField& data, const size_t &i) { /** Given a record update the frequency counter * @param[in] record Data observation * @param[out] i The column index that should be updated */ auto item = data.get(); if (this->counts[i].find(item) != this->counts[i].end()) { // Increment count this->counts[i][item]++; } else { // Initialize count this->counts[i].insert(std::make_pair(item, 1)); } } CSV_INLINE void CSVStat::min_max(const long double &x_n, const size_t &i) { /** Update current minimum and maximum * @param[in] x_n Data observation * @param[out] i The column index that should be updated */ if (std::isnan(this->mins[i])) this->mins[i] = x_n; if (std::isnan(this->maxes[i])) this->maxes[i] = x_n; if (x_n < this->mins[i]) this->mins[i] = x_n; else if (x_n > this->maxes[i]) this->maxes[i] = x_n; } CSV_INLINE void CSVStat::variance(const long double &x_n, const size_t &i) { /** Given a record update rolling mean and variance for all columns * using Welford's Algorithm * @param[in] x_n Data observation * @param[out] i The column index that should be updated */ long double& current_rolling_mean = this->rolling_means[i]; long double& current_rolling_var = this->rolling_vars[i]; long double& current_n = this->n[i]; long double delta; long double delta2; current_n++; if (current_n == 1) { current_rolling_mean = x_n; } else { delta = x_n - current_rolling_mean; current_rolling_mean += delta/current_n; delta2 = x_n - current_rolling_mean; current_rolling_var += delta*delta2; } } /** Useful for uploading CSV files to SQL databases. * * Return a data type for each column such that every value in a column can be * converted to the corresponding data type without data loss. * @param[in] filename The CSV file * * \return A mapping of column names to csv::DataType enums */ CSV_INLINE std::unordered_map csv_data_types(const std::string& filename) { CSVStat stat(filename); std::unordered_map csv_dtypes; auto col_names = stat.get_col_names(); auto temp = stat.get_dtypes(); for (size_t i = 0; i < stat.get_col_names().size(); i++) { auto& col = temp[i]; auto& col_name = col_names[i]; if (col[DataType::CSV_STRING]) csv_dtypes[col_name] = DataType::CSV_STRING; else if (col[DataType::CSV_INT64]) csv_dtypes[col_name] = DataType::CSV_INT64; else if (col[DataType::CSV_INT32]) csv_dtypes[col_name] = DataType::CSV_INT32; else if (col[DataType::CSV_INT16]) csv_dtypes[col_name] = DataType::CSV_INT16; else if (col[DataType::CSV_INT8]) csv_dtypes[col_name] = DataType::CSV_INT8; else csv_dtypes[col_name] = DataType::CSV_DOUBLE; } return csv_dtypes; } } /** @file * @brief Implementation of internal CSV data structures */ #include namespace csv { namespace internals { CSV_INLINE RawCSVField& RawCSVFieldList::operator[](size_t n) const { const size_t page_no = n / _single_buffer_capacity; const size_t buffer_idx = n % _single_buffer_capacity; return this->_owned_blocks[page_no].get()[buffer_idx]; } CSV_INLINE void RawCSVFieldList::allocate() { if (_back != nullptr) { _current_block++; } this->_owned_blocks.push_back(std::unique_ptr(new RawCSVField[_single_buffer_capacity])); _current_buffer_size = 0; _back = this->_owned_blocks.back().get(); } } } #include namespace csv { namespace internals { CSV_INLINE size_t get_file_size(csv::string_view filename) { std::ifstream infile(std::string(filename), std::ios::binary); if (!infile.is_open()) { throw std::runtime_error("Cannot open file " + std::string(filename)); } const auto start = infile.tellg(); infile.seekg(0, std::ios::end); const auto end = infile.tellg(); if (start < 0 || end < 0) { throw std::runtime_error("Cannot determine file size for " + std::string(filename)); } return static_cast(end - start); } CSV_INLINE std::string get_csv_head(csv::string_view filename) { return get_csv_head(filename, get_file_size(filename)); } CSV_INLINE std::string get_csv_head(csv::string_view filename, size_t file_size) { const size_t bytes = 500000; #if defined(__EMSCRIPTEN__) std::ifstream infile(std::string(filename), std::ios::binary); if (!infile.is_open()) { throw std::runtime_error("Cannot open file " + std::string(filename)); } const size_t length = std::min((size_t)file_size, bytes); std::string head(length, '\0'); infile.read(&head[0], (std::streamsize)length); head.resize((size_t)infile.gcount()); return head; #else std::error_code error; size_t length = std::min((size_t)file_size, bytes); auto mmap = mio::make_mmap_source(std::string(filename), 0, length, error); if (error) { throw std::runtime_error("Cannot open file " + std::string(filename)); } return std::string(mmap.begin(), mmap.end()); #endif } #ifdef _MSC_VER #pragma region IBasicCVParser #endif CSV_INLINE IBasicCSVParser::IBasicCSVParser( const CSVFormat& format, const ColNamesPtr& col_names ) : col_names_(col_names) { if (format.no_quote) { parse_flags_ = internals::make_parse_flags(format.get_delim()); } else { parse_flags_ = internals::make_parse_flags(format.get_delim(), format.quote_char); } // When no_quote, quote bytes are NOT_SPECIAL — use delimiter as safe dummy // so SIMD does not stop early on quote bytes and cause an infinite loop. const char eff_quote = format.no_quote ? format.get_delim() : format.quote_char; simd_sentinels_ = SentinelVecs(format.get_delim(), eff_quote); ws_flags_ = internals::make_ws_flags( format.trim_chars.data(), format.trim_chars.size() ); has_ws_trimming_ = !format.trim_chars.empty(); } CSV_INLINE void IBasicCSVParser::end_feed() { using internals::ParseFlags; bool empty_last_field = this->data_ptr_ && this->data_ptr_->_data && !this->data_ptr_->data.empty() && (parse_flag(this->data_ptr_->data.back()) == ParseFlags::DELIMITER || parse_flag(this->data_ptr_->data.back()) == ParseFlags::QUOTE); // Push field if (this->field_length_ > 0 || empty_last_field) { this->push_field(); } // Push row if (this->current_row_.size() > 0) this->push_row(); } CSV_INLINE void IBasicCSVParser::parse_field() noexcept { using internals::ParseFlags; auto& in = this->data_ptr_->data; if (field_start_ == UNINITIALIZED_FIELD) field_start_ = (int)(data_pos_ - current_row_start()); // Optimization: Since NOT_SPECIAL characters tend to occur in contiguous // sequences, use SIMD to skip long runs of them quickly. // find_next_non_special processes complete SIMD lanes and returns pos // unchanged for any tail shorter than one lane width. #if !defined(CSV_NO_SIMD) data_pos_ = find_next_non_special(in, data_pos_, this->simd_sentinels_); #endif // Scalar tail: handles remaining bytes after SIMD falls through, and // handles any byte that SIMD stopped at conservatively (e.g. a delimiter // inside a quoted field, which compound_parse_flag treats as NOT_SPECIAL). while (data_pos_ < in.size() && compound_parse_flag(in[data_pos_]) == ParseFlags::NOT_SPECIAL) data_pos_++; field_length_ = data_pos_ - (field_start_ + current_row_start()); // Whitespace trimming is deferred to get_field_impl() so callers that never // read field values (e.g. row counting) pay no trimming cost. } CSV_INLINE void IBasicCSVParser::push_field() { // Update fields_->emplace_back( field_start_ == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start_, field_length_, field_has_double_quote_ ); current_row_.row_length++; // Reset field state field_has_double_quote_ = false; field_start_ = UNINITIALIZED_FIELD; field_length_ = 0; } /** @return The number of characters parsed that belong to complete rows */ CSV_INLINE size_t IBasicCSVParser::parse() { using internals::ParseFlags; this->quote_escape_ = false; this->data_pos_ = 0; this->current_row_start() = 0; this->trim_utf8_bom(); auto& in = this->data_ptr_->data; while (this->data_pos_ < in.size()) { switch (compound_parse_flag(in[this->data_pos_])) { case ParseFlags::DELIMITER: this->push_field(); this->data_pos_++; break; case ParseFlags::NEWLINE: this->data_pos_++; // Catches CRLF (or LFLF, CRCRLF, or any other non-sensical combination of newlines) while (this->data_pos_ < in.size() && parse_flag(in[this->data_pos_]) == ParseFlags::NEWLINE) this->data_pos_++; // End of record -> Write record this->push_field(); this->push_row(); // Reset this->current_row_ = CSVRow(data_ptr_, this->data_pos_, fields_->size()); break; case ParseFlags::NOT_SPECIAL: this->parse_field(); break; case ParseFlags::QUOTE_ESCAPE_QUOTE: if (data_pos_ + 1 == in.size()) return this->current_row_start(); else if (data_pos_ + 1 < in.size()) { auto next_ch = parse_flag(in[data_pos_ + 1]); if (next_ch >= ParseFlags::DELIMITER) { quote_escape_ = false; data_pos_++; break; } else if (next_ch == ParseFlags::QUOTE) { // Case: Escaped quote data_pos_ += 2; this->field_length_ += 2; this->field_has_double_quote_ = true; break; } } // Case: Unescaped single quote => not strictly valid but we'll keep it this->field_length_++; data_pos_++; break; default: // Quote (currently not quote escaped) if (this->field_length_ == 0) { quote_escape_ = true; data_pos_++; if (field_start_ == UNINITIALIZED_FIELD && data_pos_ < in.size() && !ws_flag(in[data_pos_])) field_start_ = (int)(data_pos_ - current_row_start()); break; } // Case: Unescaped quote this->field_length_++; data_pos_++; break; } } return this->current_row_start(); } CSV_INLINE void IBasicCSVParser::push_row() { size_t row_len = fields_->size() - current_row_.fields_start; // Set row_length before pushing (immutable once created) current_row_.row_length = row_len; this->records_->push_back(std::move(current_row_)); } CSV_INLINE void IBasicCSVParser::reset_data_ptr() { this->data_ptr_ = std::make_shared(); this->data_ptr_->parse_flags = this->parse_flags_; this->data_ptr_->ws_flags = this->ws_flags_; this->data_ptr_->has_ws_trimming = this->has_ws_trimming_; this->data_ptr_->col_names = this->col_names_; this->fields_ = &(this->data_ptr_->fields); } CSV_INLINE void IBasicCSVParser::trim_utf8_bom() { auto& data = this->data_ptr_->data; if (!this->unicode_bom_scan_ && data.size() >= 3) { if (data[0] == '\xEF' && data[1] == '\xBB' && data[2] == '\xBF') { this->data_pos_ += 3; // Remove BOM from input string this->utf8_bom_ = true; } this->unicode_bom_scan_ = true; } } #ifdef _MSC_VER #pragma endregion #endif #ifdef _MSC_VER #pragma region Specializations #endif #if !defined(__EMSCRIPTEN__) CSV_INLINE void MmapParser::next(size_t bytes = ITERATION_CHUNK_SIZE) { // CRITICAL SECTION: Chunk Transition Logic // This function reads 10MB chunks and must correctly handle fields that span // chunk boundaries. The 'remainder' calculation below ensures partial fields // are preserved for the next chunk. // // Bug #280: Field corruption occurred here when chunk transitions incorrectly // split multi-byte characters or field boundaries. // Reset parser state this->field_start_ = UNINITIALIZED_FIELD; this->field_length_ = 0; this->reset_data_ptr(); // Create memory map const size_t offset = this->mmap_pos; const size_t remaining = (offset < this->source_size_) ? (this->source_size_ - offset) : 0; const size_t length = std::min(remaining, bytes); if (length == 0) { // No more data to read; mark EOF and end feed // (Prevent exception on empty mmap as reported by #267) this->eof_ = true; this->end_feed(); return; } std::error_code error; auto mmap = mio::make_mmap_source(this->_filename, offset, length, error); if (error) { std::string msg = "Memory mapping failed during CSV parsing: file='" + this->_filename + "' offset=" + std::to_string(offset) + " length=" + std::to_string(length); throw std::system_error(error, msg); } this->data_ptr_->_data = std::make_shared>(std::move(mmap)); this->mmap_pos += length; auto mmap_ptr = (mio::basic_mmap_source*)(this->data_ptr_->_data.get()); // Create string view this->data_ptr_->data = csv::string_view(mmap_ptr->data(), mmap_ptr->length()); // Parse this->current_row_ = CSVRow(this->data_ptr_); size_t remainder = this->parse(); if (this->mmap_pos == this->source_size_ || no_chunk()) { this->eof_ = true; this->end_feed(); } this->mmap_pos -= (length - remainder); } #endif #ifdef _MSC_VER #pragma endregion #endif } } /** @file * Defines the data type used for storing information about a CSV row */ #include #include namespace csv { namespace internals { CSV_INLINE csv::string_view get_trimmed(csv::string_view sv, const WhitespaceMap& ws_flags) noexcept { // Lazy trim only when requested size_t start = 0; while (start < sv.size() && ws_flags[sv[start] + CHAR_OFFSET]) { ++start; } size_t end = sv.size(); while (end > start && ws_flags[sv[end - 1] + CHAR_OFFSET]) { --end; } return sv.substr(start, end - start); } } /** Return a CSVField object corrsponding to the nth value in the row. * * @note This method performs bounds checking, and will throw an * `std::runtime_error` if n is invalid. * * @complexity * Constant, by calling csv::CSVRow::get_csv::string_view() * */ CSV_INLINE CSVField CSVRow::operator[](size_t n) const { return CSVField(this->get_field(n)); } /** Retrieve a value by its associated column name. If the column * specified can't be round, a runtime error is thrown. * * @complexity * Constant. This calls the other CSVRow::operator[]() after * converting column names into indices using a hash table. * * @param[in] col_name The column to look for */ CSV_INLINE CSVField CSVRow::operator[](const std::string& col_name) const { auto & col_names = this->data->col_names; auto col_pos = col_names->index_of(col_name); if (col_pos > -1) { return this->operator[](col_pos); } throw std::runtime_error("Can't find a column named " + col_name); } CSV_INLINE CSVRow::operator std::vector() const { std::vector ret; for (size_t i = 0; i < size(); i++) ret.push_back(std::string(this->get_field(i))); return ret; } /** Build a map from column names to values for a given row. */ CSV_INLINE std::unordered_map CSVRow::to_unordered_map() const { std::unordered_map row_map; row_map.reserve(this->size()); for (size_t i = 0; i < this->size(); i++) { auto col_name = (*this->data->col_names)[i]; row_map[col_name] = this->operator[](i).get(); } return row_map; } /** * Build a map from column names to values for a given row. * * @param[in] subset Vector of column names to include in the map. */ CSV_INLINE std::unordered_map CSVRow::to_unordered_map( const std::vector& subset ) const { std::unordered_map row_map; row_map.reserve(subset.size()); for (const auto& col_name : subset) row_map[col_name] = this->operator[](col_name).get(); return row_map; } CSV_INLINE csv::string_view CSVRow::get_field(size_t index) const { return this->get_field_impl(index, this->data); } CSV_INLINE csv::string_view CSVRow::get_field_safe(size_t index, internals::RawCSVDataPtr _data) const { return this->get_field_impl(index, _data); } CSV_INLINE bool CSVField::try_parse_decimal(long double& dVal, const char decimalSymbol) { // If field has already been parsed to empty, no need to do it aagin: if (this->_type == DataType::CSV_NULL) return false; // Not yet parsed or possibly parsed with other decimalSymbol if (this->_type == DataType::UNKNOWN || this->_type == DataType::CSV_STRING || this->_type == DataType::CSV_DOUBLE) this->_type = internals::data_type(this->sv, &this->value, decimalSymbol); // parse again // Integral types are not affected by decimalSymbol and need not be parsed again // Either we already had an integral type before, or we we just got any numeric type now. if (this->_type >= DataType::CSV_INT8 && this->_type <= DataType::CSV_DOUBLE) { dVal = this->value; return true; } // CSV_NULL or CSV_STRING, not numeric return false; } #ifdef _MSC_VER #pragma region CSVRow Iterator #endif /** Return an iterator pointing to the first field. */ CSV_INLINE CSVRow::iterator CSVRow::begin() const { return CSVRow::iterator(this, 0); } /** Return an iterator pointing to just after the end of the CSVRow. * * @warning Attempting to dereference the end iterator results * in dereferencing a null pointer. */ CSV_INLINE CSVRow::iterator CSVRow::end() const noexcept { return CSVRow::iterator(this, (int)this->size()); } CSV_INLINE CSVRow::reverse_iterator CSVRow::rbegin() const noexcept { return std::reverse_iterator(this->end()); } CSV_INLINE CSVRow::reverse_iterator CSVRow::rend() const { return std::reverse_iterator(this->begin()); } CSV_INLINE CSV_NON_NULL(2) CSVRow::iterator::iterator(const CSVRow* _reader, int _i) : daddy(_reader), data(_reader->data), i(_i) { if (_i < (int)this->daddy->size()) this->field = std::make_shared( CSVField(this->daddy->get_field_safe(_i, this->data))); else this->field = nullptr; } CSV_INLINE CSVRow::iterator::reference CSVRow::iterator::operator*() const { return *(this->field.get()); } CSV_INLINE CSVRow::iterator::pointer CSVRow::iterator::operator->() const { return this->field; } CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator++() { // Pre-increment operator this->i++; if (this->i < (int)this->daddy->size()) this->field = std::make_shared( CSVField(this->daddy->get_field_safe(i, this->data))); else // Reached the end of row this->field = nullptr; return *this; } CSV_INLINE CSVRow::iterator CSVRow::iterator::operator++(int) { // Post-increment operator auto temp = *this; this->operator++(); return temp; } CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator--() { // Pre-decrement operator this->i--; this->field = std::make_shared( CSVField(this->daddy->get_field_safe(this->i, this->data))); return *this; } CSV_INLINE CSVRow::iterator CSVRow::iterator::operator--(int) { // Post-decrement operator auto temp = *this; this->operator--(); return temp; } CSV_INLINE CSVRow::iterator CSVRow::iterator::operator+(difference_type n) const { // Allows for iterator arithmetic return CSVRow::iterator(this->daddy, i + (int)n); } CSV_INLINE CSVRow::iterator CSVRow::iterator::operator-(difference_type n) const { // Allows for iterator arithmetic return CSVRow::iterator::operator+(-n); } #ifdef _MSC_VER #pragma endregion CSVRow Iterator #endif } #include #include namespace csv { namespace internals { CSV_INLINE std::vector ColNames::get_col_names() const { return this->col_names; } CSV_INLINE void ColNames::set_col_names(const std::vector& cnames) { this->col_names = cnames; this->col_pos.clear(); for (size_t i = 0; i < cnames.size(); i++) { if (this->_policy == csv::ColumnNamePolicy::CASE_INSENSITIVE) { // For case-insensitive lookup, cache a lowercase version // of the column name in the map std::string lower(cnames[i]); std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); this->col_pos[lower] = i; } else { this->col_pos[cnames[i]] = i; } } } CSV_INLINE int ColNames::index_of(csv::string_view col_name) const { if (this->_policy == csv::ColumnNamePolicy::CASE_INSENSITIVE) { std::string lower(col_name); std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); auto pos = this->col_pos.find(lower); if (pos != this->col_pos.end()) return (int)pos->second; return CSV_NOT_FOUND; } auto pos = this->col_pos.find(col_name.data()); if (pos != this->col_pos.end()) return (int)pos->second; return CSV_NOT_FOUND; } CSV_INLINE void ColNames::set_policy(csv::ColumnNamePolicy policy) { this->_policy = policy; } CSV_INLINE size_t ColNames::size() const noexcept { return this->col_names.size(); } CSV_INLINE const std::string& ColNames::operator[](size_t i) const { if (i >= this->col_names.size()) throw std::out_of_range("Column index out of bounds."); return this->col_names[i]; } } } #endif foldynl-QLog-3252ff9/core/debug.cpp000066400000000000000000000023141517334601000171050ustar00rootroot00000000000000#include "debug.h" static bool logToFile = false; static QString debugLogFilename; bool isLogToFileEnabled() { return logToFile; } void setLogToFile(bool enabled) { logToFile = enabled; } QString currentDebugLogFilename() { return debugLogFilename; } void setCurrentDebugLogFilename(const QString &filename) { debugLogFilename = filename; } void set_debug_level(DEBUG_LEVEL_TYPE type) { switch ( type ) { case LEVEL_DEBUG_MAX: QLoggingCategory::setFilterRules("*.debug=true \n" "*.function.parameters=true \n" "*.function.entered=true\n"); break; case LEVEL_DEBUG_FUNCTION_PARAMETERS: QLoggingCategory::setFilterRules("*.function.parameters=true \n" "*.function.entered=true\n"); break; case LEVEL_DEBUG_FUNCTION_CALLS: QLoggingCategory::setFilterRules("*.function.parameters=false\n"); break; case LEVEL_DEBUG_RUNTIME: QLoggingCategory::setFilterRules("*.function.*=false\n"); break; case LEVEL_PRODUCTION: default: QLoggingCategory::setFilterRules("*.debug=false\n"); } } foldynl-QLog-3252ff9/core/debug.h000066400000000000000000000025431517334601000165560ustar00rootroot00000000000000#ifndef QLOG_CORE_DEBUG_LOG_H #define QLOG_CORE_DEBUG_LOG_H #include #include Q_DECLARE_LOGGING_CATEGORY(logGraphics) Q_DECLARE_LOGGING_CATEGORY(logPlugin) #define MODULE_IDENTIFICATION(m) static const char *mod_name = m; \ static const QLoggingCategory function_parameters(m".function.parameters"); \ static const QLoggingCategory runtime(m".runtime"); \ #define FCT_IDENTIFICATION QString logging_cat(mod_name); \ logging_cat.append(".function.entered"); \ QByteArray logging_cat_latin1 = logging_cat.toLatin1(); \ const char* category_name = logging_cat_latin1.isEmpty() ? "default_category" : logging_cat_latin1.constData(); \ QLoggingCategory log_category(category_name); \ qCDebug(log_category)<<"***" typedef enum debug_level { LEVEL_DEBUG_MAX, LEVEL_DEBUG_FUNCTION_PARAMETERS, LEVEL_DEBUG_FUNCTION_CALLS, LEVEL_DEBUG_RUNTIME, LEVEL_PRODUCTION } DEBUG_LEVEL_TYPE; void set_debug_level(DEBUG_LEVEL_TYPE); bool isLogToFileEnabled(); void setLogToFile(bool enabled); void closeDebugLogFile(); QString currentDebugLogFilename(); void setCurrentDebugLogFilename(const QString &filename); #endif // QLOG_CORE_DEBUG_LOG_H foldynl-QLog-3252ff9/core/main.cpp000066400000000000000000000416311517334601000167500ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "Migration.h" #include "ui/MainWindow.h" #include "rig/Rig.h" #include "rotator/Rotator.h" #include "cwkey/CWKeyer.h" #include "AppGuard.h" #include "core/zonedetect.h" #include "ui/SplashScreen.h" #include "core/MembershipQE.h" #include "service/kstchat/KSTChat.h" #include "data/Data.h" #include "service/GenericCallbook.h" #include "core/LogDatabase.h" MODULE_IDENTIFICATION("qlog.core.main"); static QMutex debug_mutex; static QFile debugLogFile; static QTextStream debugLogStream; QTemporaryDir tempDir #ifdef QLOG_FLATPAK // hack: I don't know how to openn image file // in sandbox via QDesktop::openurl // therefore QLog creates a temp directory in home directory (home is allowed for flatpak) (QDir::homePath() + "/.qlogXXXXXX"); #else ; #endif static void setupTranslator(QApplication* app, const QString &lang, const QString &translationFile) { FCT_IDENTIFICATION; qCDebug(function_parameters) << lang << translationFile; QString localeLang = ( lang.isEmpty() ) ? QLocale::system().name() : lang; QTranslator* qtTranslator = new QTranslator(app); if ( qtTranslator->load("qt_" + localeLang, #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) QLibraryInfo::location(QLibraryInfo::TranslationsPath)) ) #else QLibraryInfo::path(QLibraryInfo::TranslationsPath)) ) #endif { app->installTranslator(qtTranslator); } // give translators the ability to dynamically load files. // first, try to load file from input parameter (if exsist) if ( !translationFile.isEmpty() ) { qCDebug(runtime) << "External translation file defined - trying to load it"; QTranslator* translator = new QTranslator(app); if ( translator->load(translationFile) ) { qCDebug(runtime) << "Loaded successfully" #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) << translator->filePath() #endif ; app->installTranslator(translator); return; } qWarning() << "External translation file not found"; translator->deleteLater(); } // searching in the following directories // Linux: // application_folder/i18n // "~/.local/share/hamradio/QLog/i18n", // "/usr/local/share/hamradion/QLog/i18n", // "/usr/share/hamradio/QLog/i18n" // // looking for filename // qlog.fr_ca.qm // qlog.fr_ca // qlog.fr.qm // qlog.fr // qlog.qm // qlog QStringList translationFolders; translationFolders << qApp->applicationDirPath() << QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation); for ( const QString& folder : static_cast(translationFolders) ) { qCDebug(runtime) << "Looking for a translation in" << folder << QString("i18n%1qlog_%2").arg(QDir::separator(), localeLang); QTranslator* translator = new QTranslator(app); if ( translator->load(QStringLiteral("i18n%1qlog_%2").arg(QDir::separator(), localeLang), folder) ) { qCDebug(runtime) << "Loaded successfully" #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) << translator->filePath() #endif ; app->installTranslator(translator); return; } translator->deleteLater(); } // last attempt - build-in resources/i18n. qCDebug(runtime) << "Looking for a translation in QLog's resources"; QTranslator* translator = new QTranslator(app); if ( translator->load(":/i18n/qlog_" + localeLang) ) { qCDebug(runtime) << "Loaded successfully" #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) << translator->filePath() #endif ; app->installTranslator(translator); return; } translator->deleteLater(); qCDebug(runtime) << "Cannot find any translation file"; } static void createDataDirectory() { FCT_IDENTIFICATION; QDir dataDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); qCDebug(runtime) << dataDir.path(); if (!dataDir.exists()) { dataDir.mkpath(dataDir.path()); } } static void startRigThread() { FCT_IDENTIFICATION; QThread* rigThread = new QThread; Rig* rig = Rig::instance(); rig->moveToThread(rigThread); QObject::connect(rigThread, SIGNAL(started()), rig, SLOT(start())); rigThread->start(); } static void startRotThread() { FCT_IDENTIFICATION; QThread* rotThread = new QThread; Rotator* rot = Rotator::instance(); rot->moveToThread(rotThread); QObject::connect(rotThread, SIGNAL(started()), rot, SLOT(start())); rotThread->start(); } static void startCWKeyerThread() { FCT_IDENTIFICATION; QThread* cwKeyerThread = new QThread; CWKeyer* cwKeyer = CWKeyer::instance(); cwKeyer->moveToThread(cwKeyerThread); QObject::connect(cwKeyerThread, SIGNAL(started()), cwKeyer, SLOT(start())); cwKeyerThread->start(); } void closeDebugLogFile() { QMutexLocker locker(&debug_mutex); if ( debugLogFile.isOpen() ) { debugLogStream.flush(); debugLogStream.setDevice(nullptr); debugLogFile.close(); } } static void debugMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QMutexLocker locker(&debug_mutex); if ( isLogToFileEnabled() && !debugLogFile.isOpen() ) { const QString filename = Data::debugFilename(); debugLogFile.setFileName(filename); if ( debugLogFile.open(QIODevice::WriteOnly | QIODevice::Text) ) { setCurrentDebugLogFilename(filename); debugLogStream.setDevice(&debugLogFile); debugLogStream << "App: " << QCoreApplication::applicationVersion() << "\n" #ifdef QLOG_FLATPAK << "Flatpak" << "\n" #endif << "QT: " << qVersion() << "\n" << "OS: " << QString("%1 %2 (%3)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture(), QGuiApplication::platformName() ) << "\n" << "SSL: " << QSslSocket::sslLibraryVersionString() << "\n\n"; } else { qWarning() << "Cannot open the file for log"; setLogToFile(false); } } const char *severity_string = nullptr; switch ( type ) { case QtDebugMsg: severity_string = "[DEBUG ]"; break; case QtInfoMsg: severity_string = "[INFO ]"; break; case QtWarningMsg: severity_string = "[WARNING ]"; break; case QtCriticalMsg: severity_string = "[CRITICAL]"; break; case QtFatalMsg: severity_string = "[FATAL ]"; break; default: severity_string = "[UNKNOWN ]"; } const QString &category = QString("[%1]").arg(context.category).leftJustified(50, ' '); const QString &logEntry = QString("%1 %2 [0x%3] %4 %5 [%6:%7:%8]\n") .arg(QTime::currentTime().toString("HH:mm:ss.zzz")) .arg(severity_string) .arg(QString::number(reinterpret_cast(QThread::currentThreadId()), 16)) .arg(category) .arg(msg) .arg(context.function ? context.function : "unknown") .arg(context.file ? context.file : "unknown") .arg(context.line); if ( isLogToFileEnabled() && debugLogFile.isOpen() ) { debugLogStream << logEntry; debugLogStream.flush(); } fprintf(stderr, "%s", logEntry.toUtf8().constData()); if ( type == QtFatalMsg ) { if (debugLogFile.isOpen()) debugLogFile.close(); abort(); } } #ifdef Q_OS_LINUX void wayland_hacks() { // due to QT's issue, Dock widget is not working (cannot be docked) under QT5, < ?6.7? on Linux // Therefore it is necessary to force set XCB (X11) const QByteArray &sessionType = qgetenv("XDG_SESSION_TYPE").toLower(); const QByteArray &disableXCBFallback = qgetenv("QLOG_DISABLE_XCB"); if ( sessionType.contains("wayland") && disableXCBFallback == QByteArray() ) { qInfo() << "Force XCB"; qputenv("QT_QPA_PLATFORM", "xcb"); } } #endif int main(int argc, char* argv[]) { #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif #ifdef Q_OS_LINUX wayland_hacks(); #endif bool stylePresent = false; /* Style option is deleted in QApplication constructor. * Therefore test for the parameter presence has to be performed here */ for ( int i = 0; i < argc && !stylePresent; i++ ) { stylePresent = QString(argv[i]).contains("-style"); } QApplication app(argc, argv); app.setApplicationVersion(VERSION); QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::tr("QLog Help")); parser.addHelpOption(); parser.addVersionOption(); /* Undocumented param used for debugging. A developer can run QLog with * a specific namespace. This helps in cases where it is possible * to simultaneously run a test/develop and production versions of QLog. * * The parameter changes the Application name. It causes that all runtime * files, settings, passwords and DB file are created in a different directory/namespace. * * however, it remains necessary only one instance of QLog to run at a time. * More Notes below (AppGuard Comment). * * NOTE: This is not a preparation for the ability to run separate databases. * It's just to make it easier for developers and testers. */ QCommandLineOption environmentName(QStringList() << "n" << "namespace", QCoreApplication::translate("main", "Run with the specific namespace."), QCoreApplication::translate("main", "namespace")); QCommandLineOption translationFilename(QStringList() << "t" << "translation", QCoreApplication::translate("main", "Translation file - absolute or relative path and QM file name."), QCoreApplication::translate("main", "path/QM-filename")); QCommandLineOption forceLanguage(QStringList() << "l" << "language", QCoreApplication::translate("main", "Set language. example: 'en' or 'en_US'. Ignore environment setting."), QCoreApplication::translate("main", "code")); QCommandLineOption debugFile(QStringList() << "d" << "debug", QCoreApplication::translate("main", "Writes debug messages to the debug file")); QCommandLineOption importPending("import-pending", QCoreApplication::translate("main", "Process pending database import (internal use)")); QCommandLineOption forceLOVUpdate(QStringList() << "f" << "force-update", QCoreApplication::translate("main", "Force update of all value lists (DXCC, SATs, etc.)")); parser.addOption(environmentName); parser.addOption(translationFilename); parser.addOption(forceLanguage); parser.addOption(debugFile); parser.addOption(importPending); parser.addOption(forceLOVUpdate); parser.process(app); QString environment = parser.value(environmentName); QString translation_file = parser.value(translationFilename); QString lang = parser.value(forceLanguage); setLogToFile(parser.isSet(debugFile)); bool isImportPending = parser.isSet(importPending); bool isForceLOVUpdate = parser.isSet(forceLOVUpdate); // If started with --import-pending, wait a bit for the previous instance to fully terminate if ( isImportPending ) { qCDebug(runtime) << "Start postponed"; QCoreApplication::processEvents(); QThread::msleep(1000); } app.setOrganizationName("hamradio"); app.setApplicationName("QLog" + ((environment.isEmpty()) ? "" : environment.prepend("-"))); /* If the Style parameter is not present then use a default - Fusion style */ if ( !stylePresent ) { app.setStyle(QStyleFactory::create("Fusion")); } qInstallMessageHandler(debugMessageOutput); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType>(); qRegisterMetaType(); qRegisterMetaType(); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) qRegisterMetaTypeStreamOperators>("QSet"); #endif qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); set_debug_level(LEVEL_PRODUCTION); // you can set more verbose rules via // environment variable QT_LOGGING_RULES (project setting/debug) setupTranslator(&app, lang, translation_file); /* Application Singleton * * Only one instance of QLog application is allowed * * It is always necessary to run only one QLog on the * system, because the FLDigi interface has a fixed port. * Therefore, in the case of two or more instances, * there is a port conflict. */ AppGuard guard( "QLog" ); if ( !guard.tryToRun() ) { QMessageBox::critical(nullptr, QMessageBox::tr("QLog Error"), QMessageBox::tr("QLog is already running")); return 1; } QPixmap pixmap(":/res/qlog.png"); SplashScreen splash(pixmap); splash.show(); splash.ensureFirstPaint(); createDataDirectory(); // Process pending database import if exists if ( LogDatabase::hasPendingImport() ) { splash.showMessage(QObject::tr("Importing Database"), Qt::AlignBottom|Qt::AlignCenter); QCoreApplication::processEvents(); if ( !LogDatabase::instance()->processPendingImport() ) { QMessageBox::critical(nullptr, QMessageBox::tr("QLog Error"), QMessageBox::tr("Failed to process pending database import.")); return 1; } if ( LogDatabase::instance()->hadPasswordImportWarning() ) { QMessageBox::warning(nullptr, QMessageBox::tr("QLog Warning"), QMessageBox::tr("The database was imported successfully, but the stored passwords " "could not be restored (decryption failed or the data is corrupted). " "All service passwords have been cleared and must be re-entered in Settings.")); } } else { splash.showMessage(QObject::tr("Opening Database"), Qt::AlignBottom|Qt::AlignCenter); QCoreApplication::processEvents(); if ( ! LogDatabase::instance()->openDatabase() ) { QMessageBox::critical(nullptr, QMessageBox::tr("QLog Error"), QMessageBox::tr("Could not connect to database.")); return 1; } splash.showMessage(QObject::tr("Backuping Database"), Qt::AlignBottom|Qt::AlignCenter); QCoreApplication::processEvents(); /* a migration can break a database therefore a backup is call before it */ if (!DBSchemaMigration::backupAllQSOsToADX()) { QMessageBox::critical(nullptr, QMessageBox::tr("QLog Error"), QMessageBox::tr("Could not export a QLog database to ADIF as a backup.

Try to export your log to ADIF manually")); } splash.showMessage(QObject::tr("Migrating Database"), Qt::AlignBottom|Qt::AlignCenter); QCoreApplication::processEvents(); if ( ! LogDatabase::instance()->schemaVersionUpgrade(isForceLOVUpdate) ) { QMessageBox::critical(nullptr, QMessageBox::tr("QLog Error"), QMessageBox::tr("Database migration failed.")); return 1; } } splash.showMessage(QObject::tr("Starting Application"), Qt::AlignBottom|Qt::AlignCenter); QCoreApplication::processEvents(); startRigThread(); startRotThread(); startCWKeyerThread(); MainWindow w; QIcon icon(":/res/qlog.png"); w.setWindowIcon(icon); splash.finish(&w); w.show(); w.setLayoutGeometry(); // check version only for Windows and MacOS. Linux has own distribution points #if defined(Q_OS_WIN) || defined(Q_OS_MAC) w.checkNewVersion(); #endif return app.exec(); } foldynl-QLog-3252ff9/core/zonedetect.c000066400000000000000000001131771517334601000176350ustar00rootroot00000000000000/* * Copyright (c) 2018, Bertold Van den Bergh (vandenbergh@bertold.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the author nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTOR 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. */ /* https://github.com/BertoldVdb/ZoneDetect/tree/master/library */ #include #include #include #include #include #include #include #if defined(_MSC_VER) || defined(__MINGW32__) #include #elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) #include #include #include #include #endif #include "zonedetect.h" enum ZDInternalError { ZD_OK, ZD_E_DB_OPEN, ZD_E_DB_SEEK, ZD_E_DB_MMAP, #if defined(_MSC_VER) || defined(__MINGW32__) ZD_E_DB_MMAP_MSVIEW, ZD_E_DB_MAP_EXCEPTION, ZD_E_DB_MUNMAP_MSVIEW, #endif ZD_E_DB_MUNMAP, ZD_E_DB_CLOSE, ZD_E_PARSE_HEADER }; struct ZoneDetectOpaque { #if defined(_MSC_VER) || defined(__MINGW32__) HANDLE fd; HANDLE fdMap; int32_t length; int32_t padding; #elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) int fd; off_t length; #else int length; #endif uint8_t closeType; uint8_t *mapping; uint8_t tableType; uint8_t version; uint8_t precision; uint8_t numFields; char *notice; char **fieldNames; uint32_t bboxOffset; uint32_t metadataOffset; uint32_t dataOffset; }; static void (*zdErrorHandler)(int, int); static void zdError(enum ZDInternalError errZD, int errNative) { if (zdErrorHandler) zdErrorHandler((int)errZD, errNative); } static int32_t ZDFloatToFixedPoint(float input, float scale, unsigned int precision) { const float inputScaled = input / scale; return (int32_t)(inputScaled * (float)(1 << (precision - 1))); } static float ZDFixedPointToFloat(int32_t input, float scale, unsigned int precision) { const float value = (float)input / (float)(1 << (precision - 1)); return value * scale; } static unsigned int ZDDecodeVariableLengthUnsigned(const ZoneDetect *library, uint32_t *index, uint64_t *result) { if(*index >= (uint32_t)library->length) { return 0; } uint64_t value = 0; unsigned int i = 0; #if defined(_MSC_VER) __try { #endif uint8_t *const buffer = library->mapping + *index; uint8_t *const bufferEnd = library->mapping + library->length - 1; unsigned int shift = 0; while(1) { value |= ((((uint64_t)buffer[i]) & UINT8_C(0x7F)) << shift); shift += 7u; if(!(buffer[i] & UINT8_C(0x80))) { break; } i++; if(buffer + i > bufferEnd) { return 0; } } #if defined(_MSC_VER) } __except(GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ zdError(ZD_E_DB_MAP_EXCEPTION, (int)GetLastError()); return 0; } #endif i++; *result = value; *index += i; return i; } static unsigned int ZDDecodeVariableLengthUnsignedReverse(const ZoneDetect *library, uint32_t *index, uint64_t *result) { uint32_t i = *index; if(*index >= (uint32_t)library->length) { return 0; } #if defined(_MSC_VER) __try { #endif if(library->mapping[i] & UINT8_C(0x80)) { return 0; } if(!i) { return 0; } i--; while(library->mapping[i] & UINT8_C(0x80)) { if(!i) { return 0; } i--; } #if defined(_MSC_VER) } __except(GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ zdError(ZD_E_DB_MAP_EXCEPTION, (int)GetLastError()); return 0; } #endif *index = i; i++; uint32_t i2 = i; return ZDDecodeVariableLengthUnsigned(library, &i2, result); } static int64_t ZDDecodeUnsignedToSigned(uint64_t value) { return (value & 1) ? -(int64_t)(value / 2) : (int64_t)(value / 2); } static unsigned int ZDDecodeVariableLengthSigned(const ZoneDetect *library, uint32_t *index, int32_t *result) { uint64_t value = 0; const unsigned int retVal = ZDDecodeVariableLengthUnsigned(library, index, &value); *result = (int32_t)ZDDecodeUnsignedToSigned(value); return retVal; } static char *ZDParseString(const ZoneDetect *library, uint32_t *index) { uint64_t strLength; if(!ZDDecodeVariableLengthUnsigned(library, index, &strLength)) { return NULL; } uint32_t strOffset = *index; unsigned int remoteStr = 0; if(strLength >= 256) { strOffset = library->metadataOffset + (uint32_t)strLength - 256; remoteStr = 1; if(!ZDDecodeVariableLengthUnsigned(library, &strOffset, &strLength)) { return NULL; } if(strLength > 256) { return NULL; } } char *const str = malloc((size_t)(strLength + 1)); if(str) { #if defined(_MSC_VER) __try { #endif size_t i; for(i = 0; i < strLength; i++) { str[i] = (char)(library->mapping[strOffset + i] ^ UINT8_C(0x80)); } #if defined(_MSC_VER) } __except(GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ zdError(ZD_E_DB_MAP_EXCEPTION, (int)GetLastError()); return 0; } #endif str[strLength] = 0; } if(!remoteStr) { *index += (uint32_t)strLength; } return str; } static int ZDParseHeader(ZoneDetect *library) { if(library->length < 7) { return -1; } #if defined(_MSC_VER) __try { #endif if(memcmp(library->mapping, "PLB", 3)) { return -1; } library->tableType = library->mapping[3]; library->version = library->mapping[4]; library->precision = library->mapping[5]; library->numFields = library->mapping[6]; #if defined(_MSC_VER) } __except(GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ zdError(ZD_E_DB_MAP_EXCEPTION, (int)GetLastError()); return 0; } #endif if(library->version >= 2) { return -1; } uint32_t index = UINT32_C(7); library->fieldNames = malloc(library->numFields * sizeof *library->fieldNames); if (!library->fieldNames) { return -1; } size_t i; for(i = 0; i < library->numFields; i++) { library->fieldNames[i] = ZDParseString(library, &index); } library->notice = ZDParseString(library, &index); if(!library->notice) { return -1; } uint64_t tmp; /* Read section sizes */ /* By memset: library->bboxOffset = 0 */ if(!ZDDecodeVariableLengthUnsigned(library, &index, &tmp)) return -1; library->metadataOffset = (uint32_t)tmp + library->bboxOffset; if(!ZDDecodeVariableLengthUnsigned(library, &index, &tmp))return -1; library->dataOffset = (uint32_t)tmp + library->metadataOffset; if(!ZDDecodeVariableLengthUnsigned(library, &index, &tmp)) return -1; /* Add header size to everything */ library->bboxOffset += index; library->metadataOffset += index; library->dataOffset += index; /* Verify file length */ if(tmp + library->dataOffset != (uint32_t)library->length) { return -2; } return 0; } static int ZDPointInBox(int32_t xl, int32_t x, int32_t xr, int32_t yl, int32_t y, int32_t yr) { if((xl <= x && x <= xr) || (xr <= x && x <= xl)) { if((yl <= y && y <= yr) || (yr <= y && y <= yl)) { return 1; } } return 0; } static uint32_t ZDUnshuffle(uint64_t w) { w &= 0x5555555555555555llu; w = (w | (w >> 1)) & 0x3333333333333333llu; w = (w | (w >> 2)) & 0x0F0F0F0F0F0F0F0Fllu; w = (w | (w >> 4)) & 0x00FF00FF00FF00FFllu; w = (w | (w >> 8)) & 0x0000FFFF0000FFFFllu; w = (w | (w >> 16)) & 0x00000000FFFFFFFFllu; return (uint32_t)w; } static void ZDDecodePoint(uint64_t point, int32_t* lat, int32_t* lon) { *lat = (int32_t)ZDDecodeUnsignedToSigned(ZDUnshuffle(point)); *lon = (int32_t)ZDDecodeUnsignedToSigned(ZDUnshuffle(point >> 1)); } struct Reader { const ZoneDetect *library; uint32_t polygonIndex; uint64_t numVertices; uint8_t done, first; uint32_t referenceStart, referenceEnd; int32_t referenceDirection; int32_t pointLat, pointLon; int32_t firstLat, firstLon; }; static void ZDReaderInit(struct Reader *reader, const ZoneDetect *library, uint32_t polygonIndex) { memset(reader, 0, sizeof(*reader)); reader->library = library; reader->polygonIndex = polygonIndex; reader->first = 1; } static int ZDReaderGetPoint(struct Reader *reader, int32_t *pointLat, int32_t *pointLon) { int32_t diffLat = 0, diffLon = 0; readNewPoint: if(reader->done > 1) { return 0; } if(reader->first && reader->library->version == 0) { if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &reader->numVertices)) return -1; if(!reader->numVertices) return -1; } uint8_t referenceDone = 0; if(reader->library->version == 1) { uint64_t point = 0; if(!reader->referenceDirection) { if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &point)) return -1; } else { if(reader->referenceDirection > 0) { /* Read reference forward */ if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->referenceStart, &point)) return -1; if(reader->referenceStart >= reader->referenceEnd) { referenceDone = 1; } } else if(reader->referenceDirection < 0) { /* Read reference backwards */ if(!ZDDecodeVariableLengthUnsignedReverse(reader->library, &reader->referenceStart, &point)) return -1; if(reader->referenceStart <= reader->referenceEnd) { referenceDone = 1; } } } if(!point) { /* This is a special marker, it is not allowed in reference mode */ if(reader->referenceDirection) { return -1; } uint64_t value; if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &value)) return -1; if(value == 0) { reader->done = 2; } else if(value == 1) { int32_t diff; int64_t start; if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, (uint64_t*)&start)) return -1; if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diff)) return -1; reader->referenceStart = reader->library->dataOffset+(uint32_t)start; reader->referenceEnd = reader->library->dataOffset+(uint32_t)(start + diff); reader->referenceDirection = diff; if(diff < 0) { reader->referenceStart--; reader->referenceEnd--; } goto readNewPoint; } } else { ZDDecodePoint(point, &diffLat, &diffLon); if(reader->referenceDirection < 0) { diffLat = -diffLat; diffLon = -diffLon; } } } if(reader->library->version == 0) { if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLat)) return -1; if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLon)) return -1; } if(!reader->done) { reader->pointLat += diffLat; reader->pointLon += diffLon; if(reader->first) { reader->firstLat = reader->pointLat; reader->firstLon = reader->pointLon; } } else { /* Close the polygon (the closing point is not encoded) */ reader->pointLat = reader->firstLat; reader->pointLon = reader->firstLon; reader->done = 2; } reader->first = 0; if(reader->library->version == 0) { reader->numVertices--; if(!reader->numVertices) { reader->done = 1; } if(!diffLat && !diffLon) { goto readNewPoint; } } if(referenceDone) { reader->referenceDirection = 0; } if(pointLat) { *pointLat = reader->pointLat; } if(pointLon) { *pointLon = reader->pointLon; } return 1; } static int ZDFindPolygon(const ZoneDetect *library, uint32_t wantedId, uint32_t* metadataIndexPtr, uint32_t* polygonIndexPtr) { uint32_t polygonId = 0; uint32_t bboxIndex = library->bboxOffset; uint32_t metadataIndex = 0, polygonIndex = 0; while(bboxIndex < library->metadataOffset) { uint64_t polygonIndexDelta; int32_t metadataIndexDelta; int32_t tmp; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &metadataIndexDelta)) break; if(!ZDDecodeVariableLengthUnsigned(library, &bboxIndex, &polygonIndexDelta)) break; metadataIndex += (uint32_t)metadataIndexDelta; polygonIndex += (uint32_t)polygonIndexDelta; if(polygonId == wantedId) { if(metadataIndexPtr) { metadataIndex += library->metadataOffset; *metadataIndexPtr = metadataIndex; } if(polygonIndexPtr) { polygonIndex += library->dataOffset; *polygonIndexPtr = polygonIndex; } return 1; } polygonId ++; } return 0; } static int32_t* ZDPolygonToListInternal(const ZoneDetect *library, uint32_t polygonIndex, size_t* length) { struct Reader reader; ZDReaderInit(&reader, library, polygonIndex); size_t listLength = 2 * 100; size_t listIndex = 0; int32_t* list = malloc(sizeof(int32_t) * listLength); if(!list) { goto fail; } while(1) { int32_t pointLat, pointLon; int result = ZDReaderGetPoint(&reader, &pointLat, &pointLon); if(result < 0) { goto fail; } else if(result == 0) { break; } if(listIndex >= listLength) { listLength *= 2; if(listLength >= 1048576) { goto fail; } list = realloc(list, sizeof(int32_t) * listLength); if(!list) { goto fail; } } list[listIndex++] = pointLat; list[listIndex++] = pointLon; } if(length) { *length = listIndex; } return list; fail: if(list) { free(list); } return NULL; } float* ZDPolygonToList(const ZoneDetect *library, uint32_t polygonId, size_t* lengthPtr) { uint32_t polygonIndex; int32_t* data = NULL; float* flData = NULL; if(!ZDFindPolygon(library, polygonId, NULL, &polygonIndex)) { goto fail; } size_t length = 0; data = ZDPolygonToListInternal(library, polygonIndex, &length); if(!data) { goto fail; } flData = malloc(sizeof(float) * length); if(!flData) { goto fail; } size_t i; for(i = 0; iprecision); flData[i+1] = ZDFixedPointToFloat(lon, 180, library->precision); } if(lengthPtr) { *lengthPtr = length; } return flData; fail: if(data) { free(data); } if(flData) { free(flData); } return NULL; } static ZDLookupResult ZDPointInPolygon(const ZoneDetect *library, uint32_t polygonIndex, int32_t latFixedPoint, int32_t lonFixedPoint, uint64_t *distanceSqrMin) { int32_t pointLat, pointLon, prevLat = 0, prevLon = 0; int prevQuadrant = 0, winding = 0; uint8_t first = 1; struct Reader reader; ZDReaderInit(&reader, library, polygonIndex); while(1) { int result = ZDReaderGetPoint(&reader, &pointLat, &pointLon); if(result < 0) { return ZD_LOOKUP_PARSE_ERROR; } else if(result == 0) { break; } /* Check if point is ON the border */ if(pointLat == latFixedPoint && pointLon == lonFixedPoint) { if(distanceSqrMin) *distanceSqrMin = 0; return ZD_LOOKUP_ON_BORDER_VERTEX; } /* Find quadrant */ int quadrant; if(pointLat >= latFixedPoint) { if(pointLon >= lonFixedPoint) { quadrant = 0; } else { quadrant = 1; } } else { if(pointLon >= lonFixedPoint) { quadrant = 3; } else { quadrant = 2; } } if(!first) { int windingNeedCompare = 0, lineIsStraight = 0; float a = 0, b = 0; /* Calculate winding number */ if(quadrant == prevQuadrant) { /* Do nothing */ } else if(quadrant == (prevQuadrant + 1) % 4) { winding ++; } else if((quadrant + 1) % 4 == prevQuadrant) { winding --; } else { windingNeedCompare = 1; } /* Avoid horizontal and vertical lines */ if((pointLon == prevLon || pointLat == prevLat)) { lineIsStraight = 1; } /* Calculate the parameters of y=ax+b if needed */ if(!lineIsStraight && (distanceSqrMin || windingNeedCompare)) { a = ((float)pointLat - (float)prevLat) / ((float)pointLon - (float)prevLon); b = (float)pointLat - a * (float)pointLon; } int onStraight = ZDPointInBox(pointLat, latFixedPoint, prevLat, pointLon, lonFixedPoint, prevLon); if(lineIsStraight && (onStraight || windingNeedCompare)) { if(distanceSqrMin) *distanceSqrMin = 0; return ZD_LOOKUP_ON_BORDER_SEGMENT; } /* Jumped two quadrants. */ if(windingNeedCompare) { /* Check if the target is on the border */ const int32_t intersectLon = (int32_t)(((float)latFixedPoint - b) / a); if(intersectLon >= lonFixedPoint-1 && intersectLon <= lonFixedPoint+1) { if(distanceSqrMin) *distanceSqrMin = 0; return ZD_LOOKUP_ON_BORDER_SEGMENT; } /* Ok, it's not. In which direction did we go round the target? */ const int sign = (intersectLon < lonFixedPoint) ? 2 : -2; if(quadrant == 2 || quadrant == 3) { winding += sign; } else { winding -= sign; } } /* Calculate closest point on line (if needed) */ if(distanceSqrMin) { float closestLon, closestLat; if(!lineIsStraight) { closestLon = ((float)lonFixedPoint + a * (float)latFixedPoint - a * b) / (a * a + 1); closestLat = (a * ((float)lonFixedPoint + a * (float)latFixedPoint) + b) / (a * a + 1); } else { if(pointLon == prevLon) { closestLon = (float)pointLon; closestLat = (float)latFixedPoint; } else { closestLon = (float)lonFixedPoint; closestLat = (float)pointLat; } } const int closestInBox = ZDPointInBox(pointLon, (int32_t)closestLon, prevLon, pointLat, (int32_t)closestLat, prevLat); int64_t diffLat, diffLon; if(closestInBox) { /* Calculate squared distance to segment. */ diffLat = (int64_t)(closestLat - (float)latFixedPoint); diffLon = (int64_t)(closestLon - (float)lonFixedPoint); } else { /* * Calculate squared distance to vertices * It is enough to check the current point since the polygon is closed. */ diffLat = (int64_t)(pointLat - latFixedPoint); diffLon = (int64_t)(pointLon - lonFixedPoint); } /* Note: lon has half scale */ uint64_t distanceSqr = (uint64_t)(diffLat * diffLat) + (uint64_t)(diffLon * diffLon) * 4; if(distanceSqr < *distanceSqrMin) *distanceSqrMin = distanceSqr; } } prevQuadrant = quadrant; prevLat = pointLat; prevLon = pointLon; first = 0; }; if(winding == -4) { return ZD_LOOKUP_IN_ZONE; } else if(winding == 4) { return ZD_LOOKUP_IN_EXCLUDED_ZONE; } else if(winding == 0) { return ZD_LOOKUP_NOT_IN_ZONE; } /* Should not happen */ if(distanceSqrMin) *distanceSqrMin = 0; return ZD_LOOKUP_ON_BORDER_SEGMENT; } void ZDCloseDatabase(ZoneDetect *library) { if(library) { if(library->fieldNames) { size_t i; for(i = 0; i < (size_t)library->numFields; i++) { if(library->fieldNames[i]) { free(library->fieldNames[i]); } } free(library->fieldNames); } if(library->notice) { free(library->notice); } if(library->closeType == 0) { #if defined(_MSC_VER) || defined(__MINGW32__) if(library->mapping && !UnmapViewOfFile(library->mapping)) zdError(ZD_E_DB_MUNMAP_MSVIEW, (int)GetLastError()); if(library->fdMap && !CloseHandle(library->fdMap)) zdError(ZD_E_DB_MUNMAP, (int)GetLastError()); if(library->fd && !CloseHandle(library->fd)) zdError(ZD_E_DB_CLOSE, (int)GetLastError()); #elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) if(library->mapping && munmap(library->mapping, (size_t)(library->length))) zdError(ZD_E_DB_MUNMAP, 0); if(library->fd >= 0 && close(library->fd)) zdError(ZD_E_DB_CLOSE, 0); #endif } free(library); } } ZoneDetect *ZDOpenDatabaseFromMemory(void* buffer, size_t length) { ZoneDetect *const library = malloc(sizeof *library); if(library) { memset(library, 0, sizeof(*library)); library->closeType = 1; library->length = (long int)length; if(library->length <= 0) { #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) zdError(ZD_E_DB_SEEK, errno); #else zdError(ZD_E_DB_SEEK, 0); #endif goto fail; } library->mapping = buffer; /* Parse the header */ if(ZDParseHeader(library)) { zdError(ZD_E_PARSE_HEADER, 0); goto fail; } } return library; fail: ZDCloseDatabase(library); return NULL; } ZoneDetect *ZDOpenDatabase(const char *path) { ZoneDetect *const library = malloc(sizeof *library); if(library) { memset(library, 0, sizeof(*library)); #if defined(_MSC_VER) || defined(__MINGW32__) library->fd = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (library->fd == INVALID_HANDLE_VALUE) { zdError(ZD_E_DB_OPEN, (int)GetLastError()); goto fail; } const DWORD fsize = GetFileSize(library->fd, NULL); if (fsize == INVALID_FILE_SIZE) { zdError(ZD_E_DB_SEEK, (int)GetLastError()); goto fail; } library->length = (int32_t)fsize; library->fdMap = CreateFileMappingA(library->fd, NULL, PAGE_READONLY, 0, 0, NULL); if (!library->fdMap) { zdError(ZD_E_DB_MMAP, (int)GetLastError()); goto fail; } library->mapping = MapViewOfFile(library->fdMap, FILE_MAP_READ, 0, 0, 0); if (!library->mapping) { zdError(ZD_E_DB_MMAP_MSVIEW, (int)GetLastError()); goto fail; } #elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) library->fd = open(path, O_RDONLY | O_CLOEXEC); if(library->fd < 0) { zdError(ZD_E_DB_OPEN, errno); goto fail; } library->length = lseek(library->fd, 0, SEEK_END); if(library->length <= 0 || library->length > 50331648) { zdError(ZD_E_DB_SEEK, errno); goto fail; } lseek(library->fd, 0, SEEK_SET); library->mapping = mmap(NULL, (size_t)library->length, PROT_READ, MAP_PRIVATE | MAP_FILE, library->fd, 0); if(library->mapping == MAP_FAILED) { zdError(ZD_E_DB_MMAP, errno); goto fail; } #endif /* Parse the header */ if(ZDParseHeader(library)) { zdError(ZD_E_PARSE_HEADER, 0); goto fail; } } return library; fail: ZDCloseDatabase(library); return NULL; } ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, float *safezone) { const int32_t latFixedPoint = ZDFloatToFixedPoint(lat, 90, library->precision); const int32_t lonFixedPoint = ZDFloatToFixedPoint(lon, 180, library->precision); size_t numResults = 0; uint64_t distanceSqrMin = (uint64_t)-1; /* Iterate over all polygons */ uint32_t bboxIndex = library->bboxOffset; uint32_t metadataIndex = 0; uint32_t polygonIndex = 0; ZoneDetectResult *results = malloc(sizeof *results); if(!results) { return NULL; } uint32_t polygonId = 0; while(bboxIndex < library->metadataOffset) { int32_t minLat, minLon, maxLat, maxLon, metadataIndexDelta; uint64_t polygonIndexDelta; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &minLat)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &minLon)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &maxLat)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &maxLon)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &metadataIndexDelta)) break; if(!ZDDecodeVariableLengthUnsigned(library, &bboxIndex, &polygonIndexDelta)) break; metadataIndex += (uint32_t)metadataIndexDelta; polygonIndex += (uint32_t)polygonIndexDelta; if(latFixedPoint >= minLat) { if(latFixedPoint <= maxLat && lonFixedPoint >= minLon && lonFixedPoint <= maxLon) { const ZDLookupResult lookupResult = ZDPointInPolygon(library, library->dataOffset + polygonIndex, latFixedPoint, lonFixedPoint, (safezone) ? &distanceSqrMin : NULL); if(lookupResult == ZD_LOOKUP_PARSE_ERROR) { break; } else if(lookupResult != ZD_LOOKUP_NOT_IN_ZONE) { ZoneDetectResult *const newResults = realloc(results, sizeof *newResults * (numResults + 2)); if(newResults) { results = newResults; results[numResults].polygonId = polygonId; results[numResults].metaId = metadataIndex; results[numResults].numFields = library->numFields; results[numResults].fieldNames = library->fieldNames; results[numResults].lookupResult = lookupResult; numResults++; } else { break; } } } } else { /* The data is sorted along minLat */ break; } polygonId++; } /* Clean up results */ size_t i; for(i = 0; i < numResults; i++) { int insideSum = 0; ZDLookupResult overrideResult = ZD_LOOKUP_IGNORE; size_t j; for(j = i; j < numResults; j++) { if(results[i].metaId == results[j].metaId) { ZDLookupResult tmpResult = results[j].lookupResult; results[j].lookupResult = ZD_LOOKUP_IGNORE; /* This is the same result. Is it an exclusion zone? */ if(tmpResult == ZD_LOOKUP_IN_ZONE) { insideSum++; } else if(tmpResult == ZD_LOOKUP_IN_EXCLUDED_ZONE) { insideSum--; } else { /* If on the bodrder then the final result is on the border */ overrideResult = tmpResult; } } } if(overrideResult != ZD_LOOKUP_IGNORE) { results[i].lookupResult = overrideResult; } else { if(insideSum) { results[i].lookupResult = ZD_LOOKUP_IN_ZONE; } } } /* Remove zones to ignore */ size_t newNumResults = 0; for(i = 0; i < numResults; i++) { if(results[i].lookupResult != ZD_LOOKUP_IGNORE) { results[newNumResults] = results[i]; newNumResults++; } } numResults = newNumResults; /* Lookup metadata */ for(i = 0; i < numResults; i++) { uint32_t tmpIndex = library->metadataOffset + results[i].metaId; results[i].data = malloc(library->numFields * sizeof *results[i].data); if(results[i].data) { size_t j; for(j = 0; j < library->numFields; j++) { results[i].data[j] = ZDParseString(library, &tmpIndex); if (!results[i].data[j]) { /* free all allocated memory */ size_t m; for(m = 0; m < j; m++) { if(results[i].data[m]) { free(results[i].data[m]); } } size_t k; for(k = 0; k < i; k++) { size_t l; for(l = 0; l < (size_t)results[k].numFields; l++) { if(results[k].data[l]) { free(results[k].data[l]); } } if (results[k].data) { free(results[k].data); } } free(results); return NULL; } } } else { /* free all allocated memory */ size_t k; for(k = 0; k < i; k++) { size_t l; for(l = 0; l < (size_t)results[k].numFields; l++) { if(results[k].data[l]) { free(results[k].data[l]); } } if (results[k].data) { free(results[k].data); } } free(results); return NULL; } } /* Write end marker */ results[numResults].lookupResult = ZD_LOOKUP_END; results[numResults].numFields = 0; results[numResults].fieldNames = NULL; results[numResults].data = NULL; if(safezone) { *safezone = sqrtf((float)distanceSqrMin) * 90 / (float)(1 << (library->precision - 1)); } return results; } void ZDFreeResults(ZoneDetectResult *results) { unsigned int index = 0; if(!results) { return; } while(results[index].lookupResult != ZD_LOOKUP_END) { if(results[index].data) { size_t i; for(i = 0; i < (size_t)results[index].numFields; i++) { if(results[index].data[i]) { free(results[index].data[i]); } } free(results[index].data); } index++; } free(results); } const char *ZDGetNotice(const ZoneDetect *library) { return library->notice; } uint8_t ZDGetTableType(const ZoneDetect *library) { return library->tableType; } const char *ZDLookupResultToString(ZDLookupResult result) { switch(result) { case ZD_LOOKUP_IGNORE: return "Ignore"; case ZD_LOOKUP_END: return "End"; case ZD_LOOKUP_PARSE_ERROR: return "Parsing error"; case ZD_LOOKUP_NOT_IN_ZONE: return "Not in zone"; case ZD_LOOKUP_IN_ZONE: return "In zone"; case ZD_LOOKUP_IN_EXCLUDED_ZONE: return "In excluded zone"; case ZD_LOOKUP_ON_BORDER_VERTEX: return "Target point is border vertex"; case ZD_LOOKUP_ON_BORDER_SEGMENT: return "Target point is on border"; } return "Unknown"; } #define ZD_E_COULD_NOT(msg) "could not " msg const char *ZDGetErrorString(int errZD) { switch ((enum ZDInternalError)errZD) { default: assert(0); case ZD_OK : return ""; case ZD_E_DB_OPEN : return ZD_E_COULD_NOT("open database file"); case ZD_E_DB_SEEK : return ZD_E_COULD_NOT("retrieve database file size"); case ZD_E_DB_MMAP : return ZD_E_COULD_NOT("map database file to system memory"); #if defined(_MSC_VER) || defined(__MINGW32__) case ZD_E_DB_MMAP_MSVIEW : return ZD_E_COULD_NOT("open database file view"); case ZD_E_DB_MAP_EXCEPTION: return "I/O exception occurred while accessing database file view"; case ZD_E_DB_MUNMAP_MSVIEW: return ZD_E_COULD_NOT("close database file view"); #endif case ZD_E_DB_MUNMAP : return ZD_E_COULD_NOT("unmap database"); case ZD_E_DB_CLOSE : return ZD_E_COULD_NOT("close database file"); case ZD_E_PARSE_HEADER : return ZD_E_COULD_NOT("parse database header"); } } #undef ZD_E_COULD_NOT int ZDSetErrorHandler(void (*handler)(int, int)) { zdErrorHandler = handler; return 0; } char* ZDHelperSimpleLookupString(const ZoneDetect* library, float lat, float lon) { ZoneDetectResult *result = ZDLookup(library, lat, lon, NULL); if(!result) { return NULL; } char* output = NULL; if(result[0].lookupResult == ZD_LOOKUP_END) { goto done; } char* strings[2] = {NULL}; unsigned int i; for(i = 0; i < result[0].numFields; i++) { if(result[0].fieldNames[i] && result[0].data[i]) { if(library->tableType == 'T') { if(!strcmp(result[0].fieldNames[i], "TimezoneIdPrefix")) { strings[0] = result[0].data[i]; } if(!strcmp(result[0].fieldNames[i], "TimezoneId")) { strings[1] = result[0].data[i]; } } if(library->tableType == 'C') { if(!strcmp(result[0].fieldNames[i], "Name")) { strings[0] = result[0].data[i]; } } } } size_t length = 0; for(i=0; i 512) { goto done; } length += partLength; } } if(length == 0) { goto done; } length += 1; output = (char*)malloc(length); if(output) { output[0] = 0; for(i=0; i #include #ifndef INCL_ZONEDETECT_H_ #define INCL_ZONEDETECT_H_ #if !defined(ZD_EXPORT) #if defined(_MSC_VER) #define ZD_EXPORT __declspec(dllimport) #else #define ZD_EXPORT #endif #endif typedef enum { ZD_LOOKUP_IGNORE = -3, ZD_LOOKUP_END = -2, ZD_LOOKUP_PARSE_ERROR = -1, ZD_LOOKUP_NOT_IN_ZONE = 0, ZD_LOOKUP_IN_ZONE = 1, ZD_LOOKUP_IN_EXCLUDED_ZONE = 2, ZD_LOOKUP_ON_BORDER_VERTEX = 3, ZD_LOOKUP_ON_BORDER_SEGMENT = 4 } ZDLookupResult; typedef struct { ZDLookupResult lookupResult; uint32_t polygonId; uint32_t metaId; uint8_t numFields; char **fieldNames; char **data; } ZoneDetectResult; struct ZoneDetectOpaque; typedef struct ZoneDetectOpaque ZoneDetect; #ifdef __cplusplus extern "C" { #endif ZD_EXPORT ZoneDetect *ZDOpenDatabase(const char *path); ZD_EXPORT ZoneDetect *ZDOpenDatabaseFromMemory(void* buffer, size_t length); ZD_EXPORT void ZDCloseDatabase(ZoneDetect *library); ZD_EXPORT ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, float *safezone); ZD_EXPORT void ZDFreeResults(ZoneDetectResult *results); ZD_EXPORT const char *ZDGetNotice(const ZoneDetect *library); ZD_EXPORT uint8_t ZDGetTableType(const ZoneDetect *library); ZD_EXPORT const char *ZDLookupResultToString(ZDLookupResult result); ZD_EXPORT int ZDSetErrorHandler(void (*handler)(int, int)); ZD_EXPORT const char *ZDGetErrorString(int errZD); ZD_EXPORT float* ZDPolygonToList(const ZoneDetect *library, uint32_t polygonId, size_t* length); ZD_EXPORT char* ZDHelperSimpleLookupString(const ZoneDetect* library, float lat, float lon); ZD_EXPORT void ZDHelperSimpleLookupStringFree(char* str); #ifdef __cplusplus } #endif #endif // INCL_ZONEDETECT_H_ foldynl-QLog-3252ff9/cwkey/000077500000000000000000000000001517334601000155055ustar00rootroot00000000000000foldynl-QLog-3252ff9/cwkey/CWKeyer.cpp000066400000000000000000000223201517334601000175210ustar00rootroot00000000000000#include "CWKeyer.h" #include "cwkey/drivers/CWKey.h" #include "cwkey/drivers/CWDummyKey.h" #include "cwkey/drivers/CWWinKey.h" #include "cwkey/drivers/CWCatKey.h" #include "cwkey/drivers/CWDaemonKey.h" #include "cwkey/drivers/CWFldigiKey.h" #include "core/debug.h" #include "data/CWKeyProfile.h" MODULE_IDENTIFICATION("qlog.cwkey.cwkeyer"); #define TIME_PERIOD 1000 void CWKeyer::start() { FCT_IDENTIFICATION; timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &CWKeyer::update); timer->start(TIME_PERIOD); } void CWKeyer::stopTimer() { FCT_IDENTIFICATION; bool check = QMetaObject::invokeMethod(CWKeyer::instance(), &CWKeyer::stopTimerImplt, Qt::QueuedConnection); Q_ASSERT( check ); } void CWKeyer::update() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for cwkey mutex"; if ( !cwKeyLock.tryLock(200) ) { qCDebug(runtime) << "Waited too long"; return; } qCDebug(runtime) << "Updating key state"; if ( !cwKey ) { cwKeyLock.unlock(); return; } CWKeyProfile currCWProfile = CWKeyProfilesManager::instance()->getCurProfile1(); /***********************************************************/ /* Is Opened Profile still the globbaly used CW Profile ? */ /* if NO then reconnect it */ /***********************************************************/ if ( currCWProfile != connectedCWKeyProfile) { /* CW Key Profile Changed * Need to reconnect CW Key */ qCDebug(runtime) << "Reconnecting to a new CW Key - " << currCWProfile.profileName << "; Old - " << connectedCWKeyProfile.profileName; __openCWKey(); } timer->start(TIME_PERIOD); cwKeyLock.unlock(); } void CWKeyer::open() { FCT_IDENTIFICATION; QMetaObject::invokeMethod(this, &CWKeyer::openImpl, Qt::QueuedConnection); } void CWKeyer::openImpl() { FCT_IDENTIFICATION; cwKeyLock.lock(); __openCWKey(); cwKeyLock.unlock(); } void CWKeyer::__openCWKey() { FCT_IDENTIFICATION; // if cw keys is active then close it __closeCWKey(); CWKeyProfile newProfile = CWKeyProfilesManager::instance()->getCurProfile1(); if ( newProfile == CWKeyProfile() ) { emit cwKeyerError(tr("No CW Keyer Profile selected"), QString()); return; } qCDebug(runtime) << "Opening profile name: " << newProfile.profileName; switch ( newProfile.model ) { case CWKey::DUMMY_KEYER: cwKey = new CWDummyKey(this); break; case CWKey::WINKEY_KEYER: cwKey = new CWWinKey(newProfile.portPath, newProfile.baudrate, newProfile.keyMode, newProfile.defaultSpeed, newProfile.paddleSwap, newProfile.paddleOnlySidetone, newProfile.sidetoneFrequency, this); break; case CWKey::MORSEOVERCAT: cwKey = new CWCatKey(newProfile.keyMode, newProfile.defaultSpeed, this); break; case CWKey::CWDAEMON_KEYER: cwKey = new CWDaemonKey(newProfile.hostname, newProfile.netport, newProfile.keyMode, newProfile.defaultSpeed, newProfile.sidetoneFrequency, this); break; case CWKey::FLDIGI_KEYER: cwKey = new CWFldigiKey(newProfile.hostname, newProfile.netport, newProfile.keyMode, newProfile.defaultSpeed, this); break; default: cwKey = nullptr; qWarning() << "Unsupported Key Model " << newProfile.model; } if ( !cwKey ) { // initialization failed emit cwKeyerError(tr("Initialization Error"), tr("Internal Error")); return; } if ( !cwKey->open() ) { emit cwKeyerError(tr("Connection Error"), tr("Cannot open the Keyer connection")); qWarning() << cwKey->lastError(); __closeCWKey(); return; } connect(cwKey, &CWKey::keyError, this, &CWKeyer::keyErrorHandler); connect(cwKey, &CWKey::keyChangedWPMSpeed, this, &CWKeyer::cwKeyWPMChangedHandler); connect(cwKey, &CWKey::keyEchoText, this, &CWKeyer::cwKeyEchoTextHandler); connect(cwKey, &CWKey::keyHWButton1Pressed, this, &CWKeyer::cwKeyHWButton1PressedHandler); connect(cwKey, &CWKey::keyHWButton2Pressed, this, &CWKeyer::cwKeyHWButton2PressedHandler); connect(cwKey, &CWKey::keyHWButton3Pressed, this, &CWKeyer::cwKeyHWButton3PressedHandler); connect(cwKey, &CWKey::keyHWButton4Pressed, this, &CWKeyer::cwKeyHWButton4PressedHandler); connectedCWKeyProfile = newProfile; emit cwKeyConnected(connectedCWKeyProfile.profileName); } void CWKeyer::close() { FCT_IDENTIFICATION; QMetaObject::invokeMethod(this, &CWKeyer::closeImpl, Qt::QueuedConnection); } bool CWKeyer::canStopSending() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for cwkey mutex"; QMutexLocker locker(&cwKeyLock); qCDebug(runtime) << "Using Key"; if ( !cwKey ) { return false; } bool ret = cwKey->canStopSending(); return ret; } bool CWKeyer::canEchoChar() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for cwkey mutex"; QMutexLocker locker(&cwKeyLock); qCDebug(runtime) << "Using Key"; if ( !cwKey ) { return false; } bool ret = cwKey->canEchoChar(); return ret; } bool CWKeyer::rigMustConnected() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for cwkey mutex"; QMutexLocker locker(&cwKeyLock); qCDebug(runtime) << "Using Key"; if ( !cwKey ) { return false; } bool ret = cwKey->mustRigConnected(); return ret; } bool CWKeyer::canSetSpeed() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for cwkey mutex"; QMutexLocker locker(&cwKeyLock); qCDebug(runtime) << "Using Key"; if ( !cwKey ) { return false; } bool ret = cwKey->canSetSpeed(); return ret; } void CWKeyer::closeImpl() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for cwkey mutex"; cwKeyLock.lock(); qCDebug(runtime) << "Using Key"; __closeCWKey(); cwKeyLock.unlock(); } void CWKeyer::__closeCWKey() { FCT_IDENTIFICATION; connectedCWKeyProfile = CWKeyProfile(); if ( cwKey ) { cwKey->close(); cwKey->deleteLater(); cwKey = nullptr; } emit cwKeyDisconnected(); } void CWKeyer::setSpeed(const qint16 wpm) { FCT_IDENTIFICATION; QMetaObject::invokeMethod(this, "setSpeedImpl", Qt::QueuedConnection, Q_ARG(qint16, wpm)); } void CWKeyer::setSpeedImpl(const qint16 wpm) { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for cwkey mutex"; QMutexLocker locker(&cwKeyLock); qCDebug(runtime) << "Using Key"; if ( !cwKey ) return; cwKey->setWPM(wpm); } void CWKeyer::sendText(const QString &text) { FCT_IDENTIFICATION; QMetaObject::invokeMethod(this, "sendTextImpl", Qt::QueuedConnection, Q_ARG(QString, text)); } void CWKeyer::sendTextImpl(const QString &text) { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for cwkey mutex"; QMutexLocker locker(&cwKeyLock); qCDebug(runtime) << "Using Key"; if ( !cwKey ) return; cwKey->sendText(text); } void CWKeyer::immediatelyStop() { FCT_IDENTIFICATION; QMetaObject::invokeMethod(this, "immediatelyStopImpl", Qt::QueuedConnection); } void CWKeyer::immediatelyStopImpl() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for cwkey mutex"; QMutexLocker locker(&cwKeyLock); qCDebug(runtime) << "Using Key"; if ( !cwKey ) return; cwKey->immediatelyStop(); } void CWKeyer::stopTimerImplt() { FCT_IDENTIFICATION; if ( timer ) { timer->stop(); timer->deleteLater(); timer = nullptr; } } void CWKeyer::keyErrorHandler(const QString &main, const QString &detail) { FCT_IDENTIFICATION; emit cwKeyerError(main, detail); closeImpl(); } void CWKeyer::cwKeyWPMChangedHandler(qint32 wpm) { FCT_IDENTIFICATION; emit cwKeyWPMChanged(wpm); } void CWKeyer::cwKeyEchoTextHandler(const QString &text) { FCT_IDENTIFICATION; emit cwKeyEchoText(text); } void CWKeyer::cwKeyHWButton1PressedHandler() { emit cwKeyHWButton(1); } void CWKeyer::cwKeyHWButton2PressedHandler() { emit cwKeyHWButton(2); } void CWKeyer::cwKeyHWButton3PressedHandler() { emit cwKeyHWButton(3); } void CWKeyer::cwKeyHWButton4PressedHandler() { emit cwKeyHWButton(4); } CWKeyer::CWKeyer(QObject *parent ) : QObject(parent), cwKey(nullptr), timer(nullptr) { FCT_IDENTIFICATION; } CWKeyer::~CWKeyer() { FCT_IDENTIFICATION; if ( cwKey ) { cwKey->deleteLater(); } } foldynl-QLog-3252ff9/cwkey/CWKeyer.h000066400000000000000000000031321517334601000171660ustar00rootroot00000000000000#ifndef QLOG_CWKEY_CWKEYER_H #define QLOG_CWKEY_CWKEYER_H #include #include "cwkey/drivers/CWKey.h" #include "data/CWKeyProfile.h" class CWKeyer : public QObject { Q_OBJECT public: static CWKeyer* instance() { static CWKeyer instance; return &instance; }; void stopTimer(); signals: void cwKeyerError(QString, QString); void cwKeyConnected(QString); void cwKeyDisconnected(); void cwKeyWPMChanged(qint32); void cwKeyEchoText(QString); void cwKeyHWButton(int); void cwKeyHWHaltPressed(); public slots: void start(); void update(); void open(); void close(); bool canStopSending(); bool canEchoChar(); bool rigMustConnected(); bool canSetSpeed(); void setSpeed(const qint16 wpm); void sendText(const QString&); void immediatelyStop(); private slots: void openImpl(); void closeImpl(); void setSpeedImpl(const qint16 wpm); void sendTextImpl(const QString&); void immediatelyStopImpl(); void stopTimerImplt(); void keyErrorHandler(const QString&, const QString&); void cwKeyWPMChangedHandler(qint32); void cwKeyEchoTextHandler(const QString&); void cwKeyHWButton1PressedHandler(); void cwKeyHWButton2PressedHandler(); void cwKeyHWButton3PressedHandler(); void cwKeyHWButton4PressedHandler(); private: explicit CWKeyer(QObject *parent = nullptr); ~CWKeyer(); void __closeCWKey(); void __openCWKey(); CWKey *cwKey; CWKeyProfile connectedCWKeyProfile; QMutex cwKeyLock; QTimer* timer; }; #endif // QLOG_CWKEY_CWKEYER_H foldynl-QLog-3252ff9/cwkey/drivers/000077500000000000000000000000001517334601000171635ustar00rootroot00000000000000foldynl-QLog-3252ff9/cwkey/drivers/CWCatKey.cpp000066400000000000000000000116711517334601000213070ustar00rootroot00000000000000#include "CWCatKey.h" #include "core/debug.h" #include "rig/Rig.h" MODULE_IDENTIFICATION("qlog.cwkey.driver.cwcatkey"); CWCatKey::CWCatKey(const CWKey::CWKeyModeID mode, const qint32 defaultSpeed, QObject *parent) : CWKey(mode, defaultSpeed, parent), isKeyConnected(false) { FCT_IDENTIFICATION; } CWCatKey::~CWCatKey() { FCT_IDENTIFICATION; } bool CWCatKey::open() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for Command Mutex"; QMutexLocker locker(&commandMutex); __close(); /********************************/ /* Test if any rig is connected */ /********************************/ if ( !Rig::instance()->isRigConnected() ) { qWarning() << "Rig is not connected"; lastErrorText = tr("No Rig is connected"); __close(); return false; } /**************************************/ /* Test if the rig has Morse over CAT */ /**************************************/ if ( !Rig::instance()->isMorseOverCatSupported() ) { qWarning() << "Rig does not support Morse over CAT"; lastErrorText = tr("Rig does not support Morse over CAT"); __close(); return false; } /********************************************/ /* Rig must be in CW mode */ /* swith the rig to CW mode ? */ /* Maybe Yes - we will see users reaction */ /********************************************/ //it has the side-effect that every time you connect, // it causes to switch to CW when the key is assigned. // So let's disable it and see what's worse //Rig::instance()->setMode("CW", QString()); /*******************/ /* set default WPM */ /*******************/ Rig::instance()->setKeySpeed(defaultWPMSpeed); /************************/ /* Test if hamlib > 4.0 */ /* Stop sending feature */ /************************/ #if (HAMLIBVERSION_MAJOR >= 4) stopSendingCap = 1; #endif rigMustConnectedCap = true; isKeyConnected = true; canSetKeySpeed = true; lastErrorText = QString(); connect(Rig::instance(), &Rig::keySpeedChanged, this, &CWCatKey::rigKeySpeedChanged); return true; } bool CWCatKey::close() { FCT_IDENTIFICATION; QMutexLocker locker(&commandMutex); isKeyConnected = false; return true; } QString CWCatKey::lastError() { FCT_IDENTIFICATION; return lastErrorText; } bool CWCatKey::sendText(const QString &text) { FCT_IDENTIFICATION; if ( !isKeyConnected ) { qCDebug(runtime) << "Cannot send "; emit keyError(tr("Cannot send Text to Rig"), tr("Keyer is not connected")); return false; } if ( !Rig::instance()->isRigConnected() ) { qCDebug(runtime) << "Cannot send"; emit keyError(tr("Cannot send Text to Rig"), tr("Rig is not connected")); return false; } if ( !Rig::instance()->isMorseOverCatSupported() ) { qCDebug(runtime) << "Cannot send"; emit keyError(tr("Cannot send Text to Rig"), tr("Rig does not support Morse over CAT")); return false; } QMutexLocker locker(&commandMutex); Rig::instance()->sendMorse(text); return true; } bool CWCatKey::setWPM(const qint16 wpm) { FCT_IDENTIFICATION; if ( !isKeyConnected ) { qCDebug(runtime) << "Cannot set WPM "; emit keyError(tr("Cannot set Keyer Speed"), tr("Keyer is not connected")); return false; } if ( !Rig::instance()->isRigConnected() ) { qCDebug(runtime) << "Cannot set WPM"; emit keyError(tr("Cannot set Keyer Speed"), tr("Rig is not connected")); return false; } QMutexLocker locker(&commandMutex); Rig::instance()->setKeySpeed(wpm); //cat can echo a new Speed therefore // emit keyChangedWPMSpeed is not emitted return true; } bool CWCatKey::immediatelyStop() { FCT_IDENTIFICATION; if ( !isKeyConnected ) { qCDebug(runtime) << "Cannot stop"; emit keyError(tr("Cannot stop Text Sending"), tr("Keyer is not connected")); return false; } if ( !Rig::instance()->isRigConnected() ) { qCDebug(runtime) << "Cannot stop"; emit keyError(tr("Cannot stop Text Sending"), tr("Rig is not connected")); return false; } if ( !Rig::instance()->isMorseOverCatSupported() ) { qCDebug(runtime) << "Cannot stop"; emit keyError(tr("Cannot stop Text Sending"), tr("Rig does not support Morse over CAT")); return false; } QMutexLocker locker(&commandMutex); Rig::instance()->stopMorse(); return true; } void CWCatKey::__close() { FCT_IDENTIFICATION; disconnect(Rig::instance(), &Rig::keySpeedChanged, this, &CWCatKey::rigKeySpeedChanged); isKeyConnected = false; } void CWCatKey::rigKeySpeedChanged(VFOID, unsigned int wpm) { FCT_IDENTIFICATION; emit keyChangedWPMSpeed(wpm); } foldynl-QLog-3252ff9/cwkey/drivers/CWCatKey.h000066400000000000000000000016221517334601000207470ustar00rootroot00000000000000#ifndef QLOG_CWKEY_DRIVERS_CWCATKEY_H #define QLOG_CWKEY_DRIVERS_CWCATKEY_H #include #include #include "CWKey.h" #include "rig/Rig.h" class CWCatKey : public CWKey { Q_OBJECT public: explicit CWCatKey(const CWKey::CWKeyModeID mode, const qint32 defaultSpeed, QObject *parent = nullptr); virtual ~CWCatKey(); virtual bool open() override; virtual bool close() override; virtual QString lastError() override; virtual bool sendText(const QString &text) override; virtual bool setWPM(const qint16 wpm) override; virtual bool immediatelyStop() override; private: QMutex commandMutex; bool isKeyConnected; QString lastErrorText; //user only in open part of communication void __close(); private slots: void rigKeySpeedChanged(VFOID, unsigned int); }; #endif // QLOG_CWKEY_DRIVERS_CWCATKEY_H foldynl-QLog-3252ff9/cwkey/drivers/CWDaemonKey.cpp000066400000000000000000000062521517334601000220020ustar00rootroot00000000000000#include "CWDaemonKey.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.cwkey.driver.cwdaemonkey"); CWDaemonKey::CWDaemonKey(const QString &hostname, const quint16 port, const CWKey::CWKeyModeID mode, const qint32 defaultSpeed, qint32 sidetoneFrequency, QObject *parent) : CWKey(mode, defaultSpeed, parent), CWKeyUDPInterface(hostname, port), isOpen(false), ESCChar(27), sidetoneFrequency(sidetoneFrequency) { FCT_IDENTIFICATION; stopSendingCap = true; canSetKeySpeed = true; printKeyCaps(); } bool CWDaemonKey::open() { FCT_IDENTIFICATION; isOpen = isSocketReady(); if ( isOpen && sidetoneFrequency > 0 ) { QString toneCmd(ESCChar + QString("3") + QString::number(sidetoneFrequency)); sendData(toneCmd.toLatin1()); } return isOpen; } bool CWDaemonKey::close() { FCT_IDENTIFICATION; isOpen = false; return true; } QString CWDaemonKey::lastError() { FCT_IDENTIFICATION; qCDebug(runtime) << socket.error(); qCDebug(runtime) << lastLogicalError; return (lastLogicalError.isEmpty()) ? socket.errorString() : lastLogicalError; } bool CWDaemonKey::sendText(const QString &text) { FCT_IDENTIFICATION; qCDebug(function_parameters) << text; if ( text.isEmpty() ) return true; if ( !isOpen ) { qCWarning(runtime) << "Key is not connected"; lastLogicalError = tr("Keyer is not connected"); emit keyError(tr("Cannot send Text"), lastLogicalError); return false; } int pos = 0; QRegularExpressionMatchIterator it = speedMarkerRE().globalMatch(text); while ( it.hasNext() ) { QRegularExpressionMatch match = it.next(); QString segment = text.mid(pos, match.capturedStart() - pos); segment.remove('\n'); if ( !segment.isEmpty() ) sendData(segment.toLatin1()); setWPM(applySpeedMarker(match.captured(1))); pos = match.capturedEnd(); } QString lastSegment = text.mid(pos); lastSegment.remove('\n'); if ( !lastSegment.isEmpty() ) sendData(lastSegment.toLatin1()); return true; } bool CWDaemonKey::setWPM(const qint16 wpm) { FCT_IDENTIFICATION; qCDebug(function_parameters) << wpm; if ( !isOpen ) { qCWarning(runtime) << "Key is not connected"; lastLogicalError = tr("Keyer is not connected"); emit keyError(tr("Cannot set Keyer Speed"), lastLogicalError); return false; } currentWPM = wpm; QString sentString(ESCChar + QString("2") + QString::number(wpm)); emit keyChangedWPMSpeed(wpm); return (sendData(sentString.toLatin1()) > 0) ? true : false; } bool CWDaemonKey::immediatelyStop() { FCT_IDENTIFICATION; if ( !isOpen ) { qCWarning(runtime) << "Key is not connected"; lastLogicalError = tr("Keyer is not connected"); emit keyError(tr("Cannot stop Text Sending"), lastLogicalError); return false; } QString sentString(ESCChar + QString("4")); return (sendData(sentString.toLatin1()) > 0) ? true : false; } foldynl-QLog-3252ff9/cwkey/drivers/CWDaemonKey.h000066400000000000000000000017401517334601000214440ustar00rootroot00000000000000#ifndef QLOG_CWKEY_DRIVERS_CWDAEMONKEY_H #define QLOG_CWKEY_DRIVERS_CWDAEMONKEY_H #include #include "CWKey.h" class CWDaemonKey : public CWKey, protected CWKeyUDPInterface { Q_OBJECT public: explicit CWDaemonKey(const QString &hostname, const quint16 port, const CWKey::CWKeyModeID mode, const qint32 defaultSpeed, qint32 sidetoneFrequency, QObject *parent = nullptr); virtual ~CWDaemonKey(){}; virtual bool open() override; virtual bool close() override; virtual QString lastError() override; virtual bool sendText(const QString &text) override; virtual bool setWPM(const qint16 wpm) override; virtual bool immediatelyStop() override; protected: QString lastLogicalError; bool isOpen; const QChar ESCChar; qint32 sidetoneFrequency; }; #endif // QLOG_CWKEY_DRIVER_CWDAEMONKEY_H foldynl-QLog-3252ff9/cwkey/drivers/CWDummyKey.cpp000066400000000000000000000024551517334601000216730ustar00rootroot00000000000000#include "CWDummyKey.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.cwkey.driver.cwdummykey"); CWDummyKey::CWDummyKey(QObject *parent) : CWKey(CWKey::IAMBIC_B, 25, parent), isUsed(false) { FCT_IDENTIFICATION; canSetKeySpeed = true; } bool CWDummyKey::open() { FCT_IDENTIFICATION; qInfo() << "Key is Connected"; isUsed = true; setWPM(defaultWPMSpeed); return true; } bool CWDummyKey::close() { FCT_IDENTIFICATION; qInfo() << "Key is Disconnected"; isUsed = false; return true; } bool CWDummyKey::sendText(const QString &text) { FCT_IDENTIFICATION; if ( isUsed ) { qInfo() << "Sending " << stripSpeedMarkers(text); } return true; } bool CWDummyKey::setWPM(const qint16 wpm) { FCT_IDENTIFICATION; if ( !isUsed ) return true; qInfo() << "Setting Speed " << wpm; emit keyChangedWPMSpeed(wpm); // dummy does not echo a new Speed //therefore keyChangedWPMSpeed informs the rest for QLog that //Key speed has been changed return true; } QString CWDummyKey::lastError() { FCT_IDENTIFICATION; return QString(); } bool CWDummyKey::immediatelyStop() { FCT_IDENTIFICATION; if ( isUsed ) { qInfo() << "immediately Stop"; } return true; } foldynl-QLog-3252ff9/cwkey/drivers/CWDummyKey.h000066400000000000000000000010431517334601000213300ustar00rootroot00000000000000#ifndef QLOG_CWKEY_DRIVERS_CWDUMMYKEY_H #define QLOG_CWKEY_DRIVERS_CWDUMMYKEY_H #include "CWKey.h" class CWDummyKey : public CWKey { Q_OBJECT public: explicit CWDummyKey(QObject *parent = nullptr); virtual bool open() override; virtual bool close() override; virtual bool sendText(const QString &text) override; virtual bool setWPM(const qint16 wpm) override; virtual QString lastError() override; virtual bool immediatelyStop() override; private: bool isUsed; }; #endif // QLOG_CWKEY_DRIVER_CWDUMMYKEY_H foldynl-QLog-3252ff9/cwkey/drivers/CWFldigiKey.cpp000066400000000000000000000200771517334601000217760ustar00rootroot00000000000000#include #include "CWFldigiKey.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.cwkey.driver.cwfldigikey"); //response timeout in ms #define RESPONSE_TIMEOUT 10000 CWFldigiKey::CWFldigiKey(const QString &hostname, const quint16 port, const CWKey::CWKeyModeID mode, const qint32 defaultSpeed, QObject *parent) : CWKey(mode, defaultSpeed, parent), isOpen(false), nam(new QNetworkAccessManager(this)), hostname(hostname), port(port), RXString("^r"), transmittingText(false) { FCT_IDENTIFICATION; } bool CWFldigiKey::open() { FCT_IDENTIFICATION; if ( isOpen ) { return true; } QByteArray resp; // Check if QLog is connecting to FLDigi // And FLDigi contains all necessary commands if ( !sendXMLRPCCall("fldigi.list", resp) ) { qCDebug(runtime) << "Connection error"; return false; } if ( resp.contains("fldigi.list") && resp.contains("text.add_tx") && resp.contains("text.clear_tx") && resp.contains("main.tx") ) { qCDebug(runtime) << "Connection check OK"; } else { qCDebug(runtime) << "Connection checks failed"; lastLogicalError = tr("Connected device is not FLDigi"); return false; } if ( resp.contains("main.abort") ) { qCDebug(runtime) << "Enabling stopSendingCap"; stopSendingCap = true; } if ( resp.contains("tx.get_data") ) { qCDebug(runtime) << "Enabling echoCharsCap"; echoCharsCap = true; } printKeyCaps(); isOpen = true; getEcho(); return true; } bool CWFldigiKey::close() { FCT_IDENTIFICATION; isOpen = false; lastLogicalError = QString(); return true; } QString CWFldigiKey::lastError() { FCT_IDENTIFICATION; return lastLogicalError; } bool CWFldigiKey::sendText(const QString &text) { FCT_IDENTIFICATION; qCDebug(function_parameters) << text; if ( text.isEmpty() ) return true; if ( !isOpen ) { qCWarning(runtime) << "Key is not connected"; lastLogicalError = tr("Keyer is not connected"); emit keyError(tr("Cannot send Text to FLDigi"), lastLogicalError); return false; } QByteArray resp; if ( !transmittingText ) { if ( !sendXMLRPCCall("text.clear_tx", resp) ) { emit keyError(tr("Cannot send the Clear command to FLDigi"), lastError()); return false; } if ( !sendXMLRPCCall("main.tx", resp) ) { emit keyError(tr("Cannot send the TX command to FLDigi"), lastError()); return false; } transmittingText = true; } QList> params; QString chpString = stripSpeedMarkers(text); if ( chpString.contains("\n") ) { chpString.replace("\n", RXString); transmittingText = false; } params << QPair("string", chpString ); if ( !sendXMLRPCCall("text.add_tx", resp, ¶ms) ) { transmittingText = false; emit keyError(tr("Cannot send the Text command to FLDigi"), lastError()); return false; } return true; } bool CWFldigiKey::setWPM(const qint16) { FCT_IDENTIFICATION; // currently I don't know which FLDigi function I should call. return true; } bool CWFldigiKey::immediatelyStop() { FCT_IDENTIFICATION; if ( ! stopSendingCap ) { qCDebug(runtime) << "STOP is not supported by FLDigi"; return true; } if ( !isOpen ) { qCWarning(runtime) << "Key is not connected"; lastLogicalError = tr("Keyer is not connected"); emit keyError(tr("Cannot send the Stop command to FLDigi"), lastLogicalError); return false; } QByteArray resp; if ( !sendXMLRPCCall("main.abort", resp) ) { emit keyError(tr("Cannot send the Abort command to FLDigi"), lastError()); return false; } if ( !sendXMLRPCCall("text.clear_tx", resp) ) { emit keyError(tr("Cannot send the Clear command to FLDigi"), lastError()); return false; } return true; } void CWFldigiKey::getEcho() { FCT_IDENTIFICATION; if ( ! echoCharsCap ) { qCDebug(runtime) << "Echo Char is not supported by FLDigi"; return; } if ( !isOpen ) { qCDebug(runtime) << "Key is not connected"; return; } QByteArray resp; if ( !sendXMLRPCCall("tx.get_data", resp) ) { qWarning() << "Cannot receive the TX Data from FLDigi"; emit keyError(tr("Cannot receive data from FLDigi"), lastError()); return; } qsizetype start = resp.indexOf(""); qsizetype stop = resp.indexOf(""); if ( start == -1 || stop == -1 || stop < start ) { qCDebug(runtime) << "based64 block not found"; // TODO: EMIT ERROR and disconnect? currently without an error, I will see return; } QString echoString(QByteArray::fromBase64(resp.mid(start + 8, stop - start - 8))); qCDebug(runtime) << "\tEcho String" << echoString; emit keyEchoText(echoString); // check periodically QTimer::singleShot(1 * 1000, this, &CWFldigiKey::getEcho); } bool CWFldigiKey::sendXMLRPCCall(const QString & methodName, QByteArray &response, const QList> *params) { FCT_IDENTIFICATION; QEventLoop loop; QString ret; QXmlStreamWriter writer(&ret); QNetworkRequest request(QUrl(QString("http://%1:%2/RPC").arg(hostname, QString::number(port)))); QNetworkReply* reply = nullptr; QTimer timer; timer.setSingleShot(true); response = QByteArray(); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/xml"); writer.writeStartDocument(); writer.writeStartElement("methodCall"); writer.writeTextElement("methodName", methodName); if ( params && !params->isEmpty() ) { writer.writeStartElement("params"); for( const QPair& param : static_cast>&>(*params) ) { writer.writeStartElement("param"); writer.writeStartElement("value"); writer.writeTextElement(param.first, param.second); writer.writeEndElement(); writer.writeEndElement(); } writer.writeEndElement(); } writer.writeEndElement(); writer.writeEndDocument(); qCDebug(runtime) << ret.toLocal8Bit(); reply= nam->post(request, ret.toLocal8Bit()); // blocking call is used connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); connect(reply , &QNetworkReply::finished, &loop, &QEventLoop::quit); timer.start(RESPONSE_TIMEOUT); // timer for logical timeout - in ms loop.exec(); // Timeout occurred if (!timer.isActive()) { disconnect(reply , &QNetworkReply::finished, &loop, &QEventLoop::quit); qWarning() << "XMLRPC Call Timeout" << RESPONSE_TIMEOUT << "ms"; lastLogicalError = tr("FLDigi connection timeout"); reply->abort(); reply->deleteLater(); return false; } timer.stop(); int replyStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if ( reply->error() != QNetworkReply::NoError || replyStatusCode < 200 || replyStatusCode >= 300 ) { qWarning() << "XMLRPC Call Reply Error" << reply->errorString(); qCDebug(runtime) << "HTTP Status Code" << replyStatusCode; lastLogicalError = tr("FLDigi connection error"); reply->deleteLater(); return false; } response = reply->readAll(); qCDebug(runtime) << response; if ( response.contains("") ) { qWarning() << "XMLRPC Call Logical Error" << response; lastLogicalError = tr("FLDigi command error"); reply->deleteLater(); return false; } reply->deleteLater(); return true; } foldynl-QLog-3252ff9/cwkey/drivers/CWFldigiKey.h000066400000000000000000000022101517334601000214300ustar00rootroot00000000000000#ifndef QLOG_CWKEY_DRIVERS_CWFLDIGIKEY_H #define QLOG_CWKEY_DRIVERS_CWFLDIGIKEY_H #include #include #include "CWKey.h" class CWFldigiKey : public CWKey { public: CWFldigiKey(const QString &hostname, const quint16 port, const CWKey::CWKeyModeID mode, const qint32 defaultSpeed, QObject *parent = nullptr); virtual ~CWFldigiKey(){ nam->deleteLater();}; virtual bool open() override; virtual bool close() override; virtual QString lastError() override; virtual bool sendText(const QString &text) override; virtual bool setWPM(const qint16 wpm) override; virtual bool immediatelyStop() override; protected: QString lastLogicalError; bool isOpen; QNetworkAccessManager *nam; QString hostname; quint16 port; const QString RXString; bool transmittingText; private: bool sendXMLRPCCall(const QString&, QByteArray &, const QList>* = nullptr); private slots: void getEcho(); }; #endif // QLOG_CWKEY_DRIVERS_CWFLDIGIKEY_H foldynl-QLog-3252ff9/cwkey/drivers/CWKey.cpp000066400000000000000000000150441517334601000206550ustar00rootroot00000000000000#include #include #include "CWKey.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.cwkey.driver.cwkey"); CWKey::CWKey(CWKeyModeID mode, qint32 defaultWPM, QObject *parent) : QObject(parent), keyMode(mode), defaultWPMSpeed(defaultWPM), currentWPM(static_cast(defaultWPM)), stopSendingCap(false), echoCharsCap(false), rigMustConnectedCap(false), canSetKeySpeed(false) { FCT_IDENTIFICATION; qCDebug(function_parameters) << mode << defaultWPM; } void CWKey::printKeyCaps() { FCT_IDENTIFICATION; qCDebug(runtime) << "stopSendingCap" << stopSendingCap; qCDebug(runtime) << "echoCharsCap" << echoCharsCap; qCDebug(runtime) << "rigMustConnectedCap" << rigMustConnectedCap; qCDebug(runtime) << "canSetKeySpeed" << canSetKeySpeed; } CWKey::CWKeyTypeID CWKey::intToTypeID(int i) { FCT_IDENTIFICATION; if ( i < DUMMY_KEYER || i > LAST_MODEL ) { qCWarning(runtime) << "Unknown Mode" << i; return LAST_MODEL; } return static_cast(i); } CWKey::CWKeyModeID CWKey::intToModeID(int i) { FCT_IDENTIFICATION; if ( i < SINGLE_PADDLE || i > LAST_MODE ) { qCWarning(runtime) << "Unknown Mode" << i; return LAST_MODE; } return static_cast(i); } bool CWKey::isNetworkKey(const CWKeyTypeID &type) { FCT_IDENTIFICATION; bool ret = (type == CWDAEMON_KEYER || type == FLDIGI_KEYER ); qCDebug(runtime) << ret; return ret; } const QRegularExpression &CWKey::speedMarkerRE() { static QRegularExpression re("<(\\++|-+)>"); return re; } qint16 CWKey::applySpeedMarker(const QString &markerCapture) { qint16 delta = static_cast( markerCapture.length() * ( markerCapture[0] == QLatin1Char('+') ? 5 : -5 )); currentWPM = qBound(minWPM(), static_cast(currentWPM + delta), maxWPM()); return currentWPM; } QString CWKey::stripSpeedMarkers(const QString &text) { QString result(text); result.remove(speedMarkerRE()); return result; } QDataStream& operator>>(QDataStream &in, CWKey::CWKeyModeID &v) { int i; in >> i; v = static_cast(i); return in; } QDataStream& operator<<(QDataStream &out, const CWKey::CWKeyModeID &v) { out << static_cast(v); return out; } QDataStream& operator>>(QDataStream &in, CWKey::CWKeyTypeID &v) { int i; in >> i; v = static_cast(i); return in; } QDataStream& operator<<(QDataStream &out, const CWKey::CWKeyTypeID &v) { out << static_cast(v); return out; } CWKeySerialInterface::CWKeySerialInterface(const QString &portName, const qint32 baudrate, const qint32 timeout) : timeout(timeout) { FCT_IDENTIFICATION; qCDebug(function_parameters) << portName << baudrate << timeout; serial.setPortName(portName); if ( ! serial.setBaudRate(baudrate, QSerialPort::AllDirections) ) { qWarning() << "Cannot set Baudrate for Serial port"; } if ( ! serial.setDataBits(QSerialPort::Data8) ) { qWarning() << "Cannot set Data Bits for Serial port"; } if ( ! serial.setParity(QSerialPort::NoParity) ) { qWarning() << "Cannot set Parity for Serial port"; } if ( ! serial.setFlowControl(QSerialPort::NoFlowControl) ) { qWarning() << "Cannot set Flow Control for Serial port"; } if ( ! serial.setStopBits(QSerialPort::TwoStop) ) { qWarning() << "Cannot set Stop Bits for Serial port"; } } qint64 CWKeySerialInterface::sendDataAndWait(const QByteArray &data) { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for Port Mutex"; QMutexLocker locker(&portMutex); if ( ! serial.isOpen() ) { qCDebug(runtime) << "Serial port is not opened"; return - 1; } qCDebug(runtime) << "\t<<<<<< SND Sync: " << data; qint64 ret = serial.write(data); if ( ret == -1 ) { qWarning() << "Serial Port Error: " << serial.errorString() << serial.error(); } else { if ( !serial.waitForBytesWritten(timeout) ) { qCDebug(runtime) << "Serial Port Timeout"; return -1; } } return ret; } qint64 CWKeySerialInterface::receiveDataAndWait(QByteArray &data) { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for Port Mutex"; QMutexLocker locker(&portMutex); if ( ! serial.isOpen() ) { qCDebug(runtime) << "Serial port is not opened"; return - 1; } if ( serial.waitForReadyRead(timeout)) { data = serial.readAll(); while ( serial.waitForReadyRead(10) ) { data += serial.readAll(); } } else { qCDebug(runtime) << "Serial Port Timeout"; return -1; } qCDebug(runtime) << "\t>>>>>> RCV Sync: " << data; return data.size(); } qint64 CWKeySerialInterface::writeAsyncData(const QByteArray &data) { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for Port Mutex"; QMutexLocker locker(&portMutex); if ( ! serial.isOpen() ) { qCDebug(runtime) << "Serial port is not opened"; return - 1; } qCDebug(runtime) << "\t<<<<<< SND Async:" << data; qint64 ret = serial.write(data); if ( ret == -1 ) { qWarning() << "Serial Port Error: " << serial.errorString() << serial.error(); } return ret; } CWKeyUDPInterface::CWKeyUDPInterface(const QString &hostname, const quint16 port) : CWKeyIPInterface(hostname, port) { FCT_IDENTIFICATION; } qint64 CWKeyUDPInterface::sendData(const QByteArray &data) { FCT_IDENTIFICATION; qCDebug(runtime) << "\t<<<<<< SND: " << data << "(" << serverName << "port:" << port << ")"; return socket.writeDatagram(data, serverName, port); } bool CWKeyUDPInterface::isSocketReady() { FCT_IDENTIFICATION; qCDebug(runtime) << hasIPAddress; return hasIPAddress; } CWKeyIPInterface::CWKeyIPInterface(const QString &hostname, const quint16 port) : serverName(QHostAddress()), port(port), hasIPAddress(false) { FCT_IDENTIFICATION; qCDebug(function_parameters) << hostname << port; QHostInfo info = QHostInfo::fromName(hostname); if (info.error() == QHostInfo::NoError) { serverName = QHostAddress(info.addresses().at(0)); qCDebug(runtime) << "Using IP address" << serverName; hasIPAddress = true; } } foldynl-QLog-3252ff9/cwkey/drivers/CWKey.h000066400000000000000000000067341517334601000203300ustar00rootroot00000000000000#ifndef QLOG_CWKEY_DRIVERS_CWKEY_H #define QLOG_CWKEY_DRIVERS_CWKEY_H #include #include #include #include class CWKeySerialInterface { public: explicit CWKeySerialInterface(const QString &portName, const qint32 baudrate, const qint32 timeout); ~CWKeySerialInterface() {}; protected: virtual qint64 sendDataAndWait(const QByteArray &data); virtual qint64 receiveDataAndWait(QByteArray &data); virtual qint64 writeAsyncData(const QByteArray &); QSerialPort serial; qint32 timeout; QMutex portMutex; }; class CWKeyIPInterface { public: explicit CWKeyIPInterface(const QString &hostname, const quint16 port); ~CWKeyIPInterface() {}; protected: virtual qint64 sendData(const QByteArray &data) = 0; virtual bool isSocketReady() = 0; QHostAddress serverName; quint16 port; bool hasIPAddress; }; class CWKeyUDPInterface : public CWKeyIPInterface { public: explicit CWKeyUDPInterface(const QString &hostname, const quint16 port); ~CWKeyUDPInterface() {}; protected: virtual qint64 sendData(const QByteArray &data) override; virtual bool isSocketReady() override; QUdpSocket socket; }; class CWKey : public QObject { Q_OBJECT; public: enum CWKeyTypeID { DUMMY_KEYER = 0, WINKEY_KEYER = 1, MORSEOVERCAT = 2, CWDAEMON_KEYER = 3, FLDIGI_KEYER = 4, LAST_MODEL = 4 }; enum CWKeyModeID { SINGLE_PADDLE = 0, IAMBIC_A = 1, IAMBIC_B = 2, ULTIMATE = 3, LAST_MODE = 4 }; signals: void keyError(QString, QString); void keyChangedWPMSpeed(qint32); void keyEchoText(QString); void keyHWButton1Pressed(); void keyHWButton2Pressed(); void keyHWButton3Pressed(); void keyHWButton4Pressed(); public: explicit CWKey(CWKeyModeID mode, qint32 defaultWPM, QObject *parent = nullptr); virtual ~CWKey() {}; virtual bool open() = 0; virtual bool close() = 0; virtual bool sendText(const QString &text) = 0; virtual bool setWPM(const qint16 wpm) = 0; virtual QString lastError() = 0; virtual bool immediatelyStop() = 0; virtual bool canStopSending() { return stopSendingCap;} virtual bool canEchoChar() { return echoCharsCap;} virtual bool mustRigConnected() { return rigMustConnectedCap;} virtual bool canSetSpeed() { return canSetKeySpeed; }; void printKeyCaps(); static CWKeyTypeID intToTypeID(int); static CWKeyModeID intToModeID(int); static bool isNetworkKey(const CWKeyTypeID &type); static QString stripSpeedMarkers(const QString &text); virtual qint16 minWPM() const { return 5; } virtual qint16 maxWPM() const { return 99; } friend QDataStream& operator<<(QDataStream& out, const CWKeyTypeID& v); friend QDataStream& operator>>(QDataStream& in, CWKeyTypeID& v); friend QDataStream& operator<<(QDataStream& out, const CWKeyModeID& v); friend QDataStream& operator>>(QDataStream& in, CWKeyModeID& v); protected: CWKeyModeID keyMode; qint32 defaultWPMSpeed; qint16 currentWPM; bool stopSendingCap; bool echoCharsCap; bool rigMustConnectedCap; bool canSetKeySpeed; static const QRegularExpression &speedMarkerRE(); qint16 applySpeedMarker(const QString &markerCapture); }; #endif // QLOG_CWKEY_DRIVERS_CWKEY_H foldynl-QLog-3252ff9/cwkey/drivers/CWWinKey.cpp000066400000000000000000000540711517334601000213360ustar00rootroot00000000000000#include #include "CWWinKey.h" #include "core/debug.h" /* Based on WinKey Spec * https://k1el.tripod.com/files/Winkey10.pdf * https://k1el.tripod.com/WinkeyUSBman.pdf */ MODULE_IDENTIFICATION("qlog.cwkey.driver.cwwinkey"); CWWinKey::CWWinKey(const QString &portName, const qint32 baudrate, const CWKey::CWKeyModeID mode, const qint32 defaultSpeed, bool paddleSwap, bool paddleOnlySidetone, qint32 sidetoneFrequency, QObject *parent) : CWKey(mode, defaultSpeed, parent), CWKeySerialInterface(portName, baudrate, 5000), isInHostMode(false), xoff(false), paddleSwap(paddleSwap), paddleOnlySidetone(paddleOnlySidetone), sidetoneFrequency(sidetoneFrequency), version(0) { FCT_IDENTIFICATION; minWPMRange = defaultSpeed - 15; // Winkey has 31 steps for POT, it means that 15 steps to left // and 15 steps to right if ( minWPMRange <= 0 ) minWPMRange = 1; stopSendingCap = true; echoCharsCap = true; canSetKeySpeed = true; } CWWinKey::~CWWinKey() { FCT_IDENTIFICATION; } bool CWWinKey::open() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for Command Mutex"; QMutexLocker locker(&commandMutex); __close(); /***************/ /* Open Port */ /***************/ qCDebug(runtime) << "Opening Serial" << serial.portName(); if ( !serial.open(QIODevice::ReadWrite) ) { qWarning() << "Cannot open " << serial.portName() << " Error code " << serial.error(); return false; } serial.setReadBufferSize(1); // WinKey Responses are 1B. // It is important to set correct Buffer size beucase message below /* https://forum.qt.io/topic/137268/solved-qserialport-readyread-not-emitted-qserialport-waitforreadyread-always-return-false-with-ch340 monegator Jun 16, 2022, 3:36 PM Hello there, i opened this thread so that others facing the same issue may find a solution. In the past we always used USB-UART cables based on FTDI232 chips (TTL-232R-5V-WE). However, due to a huge price increase in the last couple of years (5€ for a cable became 35€, now dropped to 25€) we decided to ditch FTDI and bought cables that use the CH340 chip. And why shouldn't we, they cost less than 2€ each. Our software based on VB6 worked flawlessly, even better (reduced latency) however we had issues with our Qt5 based software (Qt 5.15.2). Even if the data is available (QSerialPort::bytesAvailable return values greater than zero) the readyRead signal is never emitted, and waitForReadyRead always return false. The issue was that readBufferSize was set to zero (default value), and there must be something in the interaction between CH340 driver, windows COM port object and Qt that prevented the event from being raised, but that was never an issue for FTDI cables. The solution was to set readBufferSize to 1. Once readBufferSize is different than zero readyRead works again. */ serial.setDataTerminalReady(true); serial.setRequestToSend(false); qCDebug(runtime) << "Serial port has been opened"; QThread::msleep(200); QByteArray cmd; /***********************/ /* Echo Test */ /* Testing whether */ /* the opposite site */ /* is Winkey */ /***********************/ qCDebug(runtime) << "Echo Test"; cmd.resize(3); cmd[0] = 0x00; cmd[1] = 0x04; cmd[2] = 0xF1u; if ( sendDataAndWait(cmd) != 3 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); __close(); return false; } if ( receiveDataAndWait(cmd) < 1 ) { qWarning() << "Unexpected size of response or communication error"; qCDebug(runtime) << lastError(); __close(); return false; } if ( (unsigned char)cmd.at(0) != 0xF1 ) { qWarning() << "Connected device is not the Winkey type"; lastLogicalError = tr("Connected device is not WinKey"); __close(); return false; } qCDebug(runtime) << "Echo Test OK"; /********************/ /* Enable Host Mode */ /********************/ qCDebug(runtime) << "Enabling Host Mode"; cmd.resize(2); cmd[0] = 0x00; cmd[1] = 0x02; if ( sendDataAndWait(cmd) != 2 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); __close(); return false; } /* Based on the WinKey Spec, it is needed to call read: The host must wait for this return code before any other commands or data can be sent to Winkeyer */ if ( receiveDataAndWait(cmd) < 1 ) { qWarning() << "Unexpected size of response or communication error"; qCDebug(runtime) << lastError(); __close(); return false; } version = (unsigned char)cmd.at(0); qCDebug(runtime) << "Winkey version" << version; lastLogicalError = QString(); qCDebug(runtime) << "Host Mode has been enabled"; /******************/ /* Mode Setting */ /******************/ qCDebug(runtime) << "Mode Setting"; cmd.resize(2); cmd[0] = 0x0E; cmd[1] = buildWKModeByte(); if ( sendDataAndWait(cmd) != 2 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); __close(); return false; } //receiveDataAndWait(cmd); /* it is not needed to read here - no response */ qCDebug(runtime) << "Mode has been set"; /******************/ /* WK2 Mode Status*/ /******************/ if ( version >= 20 ) { qCDebug(runtime) << "WK2 PB Mode Setting"; cmd.resize(2); cmd[0] = 0x00; cmd[1] = 0x0B; if ( sendDataAndWait(cmd) != 2 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); __close(); return false; } // receiveDataAndWait(cmd); /* it is not needed to read here - no response */ qCDebug(runtime) << "WK2 PB Mode has been set"; } QThread::msleep(200); /* Starting Async Flow for WinKey */ /* From this point, all Serial port functions must be Async */ connect(&serial, &QSerialPort::readyRead, this, &CWWinKey::handleReadyRead); connect(&serial, &QSerialPort::bytesWritten, this, &CWWinKey::handleBytesWritten); connect(&serial, &QSerialPort::errorOccurred, this, &CWWinKey::handleError); isInHostMode = true; /* Force send current status */ __sendStatusRequest(); /* Set POT Range */ __setPOTRange(); /* Sidetone Setting */ __setSidetone(!paddleOnlySidetone); /* Set Default value */ __setWPM(defaultWPMSpeed); return true; } bool CWWinKey::close() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for Command Mutex"; QMutexLocker locker(&commandMutex); __close(); return true; } bool CWWinKey::sendText(const QString &text) { FCT_IDENTIFICATION; qCDebug(function_parameters) << text; qCDebug(runtime) << "Waiting for Command Mutex"; QMutexLocker locker(&commandMutex); if ( !isInHostMode ) { qCWarning(runtime) << "Key is not in Host Mode"; emit keyError(tr("Cannot send Text to Rig"), tr("Keyer is not connected")); return false; } qCDebug(runtime) << "Waiting for WriteBuffer Mutex"; writeBufferMutex.lock(); qCDebug(runtime) << "Appending input string"; int pos = 0; QRegularExpressionMatchIterator it = speedMarkerRE().globalMatch(text); while ( it.hasNext() ) { QRegularExpressionMatch match = it.next(); QString segment = text.mid(pos, match.capturedStart() - pos); segment.remove('\n'); writeBuffer.append(segment.toLatin1()); qint16 newWPM = applySpeedMarker(match.captured(1)); writeBuffer.append(static_cast(0x1C)); // WinKey buffered speed change writeBuffer.append(static_cast(newWPM)); emit keyChangedWPMSpeed(newWPM); pos = match.capturedEnd(); } QString lastSegment = text.mid(pos); lastSegment.remove('\n'); writeBuffer.append(lastSegment.toLatin1()); writeBufferMutex.unlock(); tryAsyncWrite(); return true; } void CWWinKey::tryAsyncWrite() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for WriteBuffer Mutex"; writeBufferMutex.lock(); qCDebug(runtime) << "WBuffer Size: " << writeBuffer.size() << "; XOFF: " << xoff; if ( writeBuffer.isEmpty() || xoff ) { writeBufferMutex.unlock(); qCDebug(runtime) << "Skipping write call"; return; } qint64 size = writeAsyncData(QByteArray(writeBuffer.constData(),1)); if ( size != 1 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); } writeBuffer.remove(0, size); writeBufferMutex.unlock(); QCoreApplication::processEvents(); } void CWWinKey::handleBytesWritten(qint64 bytes) { FCT_IDENTIFICATION; qCDebug(function_parameters) << bytes; tryAsyncWrite(); } void CWWinKey::handleReadyRead() { FCT_IDENTIFICATION; unsigned char rcvByte; qCDebug(runtime) << "Waiting for Port Mutex"; portMutex.lock(); qCDebug(runtime) << "Reading from Port"; serial.read((char*)&rcvByte,1); portMutex.unlock(); qCDebug(runtime) << "\t>>>>>> RCV Async:" << QByteArray::fromRawData((char*)(&rcvByte),1); if ( (rcvByte & 0xC0) == 0xC0 ) { qCDebug(runtime) << "\tStatus Information Message:"; xoff = false; if ( rcvByte == 0xC0 ) qCDebug(runtime) << "\t\tIdle"; else { if ( version >= 20 && rcvByte & 0x08 ) { qCDebug(runtime) << "\tPushButton Status Byte"; if ( rcvByte & 0x01 ) { qCDebug(runtime) << "\t\tButton1 pressed"; emit keyHWButton1Pressed(); } if ( rcvByte & 0x02 ) { qCDebug(runtime) << "\t\tButton2 pressed"; emit keyHWButton2Pressed(); } if ( rcvByte & 0x04 ) { qCDebug(runtime) << "\t\tButton3 pressed"; emit keyHWButton3Pressed(); } if ( rcvByte & 0x10 ) { qCDebug(runtime) << "\t\tButton4 pressed"; emit keyHWButton4Pressed(); } } else { qCDebug(runtime) << "\tStatus Byte"; if ( rcvByte & 0x01 ) { qCDebug(runtime) << "\t\tBuffer 2/3 full"; xoff = true; //slow down in sending Write Buffer - to block tryAsyncWrite } if ( rcvByte & 0x02 ) qCDebug(runtime) << "\t\tBrk-in"; if ( rcvByte & 0x04 ) qCDebug(runtime) << "\t\tKey Busy"; if ( rcvByte & 0x08 ) qCDebug(runtime) << "\t\tTunning"; if ( rcvByte & 0x0F ) qCDebug(runtime) << "\t\tWaiting"; } } } else if ( (rcvByte & 0xC0) == 0x80 ) { qint32 potValue = (rcvByte & 0x7F); qint32 potWPM = minWPMRange + potValue; qCDebug(runtime) << "\tPot: " << potValue << "; WPM=" << potWPM; setWPM(potWPM); } else { qCDebug(runtime) << "\tEcho Char"; emit keyEchoText(QString(char(rcvByte))); } tryAsyncWrite(); } void CWWinKey::handleError(QSerialPort::SerialPortError serialPortError) { FCT_IDENTIFICATION; QString detail = serial.errorString(); if ( serialPortError == QSerialPort::ReadError ) { qWarning() << "An I/O error occurred while reading: " << detail; } else if ( serialPortError == QSerialPort::WriteError ) { qWarning() << "An I/O error occurred while writing: " << detail; } else if ( serialPortError != QSerialPort::NoError ) { qWarning() << "An I/O error occurred: " << detail; } /* Emit error */ emit keyError(tr("Communication Error"), detail); } bool CWWinKey::setWPM(const qint16 wpm) { FCT_IDENTIFICATION; qCDebug(function_parameters) << wpm; qCDebug(runtime) << "Waiting for Command Mutex"; QMutexLocker locker(&commandMutex); bool ret = __setWPM(wpm); if ( ret ) { emit keyChangedWPMSpeed(wpm); //Winkey does not echo a new Speed //therefore keyChangedWPMSpeed informs the rest for QLog that //Key speed has been changed } return ret; } bool CWWinKey::__setWPM(const qint16 wpm) { FCT_IDENTIFICATION; qCDebug(function_parameters) << wpm; if ( !isInHostMode ) { qCWarning(runtime) << "Key is not in Host Mode"; emit keyError(tr("Cannot set Keyer Speed"), tr("Keyer is not connected")); return false; } QByteArray cmd; cmd.resize(2); cmd[0] = 0x02; cmd[1] = static_cast(wpm); qint64 size = writeAsyncData(cmd); if ( size != 2 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); return false; } currentWPM = wpm; return true; } QString CWWinKey::lastError() { FCT_IDENTIFICATION; qCDebug(runtime) << serial.error(); qCDebug(runtime) << lastLogicalError; return (lastLogicalError.isEmpty()) ? serial.errorString() : lastLogicalError; } bool CWWinKey::immediatelyStop() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for Command Mutex"; QMutexLocker locker(&commandMutex); if ( !isInHostMode ) { qCWarning(runtime) << "Key is not in Host Mode"; emit keyError(tr("Cannot stop Text Sending"), tr("Keyer is not connected")); return false; } qCDebug(runtime) << "Waiting for WriteBuffer Mutex"; writeBufferMutex.lock(); qCDebug(runtime) << "Clearing Buffer"; writeBuffer.clear(); writeBufferMutex.unlock(); QByteArray cmd; cmd.resize(3); cmd[0] = 0x06; /* Stop */ cmd[1] = 0x01; cmd[2] = 0x0A; /* Clear */ qint64 size = writeAsyncData(cmd); if ( size != 3 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); } return true; } void CWWinKey::__close() { FCT_IDENTIFICATION; qCDebug(runtime) << "Waiting for WriteBuffer Mutex"; writeBufferMutex.lock(); qCDebug(runtime) << "Clearing Buffer"; writeBuffer.clear(); writeBufferMutex.unlock(); if ( serial.isOpen() ) { /* Switch to Sync Mode */ disconnect(&serial, &QSerialPort::bytesWritten, this, &CWWinKey::handleBytesWritten); disconnect(&serial, &QSerialPort::errorOccurred, this, &CWWinKey::handleError); disconnect(&serial, &QSerialPort::readyRead, this, &CWWinKey::handleReadyRead); if ( isInHostMode ) { QByteArray cmd; /***********************/ /* clear buffer */ /***********************/ qCDebug(runtime) << "Clearing Buffer"; cmd.resize(3); cmd[0] = 0x06; /* Stop */ cmd[1] = 0x01; cmd[2] = 0x0A; /* Clear */ if ( sendDataAndWait(cmd) != 3 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); } else { qCDebug(runtime) << "Buffered has been cleared"; } /***********************/ /* Disabling Host Mode */ /***********************/ qCDebug(runtime) << "Disabling Host Mode"; cmd.resize(2); cmd[0] = 0x00; cmd[1] = 0x03; if ( sendDataAndWait(cmd) != 2 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); } else { qCDebug(runtime) << "Host Mode has been disabled"; } } QThread::msleep(200); serial.setDataTerminalReady(false); serial.close(); } else { qCDebug(runtime) << "Port is already closed"; } isInHostMode = false; xoff = false; version = 0; lastLogicalError = QString(); } unsigned char CWWinKey::buildWKModeByte() const { FCT_IDENTIFICATION; /* 7 (MSB) Disable Paddle watchdog 6 Paddle Echoback (1=Enabled, 0=Disabled) 5,4 Key Mode: 00 = Iambic B 01 = Iambic A 10 = Ultimatic 11 = Bug Mode 3 Paddle Swap (1=Swap, 0=Normal) 2 Serial Echoback (1=Enabled, 0=Disabled) 1 Autospace (1=Enabled, 0=Disabled) 0 (LSB) CT Spacing when=1, Normal Wordspace when=0 */ unsigned char settingByte = 0; settingByte |= 1 << 7; // Disabled Paddle Watchdog settingByte |= 0 << 6; // Paddle Echoback - Even Disable, characters are sent - K3NG Keyer switch (keyMode) // Key Mode { case IAMBIC_B: case LAST_MODE: //no action 00 break; case IAMBIC_A: settingByte |= 1 << 4; break; case ULTIMATE: settingByte |= 1 << 5; break; case SINGLE_PADDLE: settingByte |= 1 << 5; settingByte |= 1 << 4; break; } settingByte |= paddleSwap << 3; // Paddle Swap Normal settingByte |= 1 << 2; // Serial Echoback Enabled - must be //1 = 0 // Autospace Disabled //0 = 0 // Normal Wordspace return settingByte; } bool CWWinKey::__sendStatusRequest() { FCT_IDENTIFICATION; if ( !isInHostMode ) { qCWarning(runtime) << "Key is not in Host Mode"; return false; } QByteArray cmd; cmd.resize(1); cmd[0] = 0x15; qint64 size = writeAsyncData(cmd); if ( size != 1 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); } return true; } bool CWWinKey::__setPOTRange() { FCT_IDENTIFICATION; if ( !isInHostMode ) { qCWarning(runtime) << "Key is not in Host Mode"; return false; } if ( defaultWPMSpeed <= 0 ) { qCDebug(runtime) << "Default WPM Speed is negative" << defaultWPMSpeed; return false; } qCDebug(runtime) << "Key POT Range will be" << minWPMRange << minWPMRange + 31; QByteArray cmd; cmd.resize(4); cmd[0] = 0x05; cmd[1] = minWPMRange; cmd[2] = 31; cmd[3] = 0xFFu; qint64 size = writeAsyncData(cmd); if ( size != 4 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); } return true; } QList> CWWinKey::sidetoneFrequencies() { return { {tr("4000 Hz"), 4000}, {tr("2000 Hz"), 2000}, {tr("1333 Hz"), 1333}, {tr("1000 Hz"), 1000}, {tr("800 Hz"), 800}, {tr("666 Hz"), 666}, {tr("571 Hz"), 571}, {tr("500 Hz"), 500}, {tr("444 Hz"), 444}, {tr("400 Hz"), 400} }; } bool CWWinKey::__setSidetone(bool enabled) { FCT_IDENTIFICATION; /* * Sidetone Control command: 0x01 * Available on WinKey v2+ only (WK2 sidetone is always enabled). * * nn bit layout (Table 1 from WinKey spec): * Bit 7 : Paddle Only Sidetone - when 1, sidetone is muted for CW * sourced from the host port; paddle entry still has sidetone. * Bits 6-4 : Unused, set to zero. * Bits 3-0 : Sidetone frequency N (Table 2): * 0x1=4000Hz, 0x2=2000Hz, 0x3=1333Hz, 0x4=1000Hz, * 0x5=800Hz, 0x6=666Hz, 0x7=571Hz, 0x8=500Hz, * 0x9=444Hz, 0xA=400Hz * * enabled=false -> Paddle Only Sidetone (0x80 | freqCode): * host CW is muted, paddle sidetone at configured frequency. * enabled=true -> normal sidetone at configured frequency (freqCode). */ if ( version < 20 ) { qCDebug(runtime) << "Sidetone control not supported on WK1"; return false; } if ( !isInHostMode ) { qCWarning(runtime) << "Key is not in Host Mode"; return false; } /* Convert Hz to WinKey frequency code (Table 2 of WinKey spec). * sidetoneFrequency is stored in Hz; the combo shares Hz with CWDaemon. */ static const int hzToCode[][2] = { {4000, 1}, {2000, 2}, {1333, 3}, {1000, 4}, {800, 5}, {666, 6}, { 571, 7}, { 500, 8}, { 444, 9}, {400, 10} }; int freqCode = 5; // fallback: 800 Hz for ( const int (&pair)[2] : hzToCode ) { if ( pair[0] == sidetoneFrequency ) { freqCode = pair[1]; break; } } unsigned char freqCodeByte = static_cast(freqCode & 0x0F); QByteArray cmd; cmd.resize(2); cmd[0] = 0x01; cmd[1] = enabled ? freqCodeByte : static_cast(0x80u | freqCodeByte); qint64 size = writeAsyncData(cmd); if ( size != 2 ) { qWarning() << "Unexpected size of write response or communication error"; qCDebug(runtime) << lastError(); return false; } return true; } foldynl-QLog-3252ff9/cwkey/drivers/CWWinKey.h000066400000000000000000000032741517334601000210020ustar00rootroot00000000000000#ifndef QLOG_CWKEY_DRIVERS_CWWINKEY_H #define QLOG_CWKEY_DRIVERS_CWWINKEY_H #include #include "CWKey.h" class CWWinKey : public CWKey, protected CWKeySerialInterface { Q_OBJECT public: explicit CWWinKey(const QString &portName, const qint32 baudrate, const CWKey::CWKeyModeID mode, const qint32 defaultSpeed, bool paddleSwap, bool paddleOnlySidetone, qint32 sidetoneFrequency, QObject *parent = nullptr); virtual ~CWWinKey(); virtual bool open() override; virtual bool close() override; virtual QString lastError() override; virtual bool sendText(const QString &text) override; virtual bool setWPM(const qint16 wpm) override; virtual bool immediatelyStop() override; static QList> sidetoneFrequencies(); static int defaultSidetoneFrequency() { return 800; } private: bool isInHostMode; bool xoff; bool paddleSwap; bool paddleOnlySidetone; qint32 sidetoneFrequency; QMutex writeBufferMutex; QMutex commandMutex; QByteArray writeBuffer; qint32 minWPMRange; QString lastLogicalError; void tryAsyncWrite(); unsigned char buildWKModeByte() const; bool __sendStatusRequest(); bool __setPOTRange(); bool __setWPM(const qint16 wpm); bool __setSidetone(bool enabled); void __close(); unsigned char version; private slots: void handleBytesWritten(qint64 bytes); void handleError(QSerialPort::SerialPortError serialPortError); void handleReadyRead(); }; #endif // QLOG_CWKEY_DRIVERS_CWWINKEY_H foldynl-QLog-3252ff9/data/000077500000000000000000000000001517334601000152745ustar00rootroot00000000000000foldynl-QLog-3252ff9/data/Accents.cpp000066400000000000000000047515321517334601000174010ustar00rootroot00000000000000#include "Data.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.data.data"); const char Data::translitTab[] = { 1, ' ', 1, '!', 2, 'C', '/', 2, 'P', 'S', 2, '$', '?', 2, 'Y', '=', 1, '|', 2, 'S', 'S', 1, '\"', 3, '(', 'c', ')', 1, 'a', 2, '<', '<', 1, '!', 3, '(', 'r', ')', 1, '-', 3, 'd', 'e', 'g', 2, '+', '-', 1, '2', 1, '3', 1, '\'', 1, 'u', 1, 'P', 1, '*', 1, ',', 1, '1', 1, 'o', 2, '>', '>', 5, ' ', '1', '/', '4', ' ', 5, ' ', '1', '/', '2', ' ', 5, ' ', '3', '/', '4', ' ', 1, '?', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 2, 'A', 'E', 1, 'C', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'I', 1, 'I', 1, 'I', 1, 'I', 1, 'D', 1, 'N', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'x', 1, 'O', 1, 'U', 1, 'U', 1, 'U', 1, 'U', 1, 'Y', 2, 'T', 'h', 2, 's', 's', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 2, 'a', 'e', 1, 'c', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'i', 1, 'i', 1, 'i', 1, 'i', 1, 'd', 1, 'n', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, '/', 1, 'o', 1, 'u', 1, 'u', 1, 'u', 1, 'u', 1, 'y', 2, 't', 'h', 1, 'y', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'C', 1, 'c', 1, 'C', 1, 'c', 1, 'C', 1, 'c', 1, 'C', 1, 'c', 1, 'D', 1, 'd', 1, 'D', 1, 'd', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'G', 1, 'g', 1, 'G', 1, 'g', 1, 'G', 1, 'g', 1, 'G', 1, 'g', 1, 'H', 1, 'h', 1, 'H', 1, 'h', 1, 'I', 1, 'i', 1, 'I', 1, 'i', 1, 'I', 1, 'i', 1, 'I', 1, 'i', 1, 'I', 1, 'i', 2, 'I', 'J', 2, 'i', 'j', 1, 'J', 1, 'j', 1, 'K', 1, 'k', 1, 'k', 1, 'L', 1, 'l', 1, 'L', 1, 'l', 1, 'L', 1, 'l', 1, 'L', 1, 'l', 1, 'L', 1, 'l', 1, 'N', 1, 'n', 1, 'N', 1, 'n', 1, 'N', 1, 'n', 2, '\'', 'n', 2, 'n', 'g', 2, 'N', 'G', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 2, 'O', 'E', 2, 'o', 'e', 1, 'R', 1, 'r', 1, 'R', 1, 'r', 1, 'R', 1, 'r', 1, 'S', 1, 's', 1, 'S', 1, 's', 1, 'S', 1, 's', 1, 'S', 1, 's', 1, 'T', 1, 't', 1, 'T', 1, 't', 1, 'T', 1, 't', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'W', 1, 'w', 1, 'Y', 1, 'y', 1, 'Y', 1, 'Z', 1, 'z', 1, 'Z', 1, 'z', 1, 'Z', 1, 'z', 1, 's', 1, 'b', 1, 'B', 1, 'B', 1, 'b', 1, '6', 1, '6', 1, 'O', 1, 'C', 1, 'c', 1, 'D', 1, 'D', 1, 'D', 1, 'd', 1, 'd', 1, '3', 1, '@', 1, 'E', 1, 'F', 1, 'f', 1, 'G', 1, 'G', 2, 'h', 'v', 1, 'I', 1, 'I', 1, 'K', 1, 'k', 1, 'l', 1, 'l', 1, 'W', 1, 'N', 1, 'n', 1, 'O', 1, 'O', 1, 'o', 2, 'O', 'I', 2, 'o', 'i', 1, 'P', 1, 'p', 2, 'Y', 'R', 1, '2', 1, '2', 2, 'S', 'H', 2, 's', 'h', 1, 't', 1, 'T', 1, 't', 1, 'T', 1, 'U', 1, 'u', 1, 'Y', 1, 'V', 1, 'Y', 1, 'y', 1, 'Z', 1, 'z', 2, 'Z', 'H', 2, 'Z', 'H', 2, 'z', 'h', 2, 'z', 'h', 1, '2', 1, '5', 1, '5', 2, 't', 's', 1, 'w', 1, '|', 2, '|', '|', 2, '|', '=', 1, '!', 2, 'D', 'Z', 2, 'D', 'z', 2, 'd', 'z', 2, 'L', 'J', 2, 'L', 'j', 2, 'l', 'j', 2, 'N', 'J', 2, 'N', 'j', 2, 'n', 'j', 1, 'A', 1, 'a', 1, 'I', 1, 'i', 1, 'O', 1, 'o', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, '@', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 2, 'A', 'E', 2, 'a', 'e', 1, 'G', 1, 'g', 1, 'G', 1, 'g', 1, 'K', 1, 'k', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 2, 'Z', 'H', 2, 'z', 'h', 1, 'j', 2, 'D', 'Z', 2, 'D', 'z', 2, 'd', 'z', 1, 'G', 1, 'g', 2, 'H', 'V', 1, 'W', 1, 'N', 1, 'n', 1, 'A', 1, 'a', 2, 'A', 'E', 2, 'a', 'e', 1, 'O', 1, 'o', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'I', 1, 'i', 1, 'I', 1, 'i', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'R', 1, 'r', 1, 'R', 1, 'r', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'S', 1, 's', 1, 'T', 1, 't', 1, 'Y', 1, 'y', 1, 'H', 1, 'h', 1, 'N', 1, 'd', 2, 'O', 'U', 2, 'o', 'u', 1, 'Z', 1, 'z', 1, 'A', 1, 'a', 1, 'E', 1, 'e', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'Y', 1, 'y', 1, 'l', 1, 'n', 1, 't', 1, 'j', 2, 'd', 'b', 2, 'q', 'p', 1, 'A', 1, 'C', 1, 'c', 1, 'L', 1, 'T', 1, 's', 1, 'z', 1, 'B', 1, 'U', 1, '^', 1, 'E', 1, 'e', 1, 'J', 1, 'j', 1, 'q', 1, 'q', 1, 'R', 1, 'r', 1, 'Y', 1, 'y', 1, 'a', 1, 'a', 1, 'a', 1, 'b', 1, 'o', 1, 'c', 1, 'd', 1, 'd', 1, 'e', 1, '@', 1, '@', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'j', 1, 'g', 1, 'g', 1, 'g', 1, 'g', 1, 'u', 1, 'Y', 1, 'h', 1, 'h', 1, 'i', 1, 'i', 1, 'I', 1, 'l', 1, 'l', 1, 'l', 2, 'l', 'Z', 1, 'W', 1, 'W', 1, 'm', 1, 'n', 1, 'n', 1, 'n', 1, 'o', 2, 'O', 'E', 1, 'O', 1, 'F', 1, 'r', 1, 'r', 1, 'r', 1, 'r', 1, 'r', 1, 'r', 1, 'r', 1, 'R', 1, 'R', 1, 's', 1, 'S', 1, 'j', 1, 'S', 1, 'S', 1, 't', 1, 't', 1, 'u', 1, 'U', 1, 'v', 1, '^', 1, 'w', 1, 'y', 1, 'Y', 1, 'z', 1, 'z', 1, 'Z', 1, 'Z', 1, '?', 1, '?', 1, '?', 1, 'C', 1, '@', 1, 'B', 1, 'E', 1, 'G', 1, 'H', 1, 'j', 1, 'k', 1, 'L', 1, 'q', 1, '?', 1, '?', 2, 'd', 'z', 2, 'd', 'Z', 2, 'd', 'z', 2, 't', 's', 2, 't', 'S', 2, 't', 'C', 2, 'f', 'N', 2, 'l', 's', 2, 'l', 'z', 2, 'W', 'W', 2, ']', ']', 1, 'h', 1, 'h', 1, 'h', 1, 'h', 1, 'j', 1, 'r', 1, 'r', 1, 'r', 1, 'r', 1, 'w', 1, 'y', 1, '\'', 1, '\"', 1, '`', 1, '\'', 1, '`', 1, '`', 1, '\'', 1, '?', 1, '?', 1, '<', 1, '>', 1, '^', 1, 'V', 1, '^', 1, 'V', 1, '\'', 1, '-', 1, '/', 1, '\\', 1, ',', 1, '_', 1, '\\', 1, '/', 1, ':', 1, '.', 1, '`', 1, '\'', 1, '^', 1, 'V', 1, '+', 1, '-', 1, 'V', 1, '.', 1, '@', 1, ',', 1, '~', 1, '\"', 1, 'R', 1, 'X', 1, 'G', 1, 'l', 1, 's', 1, 'x', 1, '?', 1, 'V', 1, '=', 1, '\"', 1, 'a', 1, 'e', 1, 'i', 1, 'o', 1, 'u', 1, 'c', 1, 'd', 1, 'h', 1, 'm', 1, 'r', 1, 't', 1, 'v', 1, 'x', 1, '\'', 1, ',', 1, '?', 1, 'A', 1, ';', 1, 'E', 1, 'E', 1, 'I', 1, 'O', 1, 'U', 1, 'O', 1, 'I', 1, 'A', 1, 'B', 1, 'G', 1, 'D', 1, 'E', 1, 'Z', 1, 'E', 2, 'T', 'h', 1, 'I', 1, 'K', 1, 'L', 1, 'M', 1, 'N', 2, 'K', 's', 1, 'O', 1, 'P', 1, 'R', 1, 'S', 1, 'T', 1, 'U', 2, 'P', 'h', 2, 'K', 'h', 2, 'P', 's', 1, 'O', 1, 'I', 1, 'U', 1, 'a', 1, 'e', 1, 'e', 1, 'i', 1, 'u', 1, 'a', 1, 'b', 1, 'g', 1, 'd', 1, 'e', 1, 'z', 1, 'e', 2, 't', 'h', 1, 'i', 1, 'k', 1, 'l', 1, 'm', 1, 'n', 1, 'x', 1, 'o', 1, 'p', 1, 'r', 1, 's', 1, 's', 1, 't', 1, 'u', 2, 'p', 'h', 2, 'k', 'h', 2, 'p', 's', 1, 'o', 1, 'i', 1, 'u', 1, 'o', 1, 'u', 1, 'o', 1, 'b', 2, 't', 'h', 1, 'U', 1, 'U', 1, 'U', 2, 'p', 'h', 1, 'p', 1, '&', 2, 'S', 't', 2, 's', 't', 1, 'W', 1, 'w', 1, 'Q', 1, 'q', 2, 'S', 'p', 2, 's', 'p', 2, 'S', 'h', 2, 's', 'h', 1, 'F', 1, 'f', 2, 'K', 'h', 2, 'k', 'h', 1, 'H', 1, 'h', 1, 'G', 1, 'g', 2, 'C', 'H', 2, 'c', 'h', 2, 'T', 'i', 2, 't', 'i', 1, 'k', 1, 'r', 1, 'c', 1, 'j', 2, 'I', 'e', 2, 'I', 'o', 2, 'D', 'j', 2, 'G', 'j', 2, 'I', 'e', 2, 'D', 'z', 1, 'I', 2, 'Y', 'i', 1, 'J', 2, 'L', 'j', 2, 'N', 'j', 3, 'T', 's', 'h', 2, 'K', 'j', 1, 'I', 1, 'U', 3, 'D', 'z', 'h', 1, 'A', 1, 'B', 1, 'V', 1, 'G', 1, 'D', 1, 'E', 2, 'Z', 'h', 1, 'Z', 1, 'I', 1, 'I', 1, 'K', 1, 'L', 1, 'M', 1, 'N', 1, 'O', 1, 'P', 1, 'R', 1, 'S', 1, 'T', 1, 'U', 1, 'F', 2, 'K', 'h', 2, 'T', 's', 2, 'C', 'h', 2, 'S', 'h', 4, 'S', 'h', 'c', 'h', 1, '\'', 1, 'Y', 1, '\'', 1, 'E', 2, 'I', 'u', 2, 'I', 'a', 1, 'a', 1, 'b', 1, 'v', 1, 'g', 1, 'd', 1, 'e', 2, 'z', 'h', 1, 'z', 1, 'i', 1, 'i', 1, 'k', 1, 'l', 1, 'm', 1, 'n', 1, 'o', 1, 'p', 1, 'r', 1, 's', 1, 't', 1, 'u', 1, 'f', 2, 'k', 'h', 2, 't', 's', 2, 'c', 'h', 2, 's', 'h', 4, 's', 'h', 'c', 'h', 1, '\'', 1, 'y', 1, '\'', 1, 'e', 2, 'i', 'u', 2, 'i', 'a', 2, 'i', 'e', 2, 'i', 'o', 2, 'd', 'j', 2, 'g', 'j', 2, 'i', 'e', 2, 'd', 'z', 1, 'i', 2, 'y', 'i', 1, 'j', 2, 'l', 'j', 2, 'n', 'j', 3, 't', 's', 'h', 2, 'k', 'j', 1, 'i', 1, 'u', 3, 'd', 'z', 'h', 1, 'O', 1, 'o', 1, 'E', 1, 'e', 2, 'I', 'e', 2, 'i', 'e', 1, 'E', 1, 'e', 2, 'I', 'e', 2, 'i', 'e', 1, 'O', 1, 'o', 2, 'I', 'o', 2, 'i', 'o', 2, 'K', 's', 2, 'k', 's', 2, 'P', 's', 2, 'p', 's', 1, 'F', 1, 'f', 1, 'Y', 1, 'y', 1, 'Y', 1, 'y', 1, 'u', 1, 'u', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 2, 'O', 't', 2, 'o', 't', 1, 'Q', 1, 'q', 6, '*', '1', '0', '0', '0', '*', 9, '*', '1', '0', '0', '.', '0', '0', '0', '*', 11, '*', '1', '.', '0', '0', '0', '.', '0', '0', '0', '*', 1, '\"', 1, '\"', 2, 'R', '\'', 2, 'r', '\'', 2, 'G', '\'', 2, 'g', '\'', 2, 'G', '\'', 2, 'g', '\'', 2, 'G', '\'', 2, 'g', '\'', 3, 'Z', 'h', '\'', 3, 'z', 'h', '\'', 2, 'Z', '\'', 2, 'z', '\'', 2, 'K', '\'', 2, 'k', '\'', 2, 'K', '\'', 2, 'k', '\'', 2, 'K', '\'', 2, 'k', '\'', 2, 'K', '\'', 2, 'k', '\'', 2, 'N', '\'', 2, 'n', '\'', 2, 'N', 'g', 2, 'n', 'g', 2, 'P', '\'', 2, 'p', '\'', 2, 'K', 'h', 2, 'k', 'h', 2, 'S', '\'', 2, 's', '\'', 2, 'T', '\'', 2, 't', '\'', 1, 'U', 1, 'u', 2, 'U', '\'', 2, 'u', '\'', 3, 'K', 'h', '\'', 3, 'k', 'h', '\'', 3, 'T', 't', 's', 3, 't', 't', 's', 3, 'C', 'h', '\'', 3, 'c', 'h', '\'', 3, 'C', 'h', '\'', 3, 'c', 'h', '\'', 1, 'H', 1, 'h', 2, 'C', 'h', 2, 'c', 'h', 3, 'C', 'h', '\'', 3, 'c', 'h', '\'', 1, '`', 2, 'Z', 'h', 2, 'z', 'h', 2, 'K', '\'', 2, 'k', '\'', 2, 'N', '\'', 2, 'n', '\'', 2, 'C', 'h', 2, 'c', 'h', 1, 'a', 1, 'a', 1, 'A', 1, 'a', 2, 'A', 'e', 2, 'a', 'e', 2, 'I', 'e', 2, 'i', 'e', 1, '@', 1, '@', 1, '@', 1, '@', 2, 'Z', 'h', 2, 'z', 'h', 1, 'Z', 1, 'z', 2, 'D', 'z', 2, 'd', 'z', 1, 'I', 1, 'i', 1, 'I', 1, 'i', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'E', 1, 'e', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 2, 'C', 'h', 2, 'c', 'h', 1, 'Y', 1, 'y', 1, 'A', 1, 'B', 1, 'G', 1, 'D', 1, 'E', 1, 'Z', 1, 'E', 1, 'E', 2, 'T', '`', 2, 'Z', 'h', 1, 'I', 1, 'L', 2, 'K', 'h', 2, 'T', 's', 1, 'K', 1, 'H', 2, 'D', 'z', 2, 'G', 'h', 2, 'C', 'h', 1, 'M', 1, 'Y', 1, 'N', 2, 'S', 'h', 1, 'O', 3, 'C', 'h', '`', 1, 'P', 1, 'J', 2, 'R', 'h', 1, 'S', 1, 'V', 1, 'T', 1, 'R', 3, 'T', 's', '`', 1, 'W', 2, 'P', '`', 2, 'K', '`', 1, 'O', 1, 'F', 1, '<', 1, '\'', 1, '/', 1, '!', 1, ',', 1, '?', 1, '.', 1, 'a', 1, 'b', 1, 'g', 1, 'd', 1, 'e', 1, 'z', 1, 'e', 1, 'e', 2, 't', '`', 2, 'z', 'h', 1, 'i', 1, 'l', 2, 'k', 'h', 2, 't', 's', 1, 'k', 1, 'h', 2, 'd', 'z', 2, 'g', 'h', 2, 'c', 'h', 1, 'm', 1, 'y', 1, 'n', 2, 's', 'h', 1, 'o', 3, 'c', 'h', '`', 1, 'p', 1, 'j', 2, 'r', 'h', 1, 's', 1, 'v', 1, 't', 1, 'r', 3, 't', 's', '`', 1, 'w', 2, 'p', '`', 2, 'k', '`', 1, 'o', 1, 'f', 2, 'e', 'w', 1, ':', 1, '-', 1, 'e', 1, 'a', 1, 'o', 1, 'i', 1, 'e', 1, 'e', 1, 'a', 1, 'a', 1, 'o', 1, 'o', 1, 'u', 1, '-', 1, '|', 1, '.', 1, 'n', 1, 'o', 1, 'A', 1, 'b', 1, 'g', 1, 'd', 1, 'h', 1, 'v', 1, 'z', 1, 'H', 1, 'T', 1, 'y', 2, 'K', 'H', 2, 'K', 'H', 1, 'l', 1, 'm', 1, 'm', 1, 'n', 1, 'n', 1, 's', 1, '`', 1, 'p', 1, 'p', 2, 'T', 'S', 2, 'T', 'S', 1, 'k', 1, 'r', 2, 'S', 'H', 1, 't', 3, 'Y', 'Y', 'Y', 1, 'V', 2, 'O', 'Y', 2, 'E', 'Y', 1, '\'', 1, '\"', 1, ',', 1, ';', 1, '?', 1, 'a', 1, '\'', 2, 'w', '\'', 2, 'y', '\'', 1, 'b', 1, '@', 1, 't', 2, 't', 'h', 1, 'j', 1, 'H', 2, 'k', 'h', 1, 'd', 2, 'd', 'h', 1, 'r', 1, 'z', 1, 's', 2, 's', 'h', 1, 'S', 1, 'D', 1, 'T', 1, 'Z', 1, '`', 1, 'G', 1, 'f', 1, 'q', 1, 'k', 1, 'l', 1, 'm', 1, 'n', 1, 'h', 1, 'w', 1, '~', 1, 'y', 2, 'a', 'n', 2, 'u', 'n', 2, 'i', 'n', 1, 'a', 1, 'u', 1, 'i', 1, 'W', 1, '\'', 1, '\'', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, '%', 1, '.', 1, ',', 1, '*', 1, '\'', 1, '\'', 1, '\'', 1, '\'', 2, '\'', 'w', 2, '\'', 'u', 2, '\'', 'y', 2, 't', 't', 3, 't', 't', 'h', 1, 'b', 1, 't', 1, 'T', 1, 'p', 2, 't', 'h', 2, 'b', 'h', 2, '\'', 'h', 1, 'H', 2, 'n', 'y', 2, 'd', 'y', 1, 'H', 2, 'c', 'h', 3, 'c', 'c', 'h', 2, 'd', 'd', 1, 'D', 1, 'D', 2, 'D', 't', 2, 'd', 'h', 3, 'd', 'd', 'h', 1, 'd', 1, 'D', 1, 'D', 2, 'r', 'r', 1, 'R', 1, 'R', 1, 'R', 1, 'R', 1, 'R', 1, 'R', 1, 'j', 1, 'R', 1, 'S', 1, 'S', 1, 'S', 1, 'S', 1, 'S', 1, 'T', 2, 'G', 'H', 1, 'F', 1, 'F', 1, 'F', 1, 'v', 1, 'f', 2, 'p', 'h', 1, 'Q', 1, 'Q', 2, 'k', 'h', 1, 'k', 1, 'K', 1, 'K', 2, 'n', 'g', 1, 'K', 1, 'g', 1, 'G', 1, 'N', 1, 'G', 1, 'G', 1, 'G', 1, 'L', 1, 'L', 1, 'L', 1, 'L', 1, 'N', 1, 'N', 1, 'N', 1, 'N', 1, 'N', 1, 'h', 2, 'C', 'h', 2, 'h', 'y', 1, 'h', 1, 'H', 1, '@', 1, 'W', 2, 'o', 'e', 2, 'o', 'e', 1, 'u', 2, 'y', 'u', 2, 'y', 'u', 1, 'W', 1, 'v', 1, 'y', 1, 'Y', 1, 'Y', 1, 'W', 1, 'y', 2, 'y', '\'', 1, '.', 2, 'a', 'e', 1, '@', 1, '#', 1, '^', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 2, 'S', 'h', 1, 'D', 2, 'G', 'h', 1, '&', 2, '+', 'm', 2, '/', '/', 1, '/', 1, ',', 1, '!', 1, '!', 1, '-', 1, ',', 1, ',', 1, ';', 1, '?', 1, '~', 1, '{', 1, '}', 1, '*', 1, '\'', 1, 'b', 1, 'g', 1, 'g', 1, 'd', 1, 'd', 1, 'h', 1, 'w', 1, 'z', 1, 'H', 1, 't', 1, 't', 1, 'y', 2, 'y', 'h', 1, 'k', 1, 'l', 1, 'm', 1, 'n', 1, 's', 1, 's', 1, '`', 1, 'p', 1, 'p', 1, 'S', 1, 'q', 1, 'r', 2, 's', 'h', 1, 't', 1, 'a', 1, 'a', 1, 'a', 1, 'A', 1, 'A', 1, 'A', 1, 'e', 1, 'e', 1, 'e', 1, 'E', 1, 'i', 1, 'i', 1, 'u', 1, 'u', 1, 'u', 1, 'o', 1, '`', 1, '\'', 1, 'X', 1, 'Q', 1, '@', 1, '@', 1, '|', 1, '+', 1, 'h', 2, 's', 'h', 1, 'n', 1, 'r', 1, 'b', 1, 'L', 1, 'k', 1, '\'', 1, 'v', 1, 'm', 1, 'f', 2, 'd', 'h', 2, 't', 'h', 1, 'l', 1, 'g', 2, 'n', 'y', 1, 's', 1, 'd', 1, 'z', 1, 't', 1, 'y', 1, 'p', 1, 'j', 2, 'c', 'h', 2, 't', 't', 2, 'h', 'h', 2, 'k', 'h', 2, 't', 'h', 1, 'z', 2, 's', 'h', 1, 's', 1, 'd', 1, 't', 1, 'z', 1, '`', 2, 'g', 'h', 1, 'q', 1, 'w', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'e', 'e', 1, 'u', 2, 'o', 'o', 1, 'e', 2, 'e', 'y', 1, 'o', 2, 'o', 'a', 1, 'N', 1, 'N', 1, 'H', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 1, 'L', 2, 'e', 'N', 1, 'e', 1, 'e', 2, 'a', 'i', 2, 'o', 'N', 1, 'o', 1, 'o', 2, 'a', 'u', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 3, 'n', 'n', 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 1, 'y', 1, 'r', 2, 'r', 'r', 1, 'l', 1, 'l', 3, 'l', 'l', 'l', 1, 'v', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 1, '\'', 1, '\'', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 2, 'R', 'R', 2, 'e', 'N', 1, 'e', 1, 'e', 2, 'a', 'i', 2, 'o', 'N', 1, 'o', 1, 'o', 2, 'a', 'u', 3, 'A', 'U', 'M', 1, '\'', 1, '\'', 1, '`', 1, '\'', 1, 'q', 3, 'k', 'h', 'h', 3, 'g', 'h', 'h', 1, 'z', 4, 'd', 'd', 'd', 'h', 2, 'r', 'h', 1, 'f', 2, 'y', 'y', 2, 'R', 'R', 2, 'L', 'L', 1, 'L', 2, 'L', 'L', 3, ' ', '/', ' ', 4, ' ', '/', '/', ' ', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, '.', 1, 'N', 1, 'N', 1, 'H', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 2, 'R', 'R', 1, 'e', 2, 'a', 'i', 1, 'o', 2, 'a', 'u', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 1, 'y', 1, 'r', 1, 'l', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 1, '\'', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 2, 'R', 'R', 1, 'e', 2, 'a', 'i', 1, 'o', 2, 'a', 'u', 1, '+', 2, 'r', 'r', 2, 'r', 'h', 2, 'y', 'y', 2, 'R', 'R', 2, 'L', 'L', 1, 'L', 2, 'L', 'L', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 2, 'r', '\'', 2, 'r', '`', 2, 'R', 's', 2, 'R', 's', 2, '1', '/', 2, '2', '/', 2, '3', '/', 2, '4', '/', 7, ' ', '1', ' ', '-', ' ', '1', '/', 3, '/', '1', '6', 1, 'N', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 2, 'e', 'e', 2, 'a', 'i', 2, 'o', 'o', 2, 'a', 'u', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'b', 1, 'm', 1, 'y', 1, 'r', 1, 'l', 2, 'l', 'l', 1, 'v', 2, 's', 'h', 1, 's', 1, 'h', 1, '\'', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 2, 'e', 'e', 2, 'a', 'i', 2, 'o', 'o', 2, 'a', 'u', 3, 'k', 'h', 'h', 3, 'g', 'h', 'h', 1, 'z', 2, 'r', 'r', 1, 'f', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, 'N', 1, 'H', 6, 'G', '.', 'E', '.', 'O', '.', 1, 'N', 1, 'N', 1, 'H', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 2, 'e', 'N', 1, 'e', 2, 'a', 'i', 2, 'o', 'N', 1, 'o', 2, 'a', 'u', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 2, 'y', 'a', 1, 'r', 1, 'l', 2, 'l', 'l', 1, 'v', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 1, '\'', 1, '\'', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 2, 'R', 'R', 2, 'e', 'N', 1, 'e', 2, 'a', 'i', 2, 'o', 'N', 1, 'o', 2, 'a', 'u', 3, 'A', 'U', 'M', 2, 'R', 'R', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, 'N', 1, 'N', 1, 'H', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 1, 'L', 1, 'e', 2, 'a', 'i', 1, 'o', 2, 'a', 'u', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 1, 'y', 1, 'r', 1, 'l', 2, 'l', 'l', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 1, '\'', 1, '\'', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 1, 'e', 2, 'a', 'i', 1, 'o', 2, 'a', 'u', 1, '+', 1, '+', 2, 'r', 'r', 2, 'r', 'h', 2, 'y', 'y', 2, 'R', 'R', 2, 'L', 'L', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, 'N', 1, 'H', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, 'k', 2, 'n', 'g', 1, 'c', 1, 'j', 2, 'n', 'y', 2, 't', 't', 2, 'n', 'n', 1, 't', 1, 'n', 3, 'n', 'n', 'n', 1, 'p', 1, 'm', 1, 'y', 1, 'r', 2, 'r', 'r', 1, 'l', 2, 'l', 'l', 3, 'l', 'l', 'l', 1, 'v', 2, 's', 's', 1, 's', 1, 'h', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, '+', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 4, '+', '1', '0', '+', 5, '+', '1', '0', '0', '+', 6, '+', '1', '0', '0', '0', '+', 1, 'N', 1, 'N', 1, 'H', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 1, 'L', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 1, 'y', 1, 'r', 2, 'r', 'r', 1, 'l', 2, 'l', 'l', 1, 'v', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 2, 'R', 'R', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, '+', 1, '+', 2, 'R', 'R', 2, 'L', 'L', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, 'N', 1, 'H', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 1, 'L', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 1, 'y', 1, 'r', 2, 'r', 'r', 1, 'l', 2, 'l', 'l', 1, 'v', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 2, 'R', 'R', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, '+', 1, '+', 3, 'l', 'l', 'l', 2, 'R', 'R', 2, 'L', 'L', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, 'N', 1, 'H', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 1, 'L', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 1, 'y', 1, 'r', 2, 'r', 'r', 1, 'l', 2, 'l', 'l', 3, 'l', 'l', 'l', 1, 'v', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, '+', 2, 'R', 'R', 2, 'L', 'L', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, 'N', 1, 'H', 1, 'a', 2, 'a', 'a', 2, 'a', 'e', 3, 'a', 'a', 'e', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 2, 'R', 'R', 1, 'L', 2, 'L', 'L', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 3, 'n', 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 3, 'j', 'n', 'y', 3, 'n', 'y', 'j', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 4, 'n', 'n', 'd', 'd', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 2, 'n', 'd', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 2, 'm', 'b', 1, 'y', 1, 'r', 1, 'l', 1, 'v', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 2, 'l', 'l', 1, 'f', 2, 'a', 'a', 2, 'a', 'e', 3, 'a', 'a', 'e', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 1, 'e', 2, 'e', 'e', 2, 'a', 'i', 1, 'o', 2, 'o', 'o', 2, 'a', 'u', 1, 'L', 2, 'R', 'R', 2, 'L', 'L', 3, ' ', '.', ' ', 1, 'k', 2, 'k', 'h', 2, 'k', 'h', 2, 'k', 'h', 2, 'k', 'h', 2, 'k', 'h', 2, 'n', 'g', 3, 'c', 'c', 'h', 2, 'c', 'h', 2, 'c', 'h', 2, 'c', 'h', 2, 'c', 'h', 1, 'y', 1, 'd', 1, 't', 2, 't', 'h', 2, 't', 'h', 2, 't', 'h', 1, 'n', 1, 'd', 1, 't', 2, 't', 'h', 2, 't', 'h', 2, 't', 'h', 1, 'n', 1, 'b', 1, 'p', 2, 'p', 'h', 1, 'f', 2, 'p', 'h', 1, 'f', 2, 'p', 'h', 1, 'm', 1, 'y', 1, 'r', 1, 'R', 1, 'l', 1, 'L', 1, 'w', 1, 's', 1, 's', 1, 's', 1, 'h', 1, 'l', 1, '`', 1, 'h', 1, '~', 1, 'a', 1, 'a', 2, 'a', 'a', 2, 'a', 'm', 1, 'i', 2, 'i', 'i', 2, 'u', 'e', 3, 'u', 'u', 'e', 1, 'u', 2, 'u', 'u', 1, '\'', 3, 'B', 'h', '.', 1, 'e', 2, 'a', 'e', 1, 'o', 2, 'a', 'i', 2, 'a', 'i', 2, 'a', 'o', 1, '+', 1, 'M', 3, ' ', '*', ' ', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 4, ' ', '/', '/', ' ', 5, ' ', '/', '/', '/', ' ', 1, 'k', 2, 'k', 'h', 2, 'k', 'h', 2, 'n', 'g', 2, 'c', 'h', 1, 's', 2, 'n', 'y', 1, 'd', 1, 'h', 2, 't', 'h', 2, 't', 'h', 1, 'n', 1, 'b', 1, 'p', 2, 'p', 'h', 1, 'f', 2, 'p', 'h', 1, 'f', 1, 'm', 1, 'y', 1, 'r', 1, 'l', 1, 'w', 1, 's', 1, 'h', 1, '`', 1, '~', 1, 'a', 2, 'a', 'a', 2, 'a', 'm', 1, 'i', 2, 'i', 'i', 1, 'y', 2, 'y', 'y', 1, 'u', 2, 'u', 'u', 1, 'o', 1, 'l', 2, 'n', 'y', 1, 'e', 2, 'e', 'i', 1, 'o', 2, 'a', 'y', 2, 'a', 'i', 1, '+', 1, 'M', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 2, 'h', 'n', 2, 'h', 'm', 3, 'A', 'U', 'M', 4, ' ', '/', '/', ' ', 3, ' ', '*', ' ', 1, '-', 3, ' ', '/', ' ', 3, ' ', '/', ' ', 4, ' ', '/', '/', ' ', 4, ' ', '-', '/', ' ', 4, ' ', '+', '/', ' ', 4, ' ', 'X', '/', ' ', 6, ' ', '/', 'X', 'X', '/', ' ', 5, ' ', '/', 'X', '/', ' ', 2, ',', ' ', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 2, '.', '5', 3, '1', '.', '5', 3, '2', '.', '5', 3, '3', '.', '5', 3, '4', '.', '5', 3, '5', '.', '5', 3, '6', '.', '5', 3, '7', '.', '5', 3, '8', '.', '5', 3, '-', '.', '5', 1, '+', 1, '*', 1, '^', 1, '_', 1, '~', 1, ']', 2, '[', '[', 2, ']', ']', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 2, 't', 's', 3, 't', 's', 'h', 2, 'd', 'z', 3, 'd', 'z', 'h', 1, 'w', 2, 'z', 'h', 1, 'z', 1, '\'', 1, 'y', 1, 'r', 1, 'l', 2, 's', 'h', 3, 's', 's', 'h', 1, 's', 1, 'h', 1, 'a', 3, 'k', 's', 's', 1, 'r', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'R', 2, 'R', 'R', 1, 'L', 2, 'L', 'L', 1, 'e', 2, 'e', 'e', 1, 'o', 2, 'o', 'o', 1, 'M', 1, 'H', 1, 'i', 2, 'i', 'i', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 2, 't', 's', 3, 't', 's', 'h', 2, 'd', 'z', 3, 'd', 'z', 'h', 1, 'w', 2, 'z', 'h', 1, 'z', 1, '\'', 1, 'y', 1, 'r', 1, 'l', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 1, 'a', 3, 'k', 's', 's', 1, 'w', 1, 'y', 1, 'r', 1, 'X', 5, ' ', ':', 'X', ':', ' ', 5, ' ', '/', 'O', '/', ' ', 5, ' ', '/', 'o', '/', ' ', 5, ' ', '\\', 'o', '\\', ' ', 5, ' ', '(', 'O', ')', ' ', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 3, 'n', 'n', 'y', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 2, 't', 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 1, 'y', 1, 'r', 1, 'l', 1, 'w', 1, 's', 1, 'h', 2, 'l', 'l', 1, 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'e', 1, 'o', 2, 'a', 'u', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'u', 1, 'e', 2, 'a', 'i', 1, 'N', 1, '\'', 1, ':', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 3, ' ', '/', ' ', 4, ' ', '/', '/', ' ', 2, 'n', '*', 2, 'r', '*', 2, 'l', '*', 2, 'e', '*', 2, 's', 'h', 2, 's', 's', 1, 'R', 2, 'R', 'R', 1, 'L', 2, 'L', 'L', 1, 'R', 2, 'R', 'R', 1, 'L', 2, 'L', 'L', 1, 'A', 1, 'B', 1, 'G', 1, 'D', 1, 'E', 1, 'V', 1, 'Z', 2, 'T', '`', 1, 'I', 1, 'K', 1, 'L', 1, 'M', 1, 'N', 1, 'O', 1, 'P', 2, 'Z', 'h', 1, 'R', 1, 'S', 1, 'T', 1, 'U', 2, 'P', '`', 2, 'K', '`', 2, 'G', '\'', 1, 'Q', 2, 'S', 'h', 3, 'C', 'h', '`', 2, 'C', '`', 2, 'Z', '\'', 1, 'C', 2, 'C', 'h', 1, 'X', 1, 'J', 1, 'H', 1, 'E', 1, 'Y', 1, 'W', 2, 'X', 'h', 2, 'O', 'E', 1, 'a', 1, 'b', 1, 'g', 1, 'd', 1, 'e', 1, 'v', 1, 'z', 2, 't', '`', 1, 'i', 1, 'k', 1, 'l', 1, 'm', 1, 'n', 1, 'o', 1, 'p', 2, 'z', 'h', 1, 'r', 1, 's', 1, 't', 1, 'u', 2, 'p', '`', 2, 'k', '`', 2, 'g', '\'', 1, 'q', 2, 's', 'h', 3, 'c', 'h', '`', 2, 'c', '`', 2, 'z', '\'', 1, 'c', 2, 'c', 'h', 1, 'x', 1, 'j', 1, 'h', 1, 'e', 1, 'y', 1, 'w', 2, 'x', 'h', 2, 'o', 'e', 1, 'f', 4, ' ', '/', '/', ' ', 1, 'g', 2, 'g', 'g', 1, 'n', 1, 'd', 2, 'd', 'd', 1, 'r', 1, 'm', 1, 'b', 2, 'b', 'b', 1, 's', 2, 's', 's', 1, 'j', 2, 'j', 'j', 1, 'c', 1, 'k', 1, 't', 1, 'p', 1, 'h', 2, 'n', 'g', 2, 'n', 'n', 2, 'n', 'd', 2, 'n', 'b', 2, 'd', 'g', 2, 'r', 'n', 2, 'r', 'r', 2, 'r', 'h', 2, 'r', 'N', 2, 'm', 'b', 2, 'm', 'N', 2, 'b', 'g', 2, 'b', 'n', 2, 'b', 's', 3, 'b', 's', 'g', 3, 'b', 's', 't', 3, 'b', 's', 'b', 3, 'b', 's', 's', 3, 'b', 's', 'j', 2, 'b', 'j', 2, 'b', 'c', 2, 'b', 't', 2, 'b', 'p', 2, 'b', 'N', 3, 'b', 'b', 'N', 2, 's', 'g', 2, 's', 'n', 2, 's', 'd', 2, 's', 'r', 2, 's', 'm', 2, 's', 'b', 3, 's', 'b', 'g', 3, 's', 's', 's', 1, 's', 2, 's', 'j', 2, 's', 'c', 2, 's', 'k', 2, 's', 't', 2, 's', 'p', 2, 's', 'h', 1, 'Z', 1, 'g', 1, 'd', 1, 'm', 1, 'b', 1, 's', 1, 'Z', 1, 'j', 1, 'c', 1, 't', 1, 'p', 1, 'N', 1, 'j', 2, 'c', 'k', 2, 'c', 'h', 2, 'p', 'b', 2, 'p', 'N', 2, 'h', 'h', 1, 'Q', 1, 'a', 2, 'a', 'e', 2, 'y', 'a', 3, 'y', 'a', 'e', 2, 'e', 'o', 1, 'e', 3, 'y', 'e', 'o', 2, 'y', 'e', 1, 'o', 2, 'w', 'a', 3, 'w', 'a', 'e', 2, 'o', 'e', 2, 'y', 'o', 1, 'u', 3, 'w', 'e', 'o', 2, 'w', 'e', 2, 'w', 'i', 2, 'y', 'u', 2, 'e', 'u', 2, 'y', 'i', 1, 'i', 3, 'a', '-', 'o', 3, 'a', '-', 'u', 4, 'y', 'a', '-', 'o', 5, 'y', 'a', '-', 'y', 'o', 4, 'e', 'o', '-', 'o', 4, 'e', 'o', '-', 'u', 5, 'e', 'o', '-', 'e', 'u', 5, 'y', 'e', 'o', '-', 'o', 5, 'y', 'e', 'o', '-', 'u', 4, 'o', '-', 'e', 'o', 3, 'o', '-', 'e', 4, 'o', '-', 'y', 'e', 3, 'o', '-', 'o', 3, 'o', '-', 'u', 5, 'y', 'o', '-', 'y', 'a', 6, 'y', 'o', '-', 'y', 'a', 'e', 6, 'y', 'o', '-', 'y', 'e', 'o', 4, 'y', 'o', '-', 'o', 4, 'y', 'o', '-', 'i', 3, 'u', '-', 'a', 4, 'u', '-', 'a', 'e', 7, 'u', '-', 'e', 'o', '-', 'e', 'u', 4, 'u', '-', 'y', 'e', 3, 'u', '-', 'u', 4, 'y', 'u', '-', 'a', 5, 'y', 'u', '-', 'e', 'o', 4, 'y', 'u', '-', 'e', 6, 'y', 'u', '-', 'y', 'e', 'o', 5, 'y', 'u', '-', 'y', 'e', 4, 'y', 'u', '-', 'u', 4, 'y', 'u', '-', 'i', 4, 'e', 'u', '-', 'u', 5, 'e', 'u', '-', 'e', 'u', 4, 'y', 'i', '-', 'u', 3, 'i', '-', 'a', 4, 'i', '-', 'y', 'a', 3, 'i', '-', 'o', 3, 'i', '-', 'u', 4, 'i', '-', 'e', 'u', 3, 'i', '-', 'U', 1, 'U', 4, 'U', '-', 'e', 'o', 3, 'U', '-', 'u', 3, 'U', '-', 'i', 2, 'U', 'U', 1, 'g', 2, 'g', 'g', 2, 'g', 's', 1, 'n', 2, 'n', 'j', 2, 'n', 'h', 1, 'd', 1, 'l', 2, 'l', 'g', 2, 'l', 'm', 2, 'l', 'b', 2, 'l', 's', 2, 'l', 't', 2, 'l', 'p', 2, 'l', 'h', 1, 'm', 1, 'b', 2, 'b', 's', 1, 's', 2, 's', 's', 2, 'n', 'g', 1, 'j', 1, 'c', 1, 'k', 1, 't', 1, 'p', 1, 'h', 2, 'g', 'l', 3, 'g', 's', 'g', 2, 'n', 'g', 2, 'n', 'd', 2, 'n', 's', 2, 'n', 'Z', 2, 'n', 't', 2, 'd', 'g', 2, 't', 'l', 3, 'l', 'g', 's', 2, 'l', 'n', 2, 'l', 'd', 3, 'l', 't', 'h', 2, 'l', 'l', 3, 'l', 'm', 'g', 3, 'l', 'm', 's', 3, 'l', 'b', 's', 3, 'l', 'b', 'h', 3, 'r', 'N', 'p', 3, 'l', 's', 's', 2, 'l', 'Z', 2, 'l', 'k', 2, 'l', 'Q', 2, 'm', 'g', 2, 'm', 'l', 2, 'm', 'b', 2, 'm', 's', 3, 'm', 's', 's', 2, 'm', 'Z', 2, 'm', 'c', 2, 'm', 'h', 2, 'm', 'N', 2, 'b', 'l', 2, 'b', 'p', 2, 'p', 'h', 2, 'p', 'N', 2, 's', 'g', 2, 's', 'd', 2, 's', 'l', 2, 's', 'b', 1, 'Z', 1, 'g', 2, 's', 's', 2, 'k', 'h', 1, 'N', 2, 'N', 's', 2, 'N', 'Z', 2, 'p', 'b', 2, 'p', 'N', 2, 'h', 'n', 2, 'h', 'l', 2, 'h', 'm', 2, 'h', 'b', 1, 'Q', 2, 'h', 'a', 2, 'h', 'u', 2, 'h', 'i', 3, 'h', 'a', 'a', 3, 'h', 'e', 'e', 2, 'h', 'e', 2, 'h', 'o', 2, 'l', 'a', 2, 'l', 'u', 2, 'l', 'i', 3, 'l', 'a', 'a', 3, 'l', 'e', 'e', 2, 'l', 'e', 2, 'l', 'o', 3, 'l', 'w', 'a', 3, 'h', 'h', 'a', 3, 'h', 'h', 'u', 3, 'h', 'h', 'i', 4, 'h', 'h', 'a', 'a', 4, 'h', 'h', 'e', 'e', 3, 'h', 'h', 'e', 3, 'h', 'h', 'o', 4, 'h', 'h', 'w', 'a', 2, 'm', 'a', 2, 'm', 'u', 2, 'm', 'i', 3, 'm', 'a', 'a', 3, 'm', 'e', 'e', 2, 'm', 'e', 2, 'm', 'o', 3, 'm', 'w', 'a', 3, 's', 'z', 'a', 3, 's', 'z', 'u', 3, 's', 'z', 'i', 4, 's', 'z', 'a', 'a', 4, 's', 'z', 'e', 'e', 3, 's', 'z', 'e', 3, 's', 'z', 'o', 4, 's', 'z', 'w', 'a', 2, 'r', 'a', 2, 'r', 'u', 2, 'r', 'i', 3, 'r', 'a', 'a', 3, 'r', 'e', 'e', 2, 'r', 'e', 2, 'r', 'o', 3, 'r', 'w', 'a', 2, 's', 'a', 2, 's', 'u', 2, 's', 'i', 3, 's', 'a', 'a', 3, 's', 'e', 'e', 2, 's', 'e', 2, 's', 'o', 3, 's', 'w', 'a', 3, 's', 'h', 'a', 3, 's', 'h', 'u', 3, 's', 'h', 'i', 4, 's', 'h', 'a', 'a', 4, 's', 'h', 'e', 'e', 3, 's', 'h', 'e', 3, 's', 'h', 'o', 4, 's', 'h', 'w', 'a', 2, 'q', 'a', 2, 'q', 'u', 2, 'q', 'i', 3, 'q', 'a', 'a', 3, 'q', 'e', 'e', 2, 'q', 'e', 2, 'q', 'o', 3, 'q', 'w', 'a', 3, 'q', 'w', 'i', 4, 'q', 'w', 'a', 'a', 4, 'q', 'w', 'e', 'e', 3, 'q', 'w', 'e', 3, 'q', 'h', 'a', 3, 'q', 'h', 'u', 3, 'q', 'h', 'i', 4, 'q', 'h', 'a', 'a', 4, 'q', 'h', 'e', 'e', 3, 'q', 'h', 'e', 3, 'q', 'h', 'o', 4, 'q', 'h', 'w', 'a', 4, 'q', 'h', 'w', 'i', 5, 'q', 'h', 'w', 'a', 'a', 5, 'q', 'h', 'w', 'e', 'e', 4, 'q', 'h', 'w', 'e', 2, 'b', 'a', 2, 'b', 'u', 2, 'b', 'i', 3, 'b', 'a', 'a', 3, 'b', 'e', 'e', 2, 'b', 'e', 2, 'b', 'o', 3, 'b', 'w', 'a', 2, 'v', 'a', 2, 'v', 'u', 2, 'v', 'i', 3, 'v', 'a', 'a', 3, 'v', 'e', 'e', 2, 'v', 'e', 2, 'v', 'o', 3, 'v', 'w', 'a', 2, 't', 'a', 2, 't', 'u', 2, 't', 'i', 3, 't', 'a', 'a', 3, 't', 'e', 'e', 2, 't', 'e', 2, 't', 'o', 3, 't', 'w', 'a', 2, 'c', 'a', 2, 'c', 'u', 2, 'c', 'i', 3, 'c', 'a', 'a', 3, 'c', 'e', 'e', 2, 'c', 'e', 2, 'c', 'o', 3, 'c', 'w', 'a', 2, 'x', 'a', 2, 'x', 'u', 2, 'x', 'i', 3, 'x', 'a', 'a', 3, 'x', 'e', 'e', 2, 'x', 'e', 2, 'x', 'o', 3, 'x', 'w', 'a', 3, 'x', 'w', 'i', 4, 'x', 'w', 'a', 'a', 4, 'x', 'w', 'e', 'e', 3, 'x', 'w', 'e', 2, 'n', 'a', 2, 'n', 'u', 2, 'n', 'i', 3, 'n', 'a', 'a', 3, 'n', 'e', 'e', 2, 'n', 'e', 2, 'n', 'o', 3, 'n', 'w', 'a', 3, 'n', 'y', 'a', 3, 'n', 'y', 'u', 3, 'n', 'y', 'i', 4, 'n', 'y', 'a', 'a', 4, 'n', 'y', 'e', 'e', 3, 'n', 'y', 'e', 3, 'n', 'y', 'o', 4, 'n', 'y', 'w', 'a', 2, '\'', 'a', 2, '\'', 'u', 3, '\'', 'a', 'a', 3, '\'', 'e', 'e', 2, '\'', 'e', 2, '\'', 'o', 3, '\'', 'w', 'a', 2, 'k', 'a', 2, 'k', 'u', 2, 'k', 'i', 3, 'k', 'a', 'a', 3, 'k', 'e', 'e', 2, 'k', 'e', 2, 'k', 'o', 3, 'k', 'w', 'a', 3, 'k', 'w', 'i', 4, 'k', 'w', 'a', 'a', 4, 'k', 'w', 'e', 'e', 3, 'k', 'w', 'e', 3, 'k', 'x', 'a', 3, 'k', 'x', 'u', 3, 'k', 'x', 'i', 4, 'k', 'x', 'a', 'a', 4, 'k', 'x', 'e', 'e', 3, 'k', 'x', 'e', 3, 'k', 'x', 'o', 4, 'k', 'x', 'w', 'a', 4, 'k', 'x', 'w', 'i', 5, 'k', 'x', 'w', 'a', 'a', 5, 'k', 'x', 'w', 'e', 'e', 4, 'k', 'x', 'w', 'e', 2, 'w', 'a', 2, 'w', 'u', 2, 'w', 'i', 3, 'w', 'a', 'a', 3, 'w', 'e', 'e', 2, 'w', 'e', 2, 'w', 'o', 2, '`', 'a', 2, '`', 'u', 2, '`', 'i', 3, '`', 'a', 'a', 3, '`', 'e', 'e', 2, '`', 'e', 2, '`', 'o', 2, 'z', 'a', 2, 'z', 'u', 2, 'z', 'i', 3, 'z', 'a', 'a', 3, 'z', 'e', 'e', 2, 'z', 'e', 2, 'z', 'o', 3, 'z', 'w', 'a', 3, 'z', 'h', 'a', 3, 'z', 'h', 'u', 3, 'z', 'h', 'i', 4, 'z', 'h', 'a', 'a', 4, 'z', 'h', 'e', 'e', 3, 'z', 'h', 'e', 3, 'z', 'h', 'o', 4, 'z', 'h', 'w', 'a', 2, 'y', 'a', 2, 'y', 'u', 2, 'y', 'i', 3, 'y', 'a', 'a', 3, 'y', 'e', 'e', 2, 'y', 'e', 2, 'y', 'o', 2, 'd', 'a', 2, 'd', 'u', 2, 'd', 'i', 3, 'd', 'a', 'a', 3, 'd', 'e', 'e', 2, 'd', 'e', 2, 'd', 'o', 3, 'd', 'w', 'a', 3, 'd', 'd', 'a', 3, 'd', 'd', 'u', 3, 'd', 'd', 'i', 4, 'd', 'd', 'a', 'a', 4, 'd', 'd', 'e', 'e', 3, 'd', 'd', 'e', 3, 'd', 'd', 'o', 4, 'd', 'd', 'w', 'a', 2, 'j', 'a', 2, 'j', 'u', 2, 'j', 'i', 3, 'j', 'a', 'a', 3, 'j', 'e', 'e', 2, 'j', 'e', 2, 'j', 'o', 3, 'j', 'w', 'a', 2, 'g', 'a', 2, 'g', 'u', 2, 'g', 'i', 3, 'g', 'a', 'a', 3, 'g', 'e', 'e', 2, 'g', 'e', 2, 'g', 'o', 3, 'g', 'w', 'a', 3, 'g', 'w', 'i', 4, 'g', 'w', 'a', 'a', 4, 'g', 'w', 'e', 'e', 3, 'g', 'w', 'e', 3, 'g', 'g', 'a', 3, 'g', 'g', 'u', 3, 'g', 'g', 'i', 4, 'g', 'g', 'a', 'a', 4, 'g', 'g', 'e', 'e', 3, 'g', 'g', 'e', 3, 'g', 'g', 'o', 3, 't', 'h', 'a', 3, 't', 'h', 'u', 3, 't', 'h', 'i', 4, 't', 'h', 'a', 'a', 4, 't', 'h', 'e', 'e', 3, 't', 'h', 'e', 3, 't', 'h', 'o', 4, 't', 'h', 'w', 'a', 3, 'c', 'h', 'a', 3, 'c', 'h', 'u', 3, 'c', 'h', 'i', 4, 'c', 'h', 'a', 'a', 4, 'c', 'h', 'e', 'e', 3, 'c', 'h', 'e', 3, 'c', 'h', 'o', 4, 'c', 'h', 'w', 'a', 3, 'p', 'h', 'a', 3, 'p', 'h', 'u', 3, 'p', 'h', 'i', 4, 'p', 'h', 'a', 'a', 4, 'p', 'h', 'e', 'e', 3, 'p', 'h', 'e', 3, 'p', 'h', 'o', 4, 'p', 'h', 'w', 'a', 3, 't', 's', 'a', 3, 't', 's', 'u', 3, 't', 's', 'i', 4, 't', 's', 'a', 'a', 4, 't', 's', 'e', 'e', 3, 't', 's', 'e', 3, 't', 's', 'o', 4, 't', 's', 'w', 'a', 3, 't', 'z', 'a', 3, 't', 'z', 'u', 3, 't', 'z', 'i', 4, 't', 'z', 'a', 'a', 4, 't', 'z', 'e', 'e', 3, 't', 'z', 'e', 3, 't', 'z', 'o', 2, 'f', 'a', 2, 'f', 'u', 2, 'f', 'i', 3, 'f', 'a', 'a', 3, 'f', 'e', 'e', 2, 'f', 'e', 2, 'f', 'o', 3, 'f', 'w', 'a', 2, 'p', 'a', 2, 'p', 'u', 2, 'p', 'i', 3, 'p', 'a', 'a', 3, 'p', 'e', 'e', 2, 'p', 'e', 2, 'p', 'o', 3, 'p', 'w', 'a', 3, 'r', 'y', 'a', 3, 'm', 'y', 'a', 3, 'f', 'y', 'a', 1, ' ', 1, '.', 1, ',', 1, ';', 1, ':', 3, ':', ':', ' ', 1, '?', 2, '/', '/', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 3, '1', '0', '+', 3, '2', '0', '+', 3, '3', '0', '+', 3, '4', '0', '+', 3, '5', '0', '+', 3, '6', '0', '+', 3, '7', '0', '+', 3, '8', '0', '+', 3, '9', '0', '+', 4, '1', '0', '0', '+', 7, '1', '0', ',', '0', '0', '0', '+', 1, 'a', 1, 'e', 1, 'i', 1, 'o', 1, 'u', 1, 'v', 2, 'g', 'a', 2, 'k', 'a', 2, 'g', 'e', 2, 'g', 'i', 2, 'g', 'o', 2, 'g', 'u', 2, 'g', 'v', 2, 'h', 'a', 2, 'h', 'e', 2, 'h', 'i', 2, 'h', 'o', 2, 'h', 'u', 2, 'h', 'v', 2, 'l', 'a', 2, 'l', 'e', 2, 'l', 'i', 2, 'l', 'o', 2, 'l', 'u', 2, 'l', 'v', 2, 'm', 'a', 2, 'm', 'e', 2, 'm', 'i', 2, 'm', 'o', 2, 'm', 'u', 2, 'n', 'a', 3, 'h', 'n', 'a', 3, 'n', 'a', 'h', 2, 'n', 'e', 2, 'n', 'i', 2, 'n', 'o', 2, 'n', 'u', 2, 'n', 'v', 3, 'q', 'u', 'a', 3, 'q', 'u', 'e', 3, 'q', 'u', 'i', 3, 'q', 'u', 'o', 3, 'q', 'u', 'u', 3, 'q', 'u', 'v', 2, 's', 'a', 1, 's', 2, 's', 'e', 2, 's', 'i', 2, 's', 'o', 2, 's', 'u', 2, 's', 'v', 2, 'd', 'a', 2, 't', 'a', 2, 'd', 'e', 2, 't', 'e', 2, 'd', 'i', 2, 't', 'i', 2, 'd', 'o', 2, 'd', 'u', 2, 'd', 'v', 3, 'd', 'l', 'a', 3, 't', 'l', 'a', 3, 't', 'l', 'e', 3, 't', 'l', 'i', 3, 't', 'l', 'o', 3, 't', 'l', 'u', 3, 't', 'l', 'v', 3, 't', 's', 'a', 3, 't', 's', 'e', 3, 't', 's', 'i', 3, 't', 's', 'o', 3, 't', 's', 'u', 3, 't', 's', 'v', 2, 'w', 'a', 2, 'w', 'e', 2, 'w', 'i', 2, 'w', 'o', 2, 'w', 'u', 2, 'w', 'v', 2, 'y', 'a', 2, 'y', 'e', 2, 'y', 'i', 2, 'y', 'o', 2, 'y', 'u', 2, 'y', 'v', 1, 'e', 3, 'a', 'a', 'i', 1, 'i', 2, 'i', 'i', 1, 'o', 2, 'o', 'o', 2, 'o', 'o', 2, 'e', 'e', 1, 'i', 1, 'a', 2, 'a', 'a', 2, 'w', 'e', 2, 'w', 'e', 2, 'w', 'i', 2, 'w', 'i', 3, 'w', 'i', 'i', 3, 'w', 'i', 'i', 2, 'w', 'o', 2, 'w', 'o', 3, 'w', 'o', 'o', 3, 'w', 'o', 'o', 3, 'w', 'o', 'o', 2, 'w', 'a', 2, 'w', 'a', 3, 'w', 'a', 'a', 3, 'w', 'a', 'a', 3, 'w', 'a', 'a', 2, 'a', 'i', 1, 'w', 1, '\'', 1, 't', 1, 'k', 2, 's', 'h', 1, 's', 1, 'n', 1, 'w', 1, 'n', 1, 'w', 1, 'c', 1, '?', 1, 'l', 2, 'e', 'n', 2, 'i', 'n', 2, 'o', 'n', 2, 'a', 'n', 2, 'p', 'e', 4, 'p', 'a', 'a', 'i', 2, 'p', 'i', 3, 'p', 'i', 'i', 2, 'p', 'o', 3, 'p', 'o', 'o', 3, 'p', 'o', 'o', 3, 'h', 'e', 'e', 2, 'h', 'i', 2, 'p', 'a', 3, 'p', 'a', 'a', 3, 'p', 'w', 'e', 3, 'p', 'w', 'e', 3, 'p', 'w', 'i', 3, 'p', 'w', 'i', 4, 'p', 'w', 'i', 'i', 4, 'p', 'w', 'i', 'i', 3, 'p', 'w', 'o', 3, 'p', 'w', 'o', 4, 'p', 'w', 'o', 'o', 4, 'p', 'w', 'o', 'o', 3, 'p', 'w', 'a', 3, 'p', 'w', 'a', 4, 'p', 'w', 'a', 'a', 4, 'p', 'w', 'a', 'a', 4, 'p', 'w', 'a', 'a', 1, 'p', 1, 'p', 1, 'h', 2, 't', 'e', 4, 't', 'a', 'a', 'i', 2, 't', 'i', 3, 't', 'i', 'i', 2, 't', 'o', 3, 't', 'o', 'o', 3, 't', 'o', 'o', 3, 'd', 'e', 'e', 2, 'd', 'i', 2, 't', 'a', 3, 't', 'a', 'a', 3, 't', 'w', 'e', 3, 't', 'w', 'e', 3, 't', 'w', 'i', 3, 't', 'w', 'i', 4, 't', 'w', 'i', 'i', 4, 't', 'w', 'i', 'i', 3, 't', 'w', 'o', 3, 't', 'w', 'o', 4, 't', 'w', 'o', 'o', 4, 't', 'w', 'o', 'o', 3, 't', 'w', 'a', 3, 't', 'w', 'a', 4, 't', 'w', 'a', 'a', 4, 't', 'w', 'a', 'a', 4, 't', 'w', 'a', 'a', 1, 't', 3, 't', 't', 'e', 3, 't', 't', 'i', 3, 't', 't', 'o', 3, 't', 't', 'a', 2, 'k', 'e', 4, 'k', 'a', 'a', 'i', 2, 'k', 'i', 3, 'k', 'i', 'i', 2, 'k', 'o', 3, 'k', 'o', 'o', 3, 'k', 'o', 'o', 2, 'k', 'a', 3, 'k', 'a', 'a', 3, 'k', 'w', 'e', 3, 'k', 'w', 'e', 3, 'k', 'w', 'i', 3, 'k', 'w', 'i', 4, 'k', 'w', 'i', 'i', 4, 'k', 'w', 'i', 'i', 3, 'k', 'w', 'o', 3, 'k', 'w', 'o', 4, 'k', 'w', 'o', 'o', 4, 'k', 'w', 'o', 'o', 3, 'k', 'w', 'a', 3, 'k', 'w', 'a', 4, 'k', 'w', 'a', 'a', 4, 'k', 'w', 'a', 'a', 4, 'k', 'w', 'a', 'a', 1, 'k', 2, 'k', 'w', 3, 'k', 'e', 'h', 3, 'k', 'i', 'h', 3, 'k', 'o', 'h', 3, 'k', 'a', 'h', 2, 'c', 'e', 4, 'c', 'a', 'a', 'i', 2, 'c', 'i', 3, 'c', 'i', 'i', 2, 'c', 'o', 3, 'c', 'o', 'o', 3, 'c', 'o', 'o', 2, 'c', 'a', 3, 'c', 'a', 'a', 3, 'c', 'w', 'e', 3, 'c', 'w', 'e', 3, 'c', 'w', 'i', 3, 'c', 'w', 'i', 4, 'c', 'w', 'i', 'i', 4, 'c', 'w', 'i', 'i', 3, 'c', 'w', 'o', 3, 'c', 'w', 'o', 4, 'c', 'w', 'o', 'o', 4, 'c', 'w', 'o', 'o', 3, 'c', 'w', 'a', 3, 'c', 'w', 'a', 4, 'c', 'w', 'a', 'a', 4, 'c', 'w', 'a', 'a', 4, 'c', 'w', 'a', 'a', 1, 'c', 2, 't', 'h', 2, 'm', 'e', 4, 'm', 'a', 'a', 'i', 2, 'm', 'i', 3, 'm', 'i', 'i', 2, 'm', 'o', 3, 'm', 'o', 'o', 3, 'm', 'o', 'o', 2, 'm', 'a', 3, 'm', 'a', 'a', 3, 'm', 'w', 'e', 3, 'm', 'w', 'e', 3, 'm', 'w', 'i', 3, 'm', 'w', 'i', 4, 'm', 'w', 'i', 'i', 4, 'm', 'w', 'i', 'i', 3, 'm', 'w', 'o', 3, 'm', 'w', 'o', 4, 'm', 'w', 'o', 'o', 4, 'm', 'w', 'o', 'o', 3, 'm', 'w', 'a', 3, 'm', 'w', 'a', 4, 'm', 'w', 'a', 'a', 4, 'm', 'w', 'a', 'a', 4, 'm', 'w', 'a', 'a', 1, 'm', 1, 'm', 2, 'm', 'h', 1, 'm', 1, 'm', 2, 'n', 'e', 4, 'n', 'a', 'a', 'i', 2, 'n', 'i', 3, 'n', 'i', 'i', 2, 'n', 'o', 3, 'n', 'o', 'o', 3, 'n', 'o', 'o', 2, 'n', 'a', 3, 'n', 'a', 'a', 3, 'n', 'w', 'e', 3, 'n', 'w', 'e', 3, 'n', 'w', 'a', 3, 'n', 'w', 'a', 4, 'n', 'w', 'a', 'a', 4, 'n', 'w', 'a', 'a', 4, 'n', 'w', 'a', 'a', 1, 'n', 2, 'n', 'g', 2, 'n', 'h', 2, 'l', 'e', 4, 'l', 'a', 'a', 'i', 2, 'l', 'i', 3, 'l', 'i', 'i', 2, 'l', 'o', 3, 'l', 'o', 'o', 3, 'l', 'o', 'o', 2, 'l', 'a', 3, 'l', 'a', 'a', 3, 'l', 'w', 'e', 3, 'l', 'w', 'e', 3, 'l', 'w', 'i', 3, 'l', 'w', 'i', 4, 'l', 'w', 'i', 'i', 4, 'l', 'w', 'i', 'i', 3, 'l', 'w', 'o', 3, 'l', 'w', 'o', 4, 'l', 'w', 'o', 'o', 4, 'l', 'w', 'o', 'o', 3, 'l', 'w', 'a', 3, 'l', 'w', 'a', 4, 'l', 'w', 'a', 'a', 4, 'l', 'w', 'a', 'a', 1, 'l', 1, 'l', 1, 'l', 2, 's', 'e', 4, 's', 'a', 'a', 'i', 2, 's', 'i', 3, 's', 'i', 'i', 2, 's', 'o', 3, 's', 'o', 'o', 3, 's', 'o', 'o', 2, 's', 'a', 3, 's', 'a', 'a', 3, 's', 'w', 'e', 3, 's', 'w', 'e', 3, 's', 'w', 'i', 3, 's', 'w', 'i', 4, 's', 'w', 'i', 'i', 4, 's', 'w', 'i', 'i', 3, 's', 'w', 'o', 3, 's', 'w', 'o', 4, 's', 'w', 'o', 'o', 4, 's', 'w', 'o', 'o', 3, 's', 'w', 'a', 3, 's', 'w', 'a', 4, 's', 'w', 'a', 'a', 4, 's', 'w', 'a', 'a', 4, 's', 'w', 'a', 'a', 1, 's', 1, 's', 2, 's', 'w', 1, 's', 2, 's', 'k', 3, 's', 'k', 'w', 2, 's', 'W', 4, 's', 'p', 'w', 'a', 4, 's', 't', 'w', 'a', 4, 's', 'k', 'w', 'a', 4, 's', 'c', 'w', 'a', 3, 's', 'h', 'e', 3, 's', 'h', 'i', 4, 's', 'h', 'i', 'i', 3, 's', 'h', 'o', 4, 's', 'h', 'o', 'o', 3, 's', 'h', 'a', 4, 's', 'h', 'a', 'a', 4, 's', 'h', 'w', 'e', 4, 's', 'h', 'w', 'e', 4, 's', 'h', 'w', 'i', 4, 's', 'h', 'w', 'i', 5, 's', 'h', 'w', 'i', 'i', 5, 's', 'h', 'w', 'i', 'i', 4, 's', 'h', 'w', 'o', 4, 's', 'h', 'w', 'o', 5, 's', 'h', 'w', 'o', 'o', 5, 's', 'h', 'w', 'o', 'o', 4, 's', 'h', 'w', 'a', 4, 's', 'h', 'w', 'a', 5, 's', 'h', 'w', 'a', 'a', 5, 's', 'h', 'w', 'a', 'a', 2, 's', 'h', 2, 'y', 'e', 4, 'y', 'a', 'a', 'i', 2, 'y', 'i', 3, 'y', 'i', 'i', 2, 'y', 'o', 3, 'y', 'o', 'o', 3, 'y', 'o', 'o', 2, 'y', 'a', 3, 'y', 'a', 'a', 3, 'y', 'w', 'e', 3, 'y', 'w', 'e', 3, 'y', 'w', 'i', 3, 'y', 'w', 'i', 4, 'y', 'w', 'i', 'i', 4, 'y', 'w', 'i', 'i', 3, 'y', 'w', 'o', 3, 'y', 'w', 'o', 4, 'y', 'w', 'o', 'o', 4, 'y', 'w', 'o', 'o', 3, 'y', 'w', 'a', 3, 'y', 'w', 'a', 4, 'y', 'w', 'a', 'a', 4, 'y', 'w', 'a', 'a', 4, 'y', 'w', 'a', 'a', 1, 'y', 1, 'y', 1, 'y', 2, 'y', 'i', 2, 'r', 'e', 2, 'r', 'e', 2, 'l', 'e', 4, 'r', 'a', 'a', 'i', 2, 'r', 'i', 3, 'r', 'i', 'i', 2, 'r', 'o', 3, 'r', 'o', 'o', 2, 'l', 'o', 2, 'r', 'a', 3, 'r', 'a', 'a', 2, 'l', 'a', 4, 'r', 'w', 'a', 'a', 4, 'r', 'w', 'a', 'a', 1, 'r', 1, 'r', 1, 'r', 2, 'f', 'e', 4, 'f', 'a', 'a', 'i', 2, 'f', 'i', 3, 'f', 'i', 'i', 2, 'f', 'o', 3, 'f', 'o', 'o', 2, 'f', 'a', 3, 'f', 'a', 'a', 4, 'f', 'w', 'a', 'a', 4, 'f', 'w', 'a', 'a', 1, 'f', 3, 't', 'h', 'e', 3, 't', 'h', 'e', 3, 't', 'h', 'i', 3, 't', 'h', 'i', 4, 't', 'h', 'i', 'i', 4, 't', 'h', 'i', 'i', 3, 't', 'h', 'o', 4, 't', 'h', 'o', 'o', 3, 't', 'h', 'a', 4, 't', 'h', 'a', 'a', 5, 't', 'h', 'w', 'a', 'a', 5, 't', 'h', 'w', 'a', 'a', 2, 't', 'h', 4, 't', 't', 'h', 'e', 4, 't', 't', 'h', 'i', 4, 't', 't', 'h', 'o', 4, 't', 't', 'h', 'a', 3, 't', 't', 'h', 3, 't', 'y', 'e', 3, 't', 'y', 'i', 3, 't', 'y', 'o', 3, 't', 'y', 'a', 2, 'h', 'e', 2, 'h', 'i', 3, 'h', 'i', 'i', 2, 'h', 'o', 3, 'h', 'o', 'o', 2, 'h', 'a', 3, 'h', 'a', 'a', 1, 'h', 1, 'h', 2, 'h', 'k', 4, 'q', 'a', 'a', 'i', 2, 'q', 'i', 3, 'q', 'i', 'i', 2, 'q', 'o', 3, 'q', 'o', 'o', 2, 'q', 'a', 3, 'q', 'a', 'a', 1, 'q', 4, 't', 'l', 'h', 'e', 4, 't', 'l', 'h', 'i', 4, 't', 'l', 'h', 'o', 4, 't', 'l', 'h', 'a', 2, 'r', 'e', 2, 'r', 'i', 2, 'r', 'o', 2, 'r', 'a', 5, 'n', 'g', 'a', 'a', 'i', 3, 'n', 'g', 'i', 4, 'n', 'g', 'i', 'i', 3, 'n', 'g', 'o', 4, 'n', 'g', 'o', 'o', 3, 'n', 'g', 'a', 4, 'n', 'g', 'a', 'a', 2, 'n', 'g', 3, 'n', 'n', 'g', 3, 's', 'h', 'e', 3, 's', 'h', 'i', 3, 's', 'h', 'o', 3, 's', 'h', 'a', 3, 't', 'h', 'e', 3, 't', 'h', 'i', 3, 't', 'h', 'o', 3, 't', 'h', 'a', 2, 't', 'h', 3, 'l', 'h', 'i', 4, 'l', 'h', 'i', 'i', 3, 'l', 'h', 'o', 4, 'l', 'h', 'o', 'o', 3, 'l', 'h', 'a', 4, 'l', 'h', 'a', 'a', 2, 'l', 'h', 3, 't', 'h', 'e', 3, 't', 'h', 'i', 4, 't', 'h', 'i', 'i', 3, 't', 'h', 'o', 4, 't', 'h', 'o', 'o', 3, 't', 'h', 'a', 4, 't', 'h', 'a', 'a', 2, 't', 'h', 1, 'b', 1, 'e', 1, 'i', 1, 'o', 1, 'a', 2, 'w', 'e', 2, 'w', 'i', 2, 'w', 'o', 2, 'w', 'a', 2, 'n', 'e', 2, 'n', 'i', 2, 'n', 'o', 2, 'n', 'a', 2, 'k', 'e', 2, 'k', 'i', 2, 'k', 'o', 2, 'k', 'a', 2, 'h', 'e', 2, 'h', 'i', 2, 'h', 'o', 2, 'h', 'a', 3, 'g', 'h', 'u', 3, 'g', 'h', 'o', 3, 'g', 'h', 'e', 4, 'g', 'h', 'e', 'e', 3, 'g', 'h', 'i', 3, 'g', 'h', 'a', 2, 'r', 'u', 2, 'r', 'o', 2, 'r', 'e', 3, 'r', 'e', 'e', 2, 'r', 'i', 2, 'r', 'a', 2, 'w', 'u', 2, 'w', 'o', 2, 'w', 'e', 3, 'w', 'e', 'e', 2, 'w', 'i', 2, 'w', 'a', 3, 'h', 'w', 'u', 3, 'h', 'w', 'o', 3, 'h', 'w', 'e', 4, 'h', 'w', 'e', 'e', 3, 'h', 'w', 'i', 3, 'h', 'w', 'a', 3, 't', 'h', 'u', 3, 't', 'h', 'o', 3, 't', 'h', 'e', 4, 't', 'h', 'e', 'e', 3, 't', 'h', 'i', 3, 't', 'h', 'a', 3, 't', 't', 'u', 3, 't', 't', 'o', 3, 't', 't', 'e', 4, 't', 't', 'e', 'e', 3, 't', 't', 'i', 3, 't', 't', 'a', 2, 'p', 'u', 2, 'p', 'o', 2, 'p', 'e', 3, 'p', 'e', 'e', 2, 'p', 'i', 2, 'p', 'a', 1, 'p', 2, 'g', 'u', 2, 'g', 'o', 2, 'g', 'e', 3, 'g', 'e', 'e', 2, 'g', 'i', 2, 'g', 'a', 3, 'k', 'h', 'u', 3, 'k', 'h', 'o', 3, 'k', 'h', 'e', 4, 'k', 'h', 'e', 'e', 3, 'k', 'h', 'i', 3, 'k', 'h', 'a', 3, 'k', 'k', 'u', 3, 'k', 'k', 'o', 3, 'k', 'k', 'e', 4, 'k', 'k', 'e', 'e', 3, 'k', 'k', 'i', 3, 'k', 'k', 'a', 2, 'k', 'k', 2, 'n', 'u', 2, 'n', 'o', 2, 'n', 'e', 3, 'n', 'e', 'e', 2, 'n', 'i', 2, 'n', 'a', 2, 'm', 'u', 2, 'm', 'o', 2, 'm', 'e', 3, 'm', 'e', 'e', 2, 'm', 'i', 2, 'm', 'a', 2, 'y', 'u', 2, 'y', 'o', 2, 'y', 'e', 3, 'y', 'e', 'e', 2, 'y', 'i', 2, 'y', 'a', 2, 'j', 'u', 2, 'j', 'u', 2, 'j', 'o', 2, 'j', 'e', 3, 'j', 'e', 'e', 2, 'j', 'i', 2, 'j', 'i', 2, 'j', 'a', 3, 'j', 'j', 'u', 3, 'j', 'j', 'o', 3, 'j', 'j', 'e', 4, 'j', 'j', 'e', 'e', 3, 'j', 'j', 'i', 3, 'j', 'j', 'a', 2, 'l', 'u', 2, 'l', 'o', 2, 'l', 'e', 3, 'l', 'e', 'e', 2, 'l', 'i', 2, 'l', 'a', 3, 'd', 'l', 'u', 3, 'd', 'l', 'o', 3, 'd', 'l', 'e', 4, 'd', 'l', 'e', 'e', 3, 'd', 'l', 'i', 3, 'd', 'l', 'a', 3, 'l', 'h', 'u', 3, 'l', 'h', 'o', 3, 'l', 'h', 'e', 4, 'l', 'h', 'e', 'e', 3, 'l', 'h', 'i', 3, 'l', 'h', 'a', 4, 't', 'l', 'h', 'u', 4, 't', 'l', 'h', 'o', 4, 't', 'l', 'h', 'e', 5, 't', 'l', 'h', 'e', 'e', 4, 't', 'l', 'h', 'i', 4, 't', 'l', 'h', 'a', 3, 't', 'l', 'u', 3, 't', 'l', 'o', 3, 't', 'l', 'e', 4, 't', 'l', 'e', 'e', 3, 't', 'l', 'i', 3, 't', 'l', 'a', 2, 'z', 'u', 2, 'z', 'o', 2, 'z', 'e', 3, 'z', 'e', 'e', 2, 'z', 'i', 2, 'z', 'a', 1, 'z', 1, 'z', 3, 'd', 'z', 'u', 3, 'd', 'z', 'o', 3, 'd', 'z', 'e', 4, 'd', 'z', 'e', 'e', 3, 'd', 'z', 'i', 3, 'd', 'z', 'a', 2, 's', 'u', 2, 's', 'o', 2, 's', 'e', 3, 's', 'e', 'e', 2, 's', 'i', 2, 's', 'a', 3, 's', 'h', 'u', 3, 's', 'h', 'o', 3, 's', 'h', 'e', 4, 's', 'h', 'e', 'e', 3, 's', 'h', 'i', 3, 's', 'h', 'a', 2, 's', 'h', 3, 't', 's', 'u', 3, 't', 's', 'o', 3, 't', 's', 'e', 4, 't', 's', 'e', 'e', 3, 't', 's', 'i', 3, 't', 's', 'a', 3, 'c', 'h', 'u', 3, 'c', 'h', 'o', 3, 'c', 'h', 'e', 4, 'c', 'h', 'e', 'e', 3, 'c', 'h', 'i', 3, 'c', 'h', 'a', 4, 't', 't', 's', 'u', 4, 't', 't', 's', 'o', 4, 't', 't', 's', 'e', 5, 't', 't', 's', 'e', 'e', 4, 't', 't', 's', 'i', 4, 't', 't', 's', 'a', 1, 'X', 1, '.', 3, 'q', 'a', 'i', 4, 'n', 'g', 'a', 'i', 4, 'n', 'n', 'g', 'i', 5, 'n', 'n', 'g', 'i', 'i', 4, 'n', 'n', 'g', 'o', 5, 'n', 'n', 'g', 'o', 'o', 4, 'n', 'n', 'g', 'a', 5, 'n', 'n', 'g', 'a', 'a', 1, ' ', 1, 'b', 1, 'l', 1, 'f', 1, 's', 1, 'n', 1, 'h', 1, 'd', 1, 't', 1, 'c', 1, 'q', 1, 'm', 1, 'g', 2, 'n', 'g', 1, 'z', 1, 'r', 1, 'a', 1, 'o', 1, 'u', 1, 'e', 1, 'i', 2, 'c', 'h', 2, 't', 'h', 2, 'p', 'h', 1, 'p', 1, 'x', 1, 'p', 1, '<', 1, '>', 1, 'f', 1, 'v', 1, 'u', 2, 'y', 'r', 1, 'y', 1, 'w', 2, 't', 'h', 2, 't', 'h', 1, 'a', 1, 'o', 2, 'a', 'c', 2, 'a', 'e', 1, 'o', 1, 'o', 1, 'o', 2, 'o', 'e', 2, 'o', 'n', 1, 'r', 1, 'k', 1, 'c', 1, 'k', 1, 'g', 2, 'n', 'g', 1, 'g', 1, 'g', 1, 'w', 1, 'h', 1, 'h', 1, 'h', 1, 'h', 1, 'n', 1, 'n', 1, 'n', 1, 'i', 1, 'e', 1, 'j', 1, 'g', 2, 'a', 'e', 1, 'a', 2, 'e', 'o', 1, 'p', 1, 'z', 1, 's', 1, 's', 1, 's', 1, 'c', 1, 'z', 1, 't', 1, 't', 1, 'd', 1, 'b', 1, 'b', 1, 'p', 1, 'p', 1, 'e', 1, 'm', 1, 'm', 1, 'm', 1, 'l', 1, 'l', 2, 'n', 'g', 2, 'n', 'g', 1, 'd', 1, 'o', 3, 'e', 'a', 'r', 3, 'i', 'o', 'r', 2, 'q', 'u', 2, 'q', 'u', 2, 'q', 'u', 1, 's', 2, 'y', 'r', 2, 'y', 'r', 2, 'y', 'r', 1, 'q', 1, 'x', 1, '.', 1, ':', 1, '+', 2, '1', '7', 2, '1', '8', 2, '1', '9', 1, 'k', 2, 'k', 'h', 1, 'g', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'c', 'h', 1, 'j', 2, 'j', 'h', 2, 'n', 'y', 1, 't', 3, 't', 't', 'h', 1, 'd', 3, 'd', 'd', 'h', 2, 'n', 'n', 1, 't', 2, 't', 'h', 1, 'd', 2, 'd', 'h', 1, 'n', 1, 'p', 2, 'p', 'h', 1, 'b', 2, 'b', 'h', 1, 'm', 1, 'y', 1, 'r', 1, 'l', 1, 'v', 2, 's', 'h', 2, 's', 's', 1, 's', 1, 'h', 1, 'l', 1, 'q', 1, 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'u', 2, 'u', 'k', 2, 'u', 'u', 3, 'u', 'u', 'v', 2, 'r', 'y', 3, 'r', 'y', 'y', 2, 'l', 'y', 3, 'l', 'y', 'y', 1, 'e', 2, 'a', 'i', 2, 'o', 'o', 2, 'o', 'o', 2, 'a', 'u', 1, 'a', 2, 'a', 'a', 2, 'a', 'a', 1, 'i', 2, 'i', 'i', 1, 'y', 2, 'y', 'y', 1, 'u', 2, 'u', 'u', 2, 'u', 'a', 2, 'o', 'e', 2, 'y', 'a', 2, 'i', 'e', 1, 'e', 2, 'a', 'e', 2, 'a', 'i', 2, 'o', 'o', 2, 'a', 'u', 1, 'M', 1, 'H', 2, 'a', '`', 1, 'r', 1, '!', 1, '.', 4, ' ', '/', '/', ' ', 1, ':', 1, '+', 2, '+', '+', 3, ' ', '*', ' ', 5, ' ', '/', '/', '/', ' ', 2, 'K', 'R', 1, '\'', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 3, ' ', '@', ' ', 5, ' ', '.', '.', '.', ' ', 2, ',', ' ', 2, '.', ' ', 2, ':', ' ', 4, ' ', '/', '/', ' ', 1, '-', 2, ',', ' ', 2, '.', ' ', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, 'a', 1, 'e', 1, 'i', 1, 'o', 1, 'u', 1, 'O', 1, 'U', 2, 'e', 'e', 1, 'n', 2, 'n', 'g', 1, 'b', 1, 'p', 1, 'q', 1, 'g', 1, 'm', 1, 'l', 1, 's', 2, 's', 'h', 1, 't', 1, 'd', 2, 'c', 'h', 1, 'j', 1, 'y', 1, 'r', 1, 'w', 1, 'f', 1, 'k', 3, 'k', 'h', 'a', 2, 't', 's', 1, 'z', 1, 'h', 2, 'z', 'r', 2, 'l', 'h', 2, 'z', 'h', 2, 'c', 'h', 1, '-', 1, 'e', 1, 'i', 1, 'o', 1, 'u', 1, 'O', 1, 'U', 2, 'n', 'g', 1, 'b', 1, 'p', 1, 'q', 1, 'g', 1, 'm', 1, 't', 1, 'd', 2, 'c', 'h', 1, 'j', 2, 't', 's', 1, 'y', 1, 'w', 1, 'k', 1, 'g', 1, 'h', 2, 'j', 'y', 2, 'n', 'y', 2, 'd', 'z', 1, 'e', 1, 'i', 2, 'i', 'y', 1, 'U', 1, 'u', 2, 'n', 'g', 1, 'k', 1, 'g', 1, 'h', 1, 'p', 2, 's', 'h', 1, 't', 1, 'd', 1, 'j', 1, 'f', 1, 'g', 1, 'h', 2, 't', 's', 1, 'z', 1, 'r', 2, 'c', 'h', 2, 'z', 'h', 1, 'i', 1, 'k', 1, 'r', 1, 'f', 2, 'z', 'h', 1, 'H', 1, 'X', 1, 'W', 1, 'M', 3, ' ', '3', ' ', 5, ' ', '3', '3', '3', ' ', 1, 'a', 1, 'i', 1, 'k', 2, 'n', 'g', 1, 'c', 2, 't', 't', 3, 't', 't', 'h', 2, 'd', 'd', 2, 'n', 'n', 1, 't', 1, 'd', 1, 'p', 2, 'p', 'h', 2, 's', 's', 2, 'z', 'h', 1, 'z', 1, 'a', 1, 't', 2, 'z', 'h', 2, 'g', 'h', 2, 'n', 'g', 1, 'c', 2, 'j', 'h', 3, 't', 't', 'a', 3, 'd', 'd', 'h', 1, 't', 2, 'd', 'h', 2, 's', 's', 2, 'c', 'y', 2, 'z', 'h', 1, 'z', 1, 'u', 1, 'y', 2, 'b', 'h', 1, '\'', 1, 'A', 2, 'A', 'E', 2, 'a', 'e', 1, 'B', 1, 'C', 1, 'D', 1, 'D', 1, 'E', 1, 'e', 1, 'i', 1, 'J', 1, 'K', 1, 'L', 1, 'M', 1, 'N', 1, 'O', 1, 'O', 1, 'O', 2, 'O', 'e', 2, 'O', 'u', 1, 'P', 1, 'R', 1, 'R', 1, 'T', 1, 'U', 1, 'u', 1, 'u', 1, 'm', 1, 'V', 1, 'W', 1, 'Z', 1, 'A', 2, 'A', 'E', 1, 'B', 1, 'B', 1, 'D', 1, 'E', 1, 'E', 1, 'G', 1, 'H', 1, 'I', 1, 'J', 1, 'K', 1, 'L', 1, 'M', 1, 'N', 1, 'N', 1, 'O', 2, 'O', 'u', 1, 'P', 1, 'R', 1, 'T', 1, 'U', 1, 'W', 1, 'a', 1, 'a', 1, 'a', 2, 'a', 'e', 1, 'b', 1, 'd', 1, 'e', 1, 'e', 1, 'e', 1, 'g', 1, 'i', 1, 'k', 1, 'm', 1, 'o', 1, 'p', 1, 't', 1, 'u', 1, 'u', 1, 'm', 1, 'v', 1, 'b', 1, 'g', 1, 'd', 1, 'f', 1, 'i', 1, 'r', 1, 'u', 1, 'v', 1, 'b', 1, 'g', 1, 'r', 1, 'f', 1, 'b', 1, 'd', 1, 'f', 1, 'm', 1, 'n', 1, 'p', 1, 'r', 1, 'r', 1, 's', 1, 't', 1, 'z', 1, 'g', 1, 'p', 1, 'b', 1, 'd', 1, 'f', 1, 'g', 1, 'k', 1, 'l', 1, 'm', 1, 'n', 1, 'p', 1, 'r', 1, 's', 1, 'v', 1, 'x', 1, 'z', 1, 'A', 1, 'a', 1, 'B', 1, 'b', 1, 'B', 1, 'b', 1, 'B', 1, 'b', 1, 'C', 1, 'c', 1, 'D', 1, 'd', 1, 'D', 1, 'd', 1, 'D', 1, 'd', 1, 'D', 1, 'd', 1, 'D', 1, 'd', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'F', 1, 'f', 1, 'G', 1, 'g', 1, 'H', 1, 'h', 1, 'H', 1, 'h', 1, 'H', 1, 'h', 1, 'H', 1, 'h', 1, 'H', 1, 'h', 1, 'I', 1, 'i', 1, 'I', 1, 'i', 1, 'K', 1, 'k', 1, 'K', 1, 'k', 1, 'K', 1, 'k', 1, 'L', 1, 'l', 1, 'L', 1, 'l', 1, 'L', 1, 'l', 1, 'L', 1, 'l', 1, 'M', 1, 'm', 1, 'M', 1, 'm', 1, 'M', 1, 'm', 1, 'N', 1, 'n', 1, 'N', 1, 'n', 1, 'N', 1, 'n', 1, 'N', 1, 'n', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'P', 1, 'p', 1, 'P', 1, 'p', 1, 'R', 1, 'r', 1, 'R', 1, 'r', 1, 'R', 1, 'r', 1, 'R', 1, 'r', 1, 'S', 1, 's', 1, 'S', 1, 's', 1, 'S', 1, 's', 1, 'S', 1, 's', 1, 'S', 1, 's', 1, 'T', 1, 't', 1, 'T', 1, 't', 1, 'T', 1, 't', 1, 'T', 1, 't', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'V', 1, 'v', 1, 'V', 1, 'v', 1, 'W', 1, 'w', 1, 'W', 1, 'w', 1, 'W', 1, 'w', 1, 'W', 1, 'w', 1, 'W', 1, 'w', 1, 'X', 1, 'x', 1, 'X', 1, 'x', 1, 'Y', 1, 'y', 1, 'Z', 1, 'z', 1, 'Z', 1, 'z', 1, 'Z', 1, 'z', 1, 'h', 1, 't', 1, 'w', 1, 'y', 1, 'a', 1, 'S', 2, 'S', 's', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'A', 1, 'a', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'E', 1, 'e', 1, 'I', 1, 'i', 1, 'I', 1, 'i', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'O', 1, 'o', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'U', 1, 'u', 1, 'Y', 1, 'y', 1, 'Y', 1, 'y', 1, 'Y', 1, 'y', 1, 'Y', 1, 'y', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'i', 1, 'i', 1, 'i', 1, 'i', 1, 'i', 1, 'i', 1, 'i', 1, 'i', 1, 'I', 1, 'I', 1, 'I', 1, 'I', 1, 'I', 1, 'I', 1, 'I', 1, 'I', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'u', 1, 'u', 1, 'u', 1, 'u', 1, 'u', 1, 'u', 1, 'u', 1, 'u', 1, 'U', 1, 'U', 1, 'U', 1, 'U', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'a', 1, 'a', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'i', 1, 'i', 1, 'o', 1, 'o', 1, 'u', 1, 'u', 1, 'o', 1, 'o', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, 'A', 1, '\'', 1, 'i', 1, '\'', 1, '~', 2, '\"', '~', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'e', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 1, 'E', 2, '\'', '`', 2, '\'', '\'', 2, '\'', '~', 1, 'i', 1, 'i', 1, 'i', 1, 'i', 1, 'i', 1, 'i', 1, 'I', 1, 'I', 1, 'I', 1, 'I', 2, '`', '\'', 2, '`', '\'', 2, '`', '~', 1, 'u', 1, 'u', 1, 'u', 1, 'u', 1, 'R', 1, 'R', 1, 'u', 1, 'u', 1, 'U', 1, 'U', 1, 'U', 1, 'U', 1, 'R', 2, '\"', '`', 2, '\"', '\'', 1, '`', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'o', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, 'O', 1, '\'', 1, '`', 1, ' ', 1, ' ', 1, ' ', 1, ' ', 1, ' ', 1, ' ', 1, ' ', 1, ' ', 1, ' ', 1, ' ', 1, ' ', 1, ' ', 1, '-', 1, '-', 1, '-', 1, '-', 2, '-', '-', 2, '-', '-', 2, '|', '|', 1, '_', 1, '\'', 1, '\'', 1, ',', 1, '\'', 1, '\"', 1, '\"', 2, ',', ',', 1, '\"', 1, '+', 2, '+', '+', 1, '*', 2, '*', '>', 1, '.', 2, '.', '.', 3, '.', '.', '.', 1, '.', 1, ' ', 2, ' ', ' ', 1, ' ', 2, '%', '0', 3, '%', '0', '0', 1, '\'', 2, '\'', '\'', 3, '\'', '\'', '\'', 1, '`', 2, '`', '`', 3, '`', '`', '`', 1, '^', 1, '<', 1, '>', 1, '*', 2, '!', '!', 2, '!', '?', 1, '-', 1, '_', 1, '-', 1, '^', 3, '*', '*', '*', 2, '-', '-', 1, '/', 2, '-', '[', 2, ']', '-', 2, '?', '?', 2, '?', '!', 2, '!', '?', 1, '&', 2, 'P', 'P', 2, '(', ']', 2, '[', ')', 1, '*', 1, '%', 1, '~', 4, '\'', '\'', '\'', '\'', 1, ' ', 1, '0', 1, 'i', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, '+', 1, '-', 1, '=', 1, '(', 1, ')', 1, 'n', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, '+', 1, '-', 1, '=', 1, '(', 1, ')', 1, 'a', 1, 'e', 1, 'o', 1, 'x', 1, 'h', 1, 'k', 1, 'l', 1, 'm', 1, 'n', 1, 'p', 1, 's', 1, 't', 3, 'E', 'C', 'U', 2, 'C', 'L', 2, 'C', 'r', 2, 'F', 'F', 1, 'L', 3, 'm', 'i', 'l', 1, 'N', 3, 'P', 't', 's', 2, 'R', 's', 1, 'W', 2, 'N', 'S', 1, 'D', 3, 'E', 'U', 'R', 1, 'K', 1, 'T', 2, 'D', 'r', 2, 'P', 'f', 1, 'P', 1, 'G', 1, 'A', 3, 'U', 'A', 'H', 2, 'C', '|', 1, 'L', 2, 'S', 'm', 1, 'T', 2, 'R', 's', 1, 'L', 1, 'M', 1, 'm', 1, 'R', 1, 'l', 3, 'B', 'T', 'C', 5, ' ', 'a', '/', 'c', ' ', 5, ' ', 'a', '/', 's', ' ', 1, 'C', 5, ' ', 'c', '/', 'o', ' ', 5, ' ', 'c', '/', 'u', ' ', 1, 'g', 1, 'H', 1, 'H', 1, 'H', 1, 'h', 1, 'I', 1, 'I', 1, 'L', 1, 'l', 1, 'N', 4, 'N', 'o', '.', ' ', 1, 'P', 1, 'Q', 1, 'R', 1, 'R', 1, 'R', 4, '(', 's', 'm', ')', 3, 'T', 'E', 'L', 4, '(', 't', 'm', ')', 1, 'Z', 1, 'Z', 1, 'K', 1, 'A', 1, 'B', 1, 'C', 1, 'e', 1, 'e', 1, 'E', 1, 'F', 1, 'F', 1, 'M', 1, 'o', 1, 'i', 3, 'F', 'A', 'X', 1, 'D', 1, 'd', 1, 'e', 1, 'i', 1, 'j', 1, 'F', 5, ' ', '1', '/', '7', ' ', 5, ' ', '1', '/', '9', ' ', 6, ' ', '1', '/', '1', '0', ' ', 5, ' ', '1', '/', '3', ' ', 5, ' ', '2', '/', '3', ' ', 5, ' ', '1', '/', '5', ' ', 5, ' ', '2', '/', '5', ' ', 5, ' ', '3', '/', '5', ' ', 5, ' ', '4', '/', '5', ' ', 5, ' ', '1', '/', '6', ' ', 5, ' ', '5', '/', '6', ' ', 5, ' ', '1', '/', '8', ' ', 5, ' ', '3', '/', '8', ' ', 5, ' ', '5', '/', '8', ' ', 5, ' ', '7', '/', '8', ' ', 3, ' ', '1', '/', 1, 'I', 2, 'I', 'I', 3, 'I', 'I', 'I', 2, 'I', 'V', 1, 'V', 2, 'V', 'I', 3, 'V', 'I', 'I', 4, 'V', 'I', 'I', 'I', 2, 'I', 'X', 1, 'X', 2, 'X', 'I', 3, 'X', 'I', 'I', 1, 'L', 1, 'C', 1, 'D', 1, 'M', 1, 'i', 2, 'i', 'i', 3, 'i', 'i', 'i', 2, 'i', 'v', 1, 'v', 2, 'v', 'i', 3, 'v', 'i', 'i', 4, 'v', 'i', 'i', 'i', 2, 'i', 'x', 1, 'x', 2, 'x', 'i', 3, 'x', 'i', 'i', 1, 'l', 1, 'c', 1, 'd', 1, 'm', 2, '(', 'D', 2, 'D', ')', 5, '(', '(', '|', ')', ')', 1, ')', 5, ' ', '0', '/', '3', ' ', 1, '-', 1, '|', 1, '-', 1, '|', 1, '-', 1, '|', 1, '\\', 1, '/', 1, '\\', 1, '/', 1, '-', 1, '-', 1, '~', 1, '~', 1, '-', 1, '|', 1, '-', 1, '|', 1, '-', 1, '-', 1, '-', 1, '|', 1, '-', 1, '|', 1, '|', 1, '-', 1, '-', 1, '-', 1, '-', 1, '-', 1, '-', 1, '|', 1, '|', 1, '|', 1, '|', 1, '|', 1, '|', 1, '|', 1, '^', 1, 'V', 1, '\\', 1, '=', 1, 'V', 1, '^', 1, '-', 1, '-', 1, '|', 1, '|', 1, '-', 1, '-', 1, '|', 1, '|', 1, '=', 1, '|', 1, '=', 1, '=', 1, '|', 1, '=', 1, '|', 1, '=', 1, '=', 1, '=', 1, '=', 1, '=', 1, '=', 1, '|', 1, '=', 1, '|', 1, '=', 1, '|', 1, '\\', 1, '/', 1, '\\', 1, '/', 1, '=', 1, '=', 1, '~', 1, '~', 1, '|', 1, '|', 1, '-', 1, '|', 1, '-', 1, '|', 1, '-', 1, '-', 1, '-', 1, '|', 1, '-', 1, '|', 1, '|', 1, '|', 1, '|', 1, '|', 1, '|', 1, '|', 1, '-', 1, '\\', 1, '\\', 1, '|', 1, '-', 1, '/', 1, '\\', 1, '*', 1, '|', 1, ':', 1, '~', 2, '<', '=', 2, '>', '=', 2, '<', '=', 2, '>', '=', 1, '^', 1, '<', 2, '>', ' ', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 2, '1', '0', 2, '1', '1', 2, '1', '2', 2, '1', '3', 2, '1', '4', 2, '1', '5', 2, '1', '6', 2, '1', '7', 2, '1', '8', 2, '1', '9', 2, '2', '0', 3, '(', '1', ')', 3, '(', '2', ')', 3, '(', '3', ')', 3, '(', '4', ')', 3, '(', '5', ')', 3, '(', '6', ')', 3, '(', '7', ')', 3, '(', '8', ')', 3, '(', '9', ')', 4, '(', '1', '0', ')', 4, '(', '1', '1', ')', 4, '(', '1', '2', ')', 4, '(', '1', '3', ')', 4, '(', '1', '4', ')', 4, '(', '1', '5', ')', 4, '(', '1', '6', ')', 4, '(', '1', '7', ')', 4, '(', '1', '8', ')', 4, '(', '1', '9', ')', 4, '(', '2', '0', ')', 2, '1', '.', 2, '2', '.', 2, '3', '.', 2, '4', '.', 2, '5', '.', 2, '6', '.', 2, '7', '.', 2, '8', '.', 2, '9', '.', 3, '1', '0', '.', 3, '1', '1', '.', 3, '1', '2', '.', 3, '1', '3', '.', 3, '1', '4', '.', 3, '1', '5', '.', 3, '1', '6', '.', 3, '1', '7', '.', 3, '1', '8', '.', 3, '1', '9', '.', 3, '2', '0', '.', 3, '(', 'a', ')', 3, '(', 'b', ')', 3, '(', 'c', ')', 3, '(', 'd', ')', 3, '(', 'e', ')', 3, '(', 'f', ')', 3, '(', 'g', ')', 3, '(', 'h', ')', 3, '(', 'i', ')', 3, '(', 'j', ')', 3, '(', 'k', ')', 3, '(', 'l', ')', 3, '(', 'm', ')', 3, '(', 'n', ')', 3, '(', 'o', ')', 3, '(', 'p', ')', 3, '(', 'q', ')', 3, '(', 'r', ')', 3, '(', 's', ')', 3, '(', 't', ')', 3, '(', 'u', ')', 3, '(', 'v', ')', 3, '(', 'w', ')', 3, '(', 'x', ')', 3, '(', 'y', ')', 3, '(', 'z', ')', 1, 'A', 1, 'B', 1, 'C', 1, 'D', 1, 'E', 1, 'F', 1, 'G', 1, 'H', 1, 'I', 1, 'J', 1, 'K', 1, 'L', 1, 'M', 1, 'N', 1, 'O', 1, 'P', 1, 'Q', 1, 'R', 1, 'S', 1, 'T', 1, 'U', 1, 'V', 1, 'W', 1, 'X', 1, 'Y', 1, 'Z', 1, 'a', 1, 'b', 1, 'c', 1, 'd', 1, 'e', 1, 'f', 1, 'g', 1, 'h', 1, 'i', 1, 'j', 1, 'k', 1, 'l', 1, 'm', 1, 'n', 1, 'o', 1, 'p', 1, 'q', 1, 'r', 1, 's', 1, 't', 1, 'u', 1, 'v', 1, 'w', 1, 'x', 1, 'y', 1, 'z', 1, '0', 2, '1', '1', 2, '1', '2', 2, '1', '3', 2, '1', '4', 2, '1', '5', 2, '1', '6', 2, '1', '7', 2, '1', '8', 2, '1', '9', 2, '2', '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 2, '1', '0', 1, '0', 1, '-', 1, '-', 1, '|', 1, '|', 1, '-', 1, '-', 1, '|', 1, '|', 1, '-', 1, '-', 1, '|', 1, '|', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '-', 1, '-', 1, '|', 1, '|', 1, '-', 1, '|', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '+', 1, '/', 1, '\\', 1, 'X', 1, '-', 1, '|', 1, '-', 1, '|', 1, '-', 1, '|', 1, '-', 1, '|', 1, '-', 1, '|', 1, '-', 1, '|', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '-', 1, '|', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '^', 1, '^', 1, '^', 1, '^', 1, '>', 1, '>', 1, '>', 1, '>', 1, '>', 1, '>', 1, 'V', 1, 'V', 1, 'V', 1, 'V', 1, '<', 1, '<', 1, '<', 1, '<', 1, '<', 1, '<', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '*', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '^', 1, '^', 1, '^', 1, 'O', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '#', 1, '*', 1, '|', 1, '\'', 1, '\"', 1, '\"', 1, ',', 2, ',', ',', 1, '!', 1, '[', 1, '<', 2, '>', ' ', 1, ' ', 1, 'a', 1, '1', 1, 'b', 1, '\'', 1, 'k', 1, '2', 1, 'l', 1, '@', 1, 'c', 1, 'i', 1, 'f', 1, '/', 1, 'm', 1, 's', 1, 'p', 1, '\"', 1, 'e', 1, '3', 1, 'h', 1, '9', 1, 'o', 1, '6', 1, 'r', 1, '^', 1, 'd', 1, 'j', 1, 'g', 1, '>', 1, 'n', 1, 't', 1, 'q', 1, ',', 1, '*', 1, '5', 1, '<', 1, '-', 1, 'u', 1, '8', 1, 'v', 1, '.', 1, '%', 1, '[', 1, '$', 1, '+', 1, 'x', 1, '!', 1, '&', 1, ';', 1, ':', 1, '4', 1, '\\', 1, '0', 1, 'z', 1, '7', 1, '(', 1, '_', 1, '?', 1, 'w', 1, ']', 1, '#', 1, 'y', 1, ')', 1, '=', 4, '[', 'd', '7', ']', 5, '[', 'd', '1', '7', ']', 5, '[', 'd', '2', '7', ']', 6, '[', 'd', '1', '2', '7', ']', 5, '[', 'd', '3', '7', ']', 6, '[', 'd', '1', '3', '7', ']', 6, '[', 'd', '2', '3', '7', ']', 7, '[', 'd', '1', '2', '3', '7', ']', 5, '[', 'd', '4', '7', ']', 6, '[', 'd', '1', '4', '7', ']', 6, '[', 'd', '2', '4', '7', ']', 7, '[', 'd', '1', '2', '4', '7', ']', 6, '[', 'd', '3', '4', '7', ']', 7, '[', 'd', '1', '3', '4', '7', ']', 7, '[', 'd', '2', '3', '4', '7', ']', 8, '[', 'd', '1', '2', '3', '4', '7', ']', 5, '[', 'd', '5', '7', ']', 6, '[', 'd', '1', '5', '7', ']', 6, '[', 'd', '2', '5', '7', ']', 7, '[', 'd', '1', '2', '5', '7', ']', 6, '[', 'd', '3', '5', '7', ']', 7, '[', 'd', '1', '3', '5', '7', ']', 7, '[', 'd', '2', '3', '5', '7', ']', 8, '[', 'd', '1', '2', '3', '5', '7', ']', 6, '[', 'd', '4', '5', '7', ']', 7, '[', 'd', '1', '4', '5', '7', ']', 7, '[', 'd', '2', '4', '5', '7', ']', 8, '[', 'd', '1', '2', '4', '5', '7', ']', 7, '[', 'd', '3', '4', '5', '7', ']', 8, '[', 'd', '1', '3', '4', '5', '7', ']', 8, '[', 'd', '2', '3', '4', '5', '7', ']', 9, '[', 'd', '1', '2', '3', '4', '5', '7', ']', 5, '[', 'd', '6', '7', ']', 6, '[', 'd', '1', '6', '7', ']', 6, '[', 'd', '2', '6', '7', ']', 7, '[', 'd', '1', '2', '6', '7', ']', 6, '[', 'd', '3', '6', '7', ']', 7, '[', 'd', '1', '3', '6', '7', ']', 7, '[', 'd', '2', '3', '6', '7', ']', 8, '[', 'd', '1', '2', '3', '6', '7', ']', 6, '[', 'd', '4', '6', '7', ']', 7, '[', 'd', '1', '4', '6', '7', ']', 7, '[', 'd', '2', '4', '6', '7', ']', 8, '[', 'd', '1', '2', '4', '6', '7', ']', 7, '[', 'd', '3', '4', '6', '7', ']', 8, '[', 'd', '1', '3', '4', '6', '7', ']', 8, '[', 'd', '2', '3', '4', '6', '7', ']', 9, '[', 'd', '1', '2', '3', '4', '6', '7', ']', 6, '[', 'd', '5', '6', '7', ']', 7, '[', 'd', '1', '5', '6', '7', ']', 7, '[', 'd', '2', '5', '6', '7', ']', 8, '[', 'd', '1', '2', '5', '6', '7', ']', 7, '[', 'd', '3', '5', '6', '7', ']', 8, '[', 'd', '1', '3', '5', '6', '7', ']', 8, '[', 'd', '2', '3', '5', '6', '7', ']', 9, '[', 'd', '1', '2', '3', '5', '6', '7', ']', 7, '[', 'd', '4', '5', '6', '7', ']', 8, '[', 'd', '1', '4', '5', '6', '7', ']', 8, '[', 'd', '2', '4', '5', '6', '7', ']', 9, '[', 'd', '1', '2', '4', '5', '6', '7', ']', 8, '[', 'd', '3', '4', '5', '6', '7', ']', 9, '[', 'd', '1', '3', '4', '5', '6', '7', ']', 9, '[', 'd', '2', '3', '4', '5', '6', '7', ']', 10, '[', 'd', '1', '2', '3', '4', '5', '6', '7', ']', 4, '[', 'd', '8', ']', 5, '[', 'd', '1', '8', ']', 5, '[', 'd', '2', '8', ']', 6, '[', 'd', '1', '2', '8', ']', 5, '[', 'd', '3', '8', ']', 6, '[', 'd', '1', '3', '8', ']', 6, '[', 'd', '2', '3', '8', ']', 7, '[', 'd', '1', '2', '3', '8', ']', 5, '[', 'd', '4', '8', ']', 6, '[', 'd', '1', '4', '8', ']', 6, '[', 'd', '2', '4', '8', ']', 7, '[', 'd', '1', '2', '4', '8', ']', 6, '[', 'd', '3', '4', '8', ']', 7, '[', 'd', '1', '3', '4', '8', ']', 7, '[', 'd', '2', '3', '4', '8', ']', 8, '[', 'd', '1', '2', '3', '4', '8', ']', 5, '[', 'd', '5', '8', ']', 6, '[', 'd', '1', '5', '8', ']', 6, '[', 'd', '2', '5', '8', ']', 7, '[', 'd', '1', '2', '5', '8', ']', 6, '[', 'd', '3', '5', '8', ']', 7, '[', 'd', '1', '3', '5', '8', ']', 7, '[', 'd', '2', '3', '5', '8', ']', 8, '[', 'd', '1', '2', '3', '5', '8', ']', 6, '[', 'd', '4', '5', '8', ']', 7, '[', 'd', '1', '4', '5', '8', ']', 7, '[', 'd', '2', '4', '5', '8', ']', 8, '[', 'd', '1', '2', '4', '5', '8', ']', 7, '[', 'd', '3', '4', '5', '8', ']', 8, '[', 'd', '1', '3', '4', '5', '8', ']', 8, '[', 'd', '2', '3', '4', '5', '8', ']', 9, '[', 'd', '1', '2', '3', '4', '5', '8', ']', 5, '[', 'd', '6', '8', ']', 6, '[', 'd', '1', '6', '8', ']', 6, '[', 'd', '2', '6', '8', ']', 7, '[', 'd', '1', '2', '6', '8', ']', 6, '[', 'd', '3', '6', '8', ']', 7, '[', 'd', '1', '3', '6', '8', ']', 7, '[', 'd', '2', '3', '6', '8', ']', 8, '[', 'd', '1', '2', '3', '6', '8', ']', 6, '[', 'd', '4', '6', '8', ']', 7, '[', 'd', '1', '4', '6', '8', ']', 7, '[', 'd', '2', '4', '6', '8', ']', 8, '[', 'd', '1', '2', '4', '6', '8', ']', 7, '[', 'd', '3', '4', '6', '8', ']', 8, '[', 'd', '1', '3', '4', '6', '8', ']', 8, '[', 'd', '2', '3', '4', '6', '8', ']', 9, '[', 'd', '1', '2', '3', '4', '6', '8', ']', 6, '[', 'd', '5', '6', '8', ']', 7, '[', 'd', '1', '5', '6', '8', ']', 7, '[', 'd', '2', '5', '6', '8', ']', 8, '[', 'd', '1', '2', '5', '6', '8', ']', 7, '[', 'd', '3', '5', '6', '8', ']', 8, '[', 'd', '1', '3', '5', '6', '8', ']', 8, '[', 'd', '2', '3', '5', '6', '8', ']', 9, '[', 'd', '1', '2', '3', '5', '6', '8', ']', 7, '[', 'd', '4', '5', '6', '8', ']', 8, '[', 'd', '1', '4', '5', '6', '8', ']', 8, '[', 'd', '2', '4', '5', '6', '8', ']', 9, '[', 'd', '1', '2', '4', '5', '6', '8', ']', 8, '[', 'd', '3', '4', '5', '6', '8', ']', 9, '[', 'd', '1', '3', '4', '5', '6', '8', ']', 9, '[', 'd', '2', '3', '4', '5', '6', '8', ']', 10, '[', 'd', '1', '2', '3', '4', '5', '6', '8', ']', 5, '[', 'd', '7', '8', ']', 6, '[', 'd', '1', '7', '8', ']', 6, '[', 'd', '2', '7', '8', ']', 7, '[', 'd', '1', '2', '7', '8', ']', 6, '[', 'd', '3', '7', '8', ']', 7, '[', 'd', '1', '3', '7', '8', ']', 7, '[', 'd', '2', '3', '7', '8', ']', 8, '[', 'd', '1', '2', '3', '7', '8', ']', 6, '[', 'd', '4', '7', '8', ']', 7, '[', 'd', '1', '4', '7', '8', ']', 7, '[', 'd', '2', '4', '7', '8', ']', 8, '[', 'd', '1', '2', '4', '7', '8', ']', 7, '[', 'd', '3', '4', '7', '8', ']', 8, '[', 'd', '1', '3', '4', '7', '8', ']', 8, '[', 'd', '2', '3', '4', '7', '8', ']', 9, '[', 'd', '1', '2', '3', '4', '7', '8', ']', 6, '[', 'd', '5', '7', '8', ']', 7, '[', 'd', '1', '5', '7', '8', ']', 7, '[', 'd', '2', '5', '7', '8', ']', 8, '[', 'd', '1', '2', '5', '7', '8', ']', 7, '[', 'd', '3', '5', '7', '8', ']', 8, '[', 'd', '1', '3', '5', '7', '8', ']', 8, '[', 'd', '2', '3', '5', '7', '8', ']', 9, '[', 'd', '1', '2', '3', '5', '7', '8', ']', 7, '[', 'd', '4', '5', '7', '8', ']', 8, '[', 'd', '1', '4', '5', '7', '8', ']', 8, '[', 'd', '2', '4', '5', '7', '8', ']', 9, '[', 'd', '1', '2', '4', '5', '7', '8', ']', 8, '[', 'd', '3', '4', '5', '7', '8', ']', 9, '[', 'd', '1', '3', '4', '5', '7', '8', ']', 9, '[', 'd', '2', '3', '4', '5', '7', '8', ']', 10, '[', 'd', '1', '2', '3', '4', '5', '7', '8', ']', 6, '[', 'd', '6', '7', '8', ']', 7, '[', 'd', '1', '6', '7', '8', ']', 7, '[', 'd', '2', '6', '7', '8', ']', 8, '[', 'd', '1', '2', '6', '7', '8', ']', 7, '[', 'd', '3', '6', '7', '8', ']', 8, '[', 'd', '1', '3', '6', '7', '8', ']', 8, '[', 'd', '2', '3', '6', '7', '8', ']', 9, '[', 'd', '1', '2', '3', '6', '7', '8', ']', 7, '[', 'd', '4', '6', '7', '8', ']', 8, '[', 'd', '1', '4', '6', '7', '8', ']', 8, '[', 'd', '2', '4', '6', '7', '8', ']', 9, '[', 'd', '1', '2', '4', '6', '7', '8', ']', 8, '[', 'd', '3', '4', '6', '7', '8', ']', 9, '[', 'd', '1', '3', '4', '6', '7', '8', ']', 9, '[', 'd', '2', '3', '4', '6', '7', '8', ']', 10, '[', 'd', '1', '2', '3', '4', '6', '7', '8', ']', 7, '[', 'd', '5', '6', '7', '8', ']', 8, '[', 'd', '1', '5', '6', '7', '8', ']', 8, '[', 'd', '2', '5', '6', '7', '8', ']', 9, '[', 'd', '1', '2', '5', '6', '7', '8', ']', 8, '[', 'd', '3', '5', '6', '7', '8', ']', 9, '[', 'd', '1', '3', '5', '6', '7', '8', ']', 9, '[', 'd', '2', '3', '5', '6', '7', '8', ']', 10, '[', 'd', '1', '2', '3', '5', '6', '7', '8', ']', 8, '[', 'd', '4', '5', '6', '7', '8', ']', 9, '[', 'd', '1', '4', '5', '6', '7', '8', ']', 9, '[', 'd', '2', '4', '5', '6', '7', '8', ']', 10, '[', 'd', '1', '2', '4', '5', '6', '7', '8', ']', 9, '[', 'd', '3', '4', '5', '6', '7', '8', ']', 10, '[', 'd', '1', '3', '4', '5', '6', '7', '8', ']', 10, '[', 'd', '2', '3', '4', '5', '6', '7', '8', ']', 11, '[', 'd', '1', '2', '3', '4', '5', '6', '7', '8', ']', 1, '{', 2, '}', ' ', 3, ':', ':', '=', 2, '=', '=', 3, '=', '=', '=', 1, 'L', 1, 'l', 1, 'L', 1, 'P', 1, 'R', 1, 'a', 1, 't', 1, 'H', 1, 'h', 1, 'K', 1, 'k', 1, 'Z', 1, 'z', 1, 'M', 1, 'A', 1, 'r', 2, 'r', '.', 1, 'T', 2, 'T', '.', 1, 's', 2, '[', ']', 1, '\\', 1, '/', 2, '_', '_', 1, '>', 1, '%', 1, '>', 1, '=', 1, '/', 1, '-', 1, '~', 1, '\\', 1, '/', 1, '~', 1, '~', 2, '|', '-', 2, '-', '|', 2, '<', '=', 2, '=', '>', 2, '(', '(', 2, ')', ')', 2, ':', ':', 1, '?', 1, '\'', 1, 'o', 1, '.', 1, ',', 1, '.', 1, ',', 1, ';', 4, '-', '-', '-', '-', 6, '-', '-', '-', '-', '-', '-', 1, 'x', 1, '|', 1, '=', 1, ',', 1, '\"', 3, '`', '-', '-', 1, ' ', 2, ',', ' ', 2, '.', ' ', 1, '\"', 5, '[', 'J', 'I', 'S', ']', 1, '\"', 1, '/', 1, '0', 1, '<', 2, '>', ' ', 2, '<', '<', 3, '>', '>', ' ', 1, '[', 2, ']', ' ', 1, '{', 2, '}', ' ', 2, '[', '(', 3, ')', ']', ' ', 1, '@', 2, 'X', ' ', 1, '[', 2, ']', ' ', 2, '[', '[', 3, ']', ']', ' ', 2, '(', '(', 3, ')', ')', ' ', 2, '[', '[', 3, ']', ']', ' ', 2, '~', ' ', 2, '`', '`', 2, '\'', '\'', 2, ',', ',', 1, '@', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, '~', 1, '+', 1, '+', 1, '+', 1, '+', 1, '@', 4, ' ', '/', '/', ' ', 4, '+', '1', '0', '+', 4, '+', '2', '0', '+', 4, '+', '3', '0', '+', 1, 'a', 1, 'a', 1, 'i', 1, 'i', 1, 'u', 1, 'u', 1, 'e', 1, 'e', 1, 'o', 1, 'o', 2, 'k', 'a', 2, 'g', 'a', 2, 'k', 'i', 2, 'g', 'i', 2, 'k', 'u', 2, 'g', 'u', 2, 'k', 'e', 2, 'g', 'e', 2, 'k', 'o', 2, 'g', 'o', 2, 's', 'a', 2, 'z', 'a', 3, 's', 'h', 'i', 2, 'z', 'i', 2, 's', 'u', 2, 'z', 'u', 2, 's', 'e', 2, 'z', 'e', 2, 's', 'o', 2, 'z', 'o', 2, 't', 'a', 2, 'd', 'a', 3, 'c', 'h', 'i', 2, 'd', 'i', 3, 't', 's', 'u', 3, 't', 's', 'u', 2, 'd', 'u', 2, 't', 'e', 2, 'd', 'e', 2, 't', 'o', 2, 'd', 'o', 2, 'n', 'a', 2, 'n', 'i', 2, 'n', 'u', 2, 'n', 'e', 2, 'n', 'o', 2, 'h', 'a', 2, 'b', 'a', 2, 'p', 'a', 2, 'h', 'i', 2, 'b', 'i', 2, 'p', 'i', 2, 'h', 'u', 2, 'b', 'u', 2, 'p', 'u', 2, 'h', 'e', 2, 'b', 'e', 2, 'p', 'e', 2, 'h', 'o', 2, 'b', 'o', 2, 'p', 'o', 2, 'm', 'a', 2, 'm', 'i', 2, 'm', 'u', 2, 'm', 'e', 2, 'm', 'o', 2, 'y', 'a', 2, 'y', 'a', 2, 'y', 'u', 2, 'y', 'u', 2, 'y', 'o', 2, 'y', 'o', 2, 'r', 'a', 2, 'r', 'i', 2, 'r', 'u', 2, 'r', 'e', 2, 'r', 'o', 2, 'w', 'a', 2, 'w', 'a', 2, 'w', 'i', 2, 'w', 'e', 2, 'w', 'o', 1, 'n', 2, 'v', 'u', 1, '\"', 1, '\"', 1, 'a', 1, 'a', 1, 'i', 1, 'i', 1, 'u', 1, 'u', 1, 'e', 1, 'e', 1, 'o', 1, 'o', 2, 'k', 'a', 2, 'g', 'a', 2, 'k', 'i', 2, 'g', 'i', 2, 'k', 'u', 2, 'g', 'u', 2, 'k', 'e', 2, 'g', 'e', 2, 'k', 'o', 2, 'g', 'o', 2, 's', 'a', 2, 'z', 'a', 3, 's', 'h', 'i', 2, 'z', 'i', 2, 's', 'u', 2, 'z', 'u', 2, 's', 'e', 2, 'z', 'e', 2, 's', 'o', 2, 'z', 'o', 2, 't', 'a', 2, 'd', 'a', 3, 'c', 'h', 'i', 2, 'd', 'i', 3, 't', 's', 'u', 3, 't', 's', 'u', 2, 'd', 'u', 2, 't', 'e', 2, 'd', 'e', 2, 't', 'o', 2, 'd', 'o', 2, 'n', 'a', 2, 'n', 'i', 2, 'n', 'u', 2, 'n', 'e', 2, 'n', 'o', 2, 'h', 'a', 2, 'b', 'a', 2, 'p', 'a', 2, 'h', 'i', 2, 'b', 'i', 2, 'p', 'i', 2, 'h', 'u', 2, 'b', 'u', 2, 'p', 'u', 2, 'h', 'e', 2, 'b', 'e', 2, 'p', 'e', 2, 'h', 'o', 2, 'b', 'o', 2, 'p', 'o', 2, 'm', 'a', 2, 'm', 'i', 2, 'm', 'u', 2, 'm', 'e', 2, 'm', 'o', 2, 'y', 'a', 2, 'y', 'a', 2, 'y', 'u', 2, 'y', 'u', 2, 'y', 'o', 2, 'y', 'o', 2, 'r', 'a', 2, 'r', 'i', 2, 'r', 'u', 2, 'r', 'e', 2, 'r', 'o', 2, 'w', 'a', 2, 'w', 'a', 2, 'w', 'i', 2, 'w', 'e', 2, 'w', 'o', 1, 'n', 2, 'v', 'u', 2, 'k', 'a', 2, 'k', 'e', 2, 'v', 'a', 2, 'v', 'i', 2, 'v', 'e', 2, 'v', 'o', 1, '\"', 1, '\"', 1, 'B', 1, 'P', 1, 'M', 1, 'F', 1, 'D', 1, 'T', 1, 'N', 1, 'L', 1, 'G', 1, 'K', 1, 'H', 1, 'J', 1, 'Q', 1, 'X', 2, 'Z', 'H', 2, 'C', 'H', 2, 'S', 'H', 1, 'R', 1, 'Z', 1, 'C', 1, 'S', 1, 'A', 1, 'O', 1, 'E', 2, 'E', 'H', 2, 'A', 'I', 2, 'E', 'I', 2, 'A', 'U', 2, 'O', 'U', 2, 'A', 'N', 2, 'E', 'N', 3, 'A', 'N', 'G', 3, 'E', 'N', 'G', 2, 'E', 'R', 1, 'I', 1, 'U', 2, 'I', 'U', 1, 'V', 2, 'N', 'G', 2, 'G', 'N', 1, 'g', 2, 'g', 'g', 2, 'g', 's', 1, 'n', 2, 'n', 'j', 2, 'n', 'h', 1, 'd', 2, 'd', 'd', 1, 'r', 2, 'l', 'g', 2, 'l', 'm', 2, 'l', 'b', 2, 'l', 's', 2, 'l', 't', 2, 'l', 'p', 2, 'r', 'h', 1, 'm', 1, 'b', 2, 'b', 'b', 2, 'b', 's', 1, 's', 2, 's', 's', 1, 'j', 2, 'j', 'j', 1, 'c', 1, 'k', 1, 't', 1, 'p', 1, 'h', 1, 'a', 2, 'a', 'e', 2, 'y', 'a', 3, 'y', 'a', 'e', 2, 'e', 'o', 1, 'e', 3, 'y', 'e', 'o', 2, 'y', 'e', 1, 'o', 2, 'w', 'a', 3, 'w', 'a', 'e', 2, 'o', 'e', 2, 'y', 'o', 1, 'u', 3, 'w', 'e', 'o', 2, 'w', 'e', 2, 'w', 'i', 2, 'y', 'u', 2, 'e', 'u', 2, 'y', 'i', 1, 'i', 2, 'n', 'n', 2, 'n', 'd', 2, 'n', 's', 2, 'n', 'Z', 3, 'l', 'g', 's', 2, 'l', 'd', 3, 'l', 'b', 's', 2, 'l', 'Z', 2, 'l', 'Q', 2, 'm', 'b', 2, 'm', 's', 2, 'm', 'Z', 2, 'm', 'N', 2, 'b', 'g', 3, 'b', 's', 'g', 3, 'b', 's', 't', 2, 'b', 'j', 2, 'b', 't', 2, 'b', 'N', 3, 'b', 'b', 'N', 2, 's', 'g', 2, 's', 'n', 2, 's', 'd', 2, 's', 'b', 2, 's', 'j', 1, 'Z', 1, 'N', 2, 'N', 's', 2, 'N', 'Z', 2, 'p', 'N', 2, 'h', 'h', 1, 'Q', 5, 'y', 'o', '-', 'y', 'a', 6, 'y', 'o', '-', 'y', 'a', 'e', 4, 'y', 'o', '-', 'i', 6, 'y', 'u', '-', 'y', 'e', 'o', 5, 'y', 'u', '-', 'y', 'e', 4, 'y', 'u', '-', 'i', 1, 'U', 3, 'U', '-', 'i', 2, 'B', 'U', 2, 'Z', 'I', 2, 'J', 'I', 2, 'G', 'U', 2, 'E', 'E', 3, 'E', 'N', 'N', 2, 'O', 'O', 3, 'O', 'N', 'N', 2, 'I', 'R', 3, 'A', 'N', 'N', 3, 'I', 'N', 'N', 3, 'U', 'N', 'N', 2, 'I', 'M', 3, 'N', 'G', 'G', 4, 'A', 'I', 'N', 'N', 4, 'A', 'U', 'N', 'N', 2, 'A', 'M', 2, 'O', 'M', 3, 'O', 'N', 'G', 4, 'I', 'N', 'N', 'N', 1, 'P', 1, 'T', 1, 'K', 1, 'H', 3, '(', 'g', ')', 3, '(', 'n', ')', 3, '(', 'd', ')', 3, '(', 'r', ')', 3, '(', 'm', ')', 3, '(', 'b', ')', 3, '(', 's', ')', 2, '(', ')', 3, '(', 'j', ')', 3, '(', 'c', ')', 3, '(', 'k', ')', 3, '(', 't', ')', 3, '(', 'p', ')', 3, '(', 'h', ')', 4, '(', 'g', 'a', ')', 4, '(', 'n', 'a', ')', 4, '(', 'd', 'a', ')', 4, '(', 'r', 'a', ')', 4, '(', 'm', 'a', ')', 4, '(', 'b', 'a', ')', 4, '(', 's', 'a', ')', 3, '(', 'a', ')', 4, '(', 'j', 'a', ')', 4, '(', 'c', 'a', ')', 4, '(', 'k', 'a', ')', 4, '(', 't', 'a', ')', 4, '(', 'p', 'a', ')', 4, '(', 'h', 'a', ')', 4, '(', 'j', 'u', ')', 4, '(', '1', ')', ' ', 4, '(', '2', ')', ' ', 4, '(', '3', ')', ' ', 4, '(', '4', ')', ' ', 4, '(', '5', ')', ' ', 4, '(', '6', ')', ' ', 4, '(', '7', ')', ' ', 4, '(', '8', ')', ' ', 4, '(', '9', ')', ' ', 5, '(', '1', '0', ')', ' ', 6, '(', 'Y', 'u', 'e', ')', ' ', 6, '(', 'H', 'u', 'o', ')', ' ', 7, '(', 'S', 'h', 'u', 'i', ')', ' ', 5, '(', 'M', 'u', ')', ' ', 6, '(', 'J', 'i', 'n', ')', ' ', 5, '(', 'T', 'u', ')', ' ', 5, '(', 'R', 'i', ')', ' ', 6, '(', 'Z', 'h', 'u', ')', ' ', 6, '(', 'Y', 'o', 'u', ')', ' ', 6, '(', 'S', 'h', 'e', ')', ' ', 7, '(', 'M', 'i', 'n', 'g', ')', ' ', 5, '(', 'T', 'e', ')', ' ', 6, '(', 'C', 'a', 'i', ')', ' ', 6, '(', 'Z', 'h', 'u', ')', ' ', 6, '(', 'L', 'a', 'o', ')', ' ', 6, '(', 'D', 'a', 'i', ')', ' ', 5, '(', 'H', 'u', ')', ' ', 6, '(', 'X', 'u', 'e', ')', ' ', 7, '(', 'J', 'i', 'a', 'n', ')', ' ', 5, '(', 'Q', 'i', ')', ' ', 5, '(', 'Z', 'i', ')', ' ', 6, '(', 'X', 'i', 'e', ')', ' ', 5, '(', 'J', 'i', ')', ' ', 6, '(', 'X', 'i', 'u', ')', ' ', 2, '<', '<', 2, '>', '>', 2, '2', '1', 2, '2', '2', 2, '2', '3', 2, '2', '4', 2, '2', '5', 2, '2', '6', 2, '2', '7', 2, '2', '8', 2, '2', '9', 2, '3', '0', 2, '3', '1', 2, '3', '2', 2, '3', '3', 2, '3', '4', 2, '3', '5', 3, '(', 'g', ')', 3, '(', 'n', ')', 3, '(', 'd', ')', 3, '(', 'r', ')', 3, '(', 'm', ')', 3, '(', 'b', ')', 3, '(', 's', ')', 2, '(', ')', 3, '(', 'j', ')', 3, '(', 'c', ')', 3, '(', 'k', ')', 3, '(', 't', ')', 3, '(', 'p', ')', 3, '(', 'h', ')', 4, '(', 'g', 'a', ')', 4, '(', 'n', 'a', ')', 4, '(', 'd', 'a', ')', 4, '(', 'r', 'a', ')', 4, '(', 'm', 'a', ')', 4, '(', 'b', 'a', ')', 4, '(', 's', 'a', ')', 3, '(', 'a', ')', 4, '(', 'j', 'a', ')', 4, '(', 'c', 'a', ')', 4, '(', 'k', 'a', ')', 4, '(', 't', 'a', ')', 4, '(', 'p', 'a', ')', 4, '(', 'h', 'a', ')', 4, 'K', 'I', 'S', ' ', 4, '(', '1', ')', ' ', 4, '(', '2', ')', ' ', 4, '(', '3', ')', ' ', 4, '(', '4', ')', ' ', 4, '(', '5', ')', ' ', 4, '(', '6', ')', ' ', 4, '(', '7', ')', ' ', 4, '(', '8', ')', ' ', 4, '(', '9', ')', ' ', 5, '(', '1', '0', ')', ' ', 6, '(', 'Y', 'u', 'e', ')', ' ', 6, '(', 'H', 'u', 'o', ')', ' ', 7, '(', 'S', 'h', 'u', 'i', ')', ' ', 5, '(', 'M', 'u', ')', ' ', 6, '(', 'J', 'i', 'n', ')', ' ', 5, '(', 'T', 'u', ')', ' ', 5, '(', 'R', 'i', ')', ' ', 6, '(', 'Z', 'h', 'u', ')', ' ', 6, '(', 'Y', 'o', 'u', ')', ' ', 6, '(', 'S', 'h', 'e', ')', ' ', 7, '(', 'M', 'i', 'n', 'g', ')', ' ', 5, '(', 'T', 'e', ')', ' ', 6, '(', 'C', 'a', 'i', ')', ' ', 6, '(', 'Z', 'h', 'u', ')', ' ', 6, '(', 'L', 'a', 'o', ')', ' ', 5, '(', 'M', 'i', ')', ' ', 6, '(', 'N', 'a', 'n', ')', ' ', 5, '(', 'N', 'u', ')', ' ', 6, '(', 'S', 'h', 'i', ')', ' ', 6, '(', 'Y', 'o', 'u', ')', ' ', 6, '(', 'Y', 'i', 'n', ')', ' ', 6, '(', 'Z', 'h', 'u', ')', ' ', 8, '(', 'X', 'i', 'a', 'n', 'g', ')', ' ', 6, '(', 'X', 'i', 'u', ')', ' ', 6, '(', 'X', 'i', 'e', ')', ' ', 8, '(', 'Z', 'h', 'e', 'n', 'g', ')', ' ', 8, '(', 'S', 'h', 'a', 'n', 'g', ')', ' ', 8, '(', 'Z', 'h', 'o', 'n', 'g', ')', ' ', 6, '(', 'X', 'i', 'a', ')', ' ', 6, '(', 'Z', 'u', 'o', ')', ' ', 6, '(', 'Y', 'o', 'u', ')', ' ', 5, '(', 'Y', 'i', ')', ' ', 7, '(', 'Z', 'o', 'n', 'g', ')', ' ', 6, '(', 'X', 'u', 'e', ')', ' ', 7, '(', 'J', 'i', 'a', 'n', ')', ' ', 5, '(', 'Q', 'i', ')', ' ', 5, '(', 'Z', 'i', ')', ' ', 6, '(', 'X', 'i', 'e', ')', ' ', 5, '(', 'Y', 'e', ')', ' ', 2, '3', '6', 2, '3', '7', 2, '3', '8', 2, '3', '9', 2, '4', '0', 2, '4', '1', 2, '4', '2', 2, '4', '3', 2, '4', '4', 2, '4', '5', 2, '4', '6', 2, '4', '7', 2, '4', '8', 2, '4', '9', 2, '5', '0', 2, '1', 'M', 2, '2', 'M', 2, '3', 'M', 2, '4', 'M', 2, '5', 'M', 2, '6', 'M', 2, '7', 'M', 2, '8', 'M', 2, '9', 'M', 3, '1', '0', 'M', 3, '1', '1', 'M', 3, '1', '2', 'M', 2, 'H', 'g', 3, 'e', 'r', 'g', 2, 'e', 'V', 3, 'L', 'T', 'D', 1, 'a', 1, 'i', 1, 'u', 1, 'u', 1, 'o', 2, 'k', 'a', 2, 'k', 'i', 2, 'k', 'u', 2, 'k', 'e', 2, 'k', 'o', 2, 's', 'a', 2, 's', 'i', 2, 's', 'u', 2, 's', 'e', 2, 's', 'o', 2, 't', 'a', 2, 't', 'i', 2, 't', 'u', 2, 't', 'e', 2, 't', 'o', 2, 'n', 'a', 2, 'n', 'i', 2, 'n', 'u', 2, 'n', 'e', 2, 'n', 'o', 2, 'h', 'a', 2, 'h', 'i', 2, 'h', 'u', 2, 'h', 'e', 2, 'h', 'o', 2, 'm', 'a', 2, 'm', 'i', 2, 'm', 'u', 2, 'm', 'e', 2, 'm', 'o', 2, 'y', 'a', 2, 'y', 'u', 2, 'y', 'o', 2, 'r', 'a', 2, 'r', 'i', 2, 'r', 'u', 2, 'r', 'e', 2, 'r', 'o', 2, 'w', 'a', 2, 'w', 'i', 2, 'w', 'e', 2, 'w', 'o', 9, 'a', 'p', 'a', 'r', 't', 'm', 'e', 'n', 't', 5, 'a', 'l', 'p', 'h', 'a', 6, 'a', 'm', 'p', 'e', 'r', 'e', 3, 'a', 'r', 'e', 6, 'i', 'n', 'n', 'i', 'n', 'g', 4, 'i', 'n', 'c', 'h', 3, 'w', 'o', 'n', 6, 'e', 's', 'c', 'u', 'd', 'o', 4, 'a', 'c', 'r', 'e', 5, 'o', 'u', 'n', 'c', 'e', 3, 'o', 'h', 'm', 6, 'k', 'a', 'i', '-', 'r', 'i', 5, 'c', 'a', 'r', 'a', 't', 7, 'c', 'a', 'l', 'o', 'r', 'i', 'e', 6, 'g', 'a', 'l', 'l', 'o', 'n', 5, 'g', 'a', 'm', 'm', 'a', 4, 'g', 'i', 'g', 'a', 6, 'g', 'u', 'i', 'n', 'e', 'a', 5, 'c', 'u', 'r', 'i', 'e', 7, 'g', 'u', 'i', 'l', 'd', 'e', 'r', 4, 'k', 'i', 'l', 'o', 8, 'k', 'i', 'l', 'o', 'g', 'r', 'a', 'm', 9, 'k', 'i', 'l', 'o', 'm', 'e', 't', 'e', 'r', 8, 'k', 'i', 'l', 'o', 'w', 'a', 't', 't', 4, 'g', 'r', 'a', 'm', 8, 'g', 'r', 'a', 'm', ' ', 't', 'o', 'n', 8, 'c', 'r', 'u', 'z', 'e', 'i', 'r', 'o', 5, 'k', 'r', 'o', 'n', 'e', 4, 'c', 'a', 's', 'e', 6, 'k', 'o', 'r', 'u', 'n', 'a', 5, 'c', 'o', '-', 'o', 'p', 5, 'c', 'y', 'c', 'l', 'e', 7, 'c', 'e', 'n', 't', 'i', 'm', 'e', 8, 's', 'h', 'i', 'l', 'l', 'i', 'n', 'g', 5, 'c', 'e', 'n', 't', 'i', 4, 'c', 'e', 'n', 't', 5, 'd', 'o', 'z', 'e', 'n', 4, 'd', 'e', 's', 'i', 6, 'd', 'o', 'l', 'l', 'a', 'r', 3, 't', 'o', 'n', 4, 'n', 'a', 'n', 'o', 4, 'k', 'n', 'o', 't', 7, 'h', 'e', 'i', 'g', 'h', 't', 's', 7, 'p', 'e', 'r', 'c', 'e', 'n', 't', 5, 'p', 'a', 'r', 't', 's', 6, 'b', 'a', 'r', 'r', 'e', 'l', 7, 'p', 'i', 'a', 's', 't', 'e', 'r', 5, 'p', 'i', 'c', 'u', 'l', 4, 'p', 'i', 'c', 'o', 8, 'b', 'u', 'i', 'l', 'd', 'i', 'n', 'g', 5, 'f', 'a', 'r', 'a', 'd', 4, 'f', 'e', 'e', 't', 6, 'b', 'u', 's', 'h', 'e', 'l', 5, 'f', 'r', 'a', 'n', 'c', 7, 'h', 'e', 'c', 't', 'a', 'r', 'e', 4, 'p', 'e', 's', 'o', 7, 'p', 'f', 'e', 'n', 'n', 'i', 'g', 5, 'h', 'e', 'r', 't', 'z', 5, 'p', 'e', 'n', 'c', 'e', 4, 'p', 'a', 'g', 'e', 4, 'b', 'e', 't', 'a', 5, 'p', 'o', 'i', 'n', 't', 4, 'v', 'o', 'l', 't', 3, 'h', 'o', 'n', 5, 'p', 'o', 'u', 'n', 'd', 4, 'h', 'a', 'l', 'l', 4, 'h', 'o', 'r', 'n', 5, 'm', 'i', 'c', 'r', 'o', 4, 'm', 'i', 'l', 'e', 4, 'm', 'a', 'c', 'h', 4, 'm', 'a', 'r', 'k', 7, 'm', 'a', 'n', 's', 'i', 'o', 'n', 6, 'm', 'i', 'c', 'r', 'o', 'n', 5, 'm', 'i', 'l', 'l', 'i', 8, 'm', 'i', 'l', 'l', 'i', 'b', 'a', 'r', 4, 'm', 'e', 'g', 'a', 7, 'm', 'e', 'g', 'a', 't', 'o', 'n', 5, 'm', 'e', 't', 'e', 'r', 4, 'y', 'a', 'r', 'd', 4, 'y', 'a', 'r', 'd', 4, 'y', 'u', 'a', 'n', 5, 'l', 'i', 't', 'e', 'r', 4, 'l', 'i', 'r', 'a', 5, 'r', 'u', 'p', 'e', 'e', 5, 'r', 'u', 'b', 'l', 'e', 3, 'r', 'e', 'm', 8, 'r', 'o', 'e', 'n', 't', 'g', 'e', 'n', 4, 'w', 'a', 't', 't', 2, '0', 'h', 2, '1', 'h', 2, '2', 'h', 2, '3', 'h', 2, '4', 'h', 2, '5', 'h', 2, '6', 'h', 2, '7', 'h', 2, '8', 'h', 2, '9', 'h', 3, '1', '0', 'h', 3, '1', '1', 'h', 3, '1', '2', 'h', 3, '1', '3', 'h', 3, '1', '4', 'h', 3, '1', '5', 'h', 3, '1', '6', 'h', 3, '1', '7', 'h', 3, '1', '8', 'h', 3, '1', '9', 'h', 3, '2', '0', 'h', 3, '2', '1', 'h', 3, '2', '2', 'h', 3, '2', '3', 'h', 3, '2', '4', 'h', 3, 'h', 'P', 'a', 2, 'd', 'a', 2, 'A', 'U', 3, 'b', 'a', 'r', 2, 'o', 'V', 2, 'p', 'c', 2, 'd', 'm', 4, 'd', 'm', '^', '2', 4, 'd', 'm', '^', '3', 2, 'I', 'U', 6, 'H', 'e', 'i', 's', 'e', 'i', 6, 'S', 'y', 'o', 'u', 'w', 'a', 7, 'T', 'a', 'i', 's', 'y', 'o', 'u', 5, 'M', 'e', 'i', 'j', 'i', 4, 'I', 'n', 'c', '.', 2, 'p', 'A', 2, 'n', 'A', 2, 'u', 'A', 2, 'm', 'A', 2, 'k', 'A', 2, 'k', 'B', 2, 'M', 'B', 2, 'G', 'B', 3, 'c', 'a', 'l', 4, 'k', 'c', 'a', 'l', 2, 'p', 'F', 2, 'n', 'F', 2, 'u', 'F', 2, 'u', 'g', 2, 'm', 'g', 2, 'k', 'g', 2, 'H', 'z', 3, 'k', 'H', 'z', 3, 'M', 'H', 'z', 3, 'G', 'H', 'z', 3, 'T', 'H', 'z', 2, 'u', 'l', 2, 'm', 'l', 2, 'd', 'l', 2, 'k', 'l', 2, 'f', 'm', 2, 'n', 'm', 2, 'u', 'm', 2, 'm', 'm', 2, 'c', 'm', 2, 'k', 'm', 4, 'm', 'm', '^', '2', 4, 'c', 'm', '^', '2', 3, 'm', '^', '2', 4, 'k', 'm', '^', '2', 4, 'm', 'm', '^', '3', 4, 'c', 'm', '^', '3', 3, 'm', '^', '3', 4, 'k', 'm', '^', '3', 3, 'm', '/', 's', 5, 'm', '/', 's', '^', '2', 2, 'P', 'a', 3, 'k', 'P', 'a', 3, 'M', 'P', 'a', 3, 'G', 'P', 'a', 3, 'r', 'a', 'd', 5, 'r', 'a', 'd', '/', 's', 7, 'r', 'a', 'd', '/', 's', '^', '2', 2, 'p', 's', 2, 'n', 's', 2, 'u', 's', 2, 'm', 's', 2, 'p', 'V', 2, 'n', 'V', 2, 'u', 'V', 2, 'm', 'V', 2, 'k', 'V', 2, 'M', 'V', 2, 'p', 'W', 2, 'n', 'W', 2, 'u', 'W', 2, 'm', 'W', 2, 'k', 'W', 2, 'M', 'W', 4, 'k', 'O', 'h', 'm', 4, 'M', 'O', 'h', 'm', 4, 'a', '.', 'm', '.', 2, 'B', 'q', 2, 'c', 'c', 2, 'c', 'd', 4, 'C', '/', 'k', 'g', 3, 'C', 'o', '.', 2, 'd', 'B', 2, 'G', 'y', 2, 'h', 'a', 2, 'H', 'P', 2, 'i', 'n', 4, 'K', '.', 'K', '.', 2, 'K', 'M', 2, 'k', 't', 2, 'l', 'm', 2, 'l', 'n', 3, 'l', 'o', 'g', 2, 'l', 'x', 2, 'm', 'b', 3, 'm', 'i', 'l', 3, 'm', 'o', 'l', 2, 'p', 'H', 4, 'p', '.', 'm', '.', 3, 'P', 'P', 'M', 2, 'P', 'R', 2, 's', 'r', 2, 'S', 'v', 2, 'W', 'b', 3, 'V', '/', 'm', 3, 'A', '/', 'm', 2, '1', 'd', 2, '2', 'd', 2, '3', 'd', 2, '4', 'd', 2, '5', 'd', 2, '6', 'd', 2, '7', 'd', 2, '8', 'd', 2, '9', 'd', 3, '1', '0', 'd', 3, '1', '1', 'd', 3, '1', '2', 'd', 3, '1', '3', 'd', 3, '1', '4', 'd', 3, '1', '5', 'd', 3, '1', '6', 'd', 3, '1', '7', 'd', 3, '1', '8', 'd', 3, '1', '9', 'd', 3, '2', '0', 'd', 3, '2', '1', 'd', 3, '2', '2', 'd', 3, '2', '3', 'd', 3, '2', '4', 'd', 3, '2', '5', 'd', 3, '2', '6', 'd', 3, '2', '7', 'd', 3, '2', '8', 'd', 3, '2', '9', 'd', 3, '3', '0', 'd', 3, '3', '1', 'd', 3, 'g', 'a', 'l', 3, 'Y', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'K', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 3, 'M', 'o', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'S', 'a', 'n', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 3, 'J', 'i', ' ', 3, 'B', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'G', 'a', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'C', 'h', 'o', 'u', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'P', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'S', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'D', 'i', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'D', 'i', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'S', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'n', ' ', 4, 'J', 'i', 'u', ' ', 3, 'G', 'e', ' ', 3, 'Y', 'a', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'J', 'i', 'e', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'H', 'a', ' ', 4, 'W', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 3, 'J', 'u', ' ', 4, 'P', 'i', 'e', ' ', 3, 'F', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'N', 'a', 'i', ' ', 6, 'S', 'h', 'i', 'm', 'e', ' ', 4, 'J', 'i', 'u', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'W', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'H', 'u', ' ', 3, 'F', 'a', ' ', 3, 'L', 'e', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'P', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'H', 'u', ' ', 5, 'G', 'u', 'a', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'M', 'i', 'e', ' ', 4, 'J', 'i', 'u', ' ', 3, 'Q', 'i', ' ', 3, 'Y', 'e', ' ', 3, 'X', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'G', 'a', 'i', ' ', 4, 'D', 'i', 'u', ' ', 4, 'H', 'a', 'l', ' ', 4, 'S', 'h', 'u', ' ', 5, 'T', 'w', 'u', 'l', ' ', 4, 'S', 'h', 'i', ' ', 3, 'J', 'i', ' ', 5, 'N', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 4, 'K', 'e', 'l', ' ', 4, 'S', 'h', 'i', ' ', 3, 'O', 'l', ' ', 4, 'M', 'a', 'i', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'C', 'a', 'l', ' ', 3, 'R', 'u', ' ', 4, 'X', 'u', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'S', 'h', 'a', ' ', 3, 'N', 'a', ' ', 4, 'G', 'a', 'n', ' ', 4, 'S', 'o', 'l', ' ', 3, 'E', 'l', ' ', 5, 'C', 'w', 'u', 'l', ' ', 4, 'G', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'G', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'u', 'e', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'M', 'a', ' ', 3, 'Y', 'u', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'E', 'r', ' ', 4, 'C', 'h', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'H', 'u', ' ', 3, 'Q', 'i', ' ', 3, 'W', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'S', 'i', ' ', 4, 'S', 'u', 'i', ' ', 4, 'G', 'e', 'n', ' ', 4, 'G', 'e', 'n', ' ', 3, 'Y', 'a', ' ', 4, 'X', 'i', 'e', ' ', 3, 'Y', 'a', ' ', 3, 'Q', 'i', ' ', 3, 'Y', 'a', ' ', 3, 'J', 'i', ' ', 4, 'T', 'o', 'u', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'K', 'a', 'n', 'g', ' ', 3, 'T', 'a', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'H', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 3, 'M', 'u', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'T', 'i', 'n', 'g', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'B', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'X', 'i', 'e', ' ', 4, 'D', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 4, 'W', 'e', 'i', ' ', 4, 'R', 'e', 'n', ' ', 4, 'R', 'e', 'n', ' ', 3, 'J', 'i', ' ', 3, 'L', 'a', ' ', 5, 'W', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'R', 'e', 'n', ' ', 3, 'L', 'e', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'Z', 'e', ' ', 4, 'J', 'i', 'n', ' ', 3, 'P', 'u', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'B', 'a', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 4, 'J', 'i', 'e', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'R', 'e', 'n', 'g', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'F', 'o', ' ', 4, 'S', 'a', 'n', ' ', 4, 'L', 'u', 'n', ' ', 4, 'S', 'y', 'a', ' ', 5, 'C', 'a', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'T', 'a', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'T', 'u', 'o', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'R', 'e', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'D', 'i', ' ', 4, 'D', 'a', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 5, 'C', 'h', 'a', 'o', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'S', 'a', ' ', 3, 'Y', 'i', ' ', 3, 'M', 'u', ' ', 4, 'M', 'e', 'n', ' ', 4, 'R', 'e', 'n', ' ', 4, 'J', 'i', 'a', ' ', 5, 'C', 'h', 'a', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'P', 'i', ' ', 4, 'W', 'a', 'n', ' ', 3, 'W', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'C', 'a', 'n', 'g', ' ', 4, 'R', 'e', 'n', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 3, 'D', 'i', ' ', 5, 'F', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'P', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'D', 'u', 'n', ' ', 4, 'W', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'i', 'n', ' ', 5, 'K', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'i', ' ', 3, 'A', 'i', ' ', 3, 'W', 'u', ' ', 3, 'J', 'i', ' ', 3, 'F', 'u', ' ', 3, 'F', 'a', ' ', 4, 'X', 'i', 'u', ' ', 4, 'J', 'i', 'n', ' ', 4, 'B', 'e', 'i', ' ', 4, 'D', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'H', 'u', 'o', ' ', 4, 'H', 'u', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'u', 'i', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'e', ' ', 3, 'Y', 'a', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'n', ' ', 5, 'C', 'a', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 4, 'X', 'i', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'N', 'u', ' ', 3, 'B', 'o', ' ', 3, 'G', 'u', ' ', 3, 'N', 'i', ' ', 3, 'N', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'B', 'a', 'n', ' ', 3, 'X', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'Q', 'u', ' ', 3, 'S', 'i', ' ', 5, 'B', 'e', 'n', 'g', ' ', 3, 'S', 'i', ' ', 4, 'J', 'i', 'a', ' ', 3, 'P', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'S', 'i', ' ', 3, 'A', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 4, 'M', 'a', 'i', ' ', 4, 'D', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'B', 'u', ' ', 3, 'Q', 'u', ' ', 3, 'B', 'i', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'C', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'T', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'H', 'e', ' ', 3, 'B', 'i', ' ', 4, 'T', 'u', 'o', ' ', 4, 'S', 'h', 'e', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'F', 'o', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'K', 'o', 'u', ' ', 5, 'N', 'i', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'N', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'W', 'a', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'K', 'a', ' ', 4, 'P', 'e', 'i', ' ', 5, 'H', 'u', 'a', 'i', ' ', 3, 'H', 'e', ' ', 4, 'L', 'a', 'o', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'G', 'e', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'i', ' ', 3, 'F', 'a', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 3, 'E', 'r', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'H', 'e', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'G', 'u', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'C', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'T', 'u', 'o', ' ', 4, 'K', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'G', 'a', 'i', ' ', 4, 'L', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'h', 'i', ' ', 4, 'K', 'u', 'a', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'M', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'X', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'A', 'n', ' ', 3, 'L', 'u', ' ', 4, 'M', 'o', 'u', ' ', 3, 'E', 'r', ' ', 4, 'L', 'u', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'a', ' ', 4, 'C', 'h', 'i', ' ', 4, 'X', 'u', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'R', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'a', ' ', 4, 'J', 'i', 'a', ' ', 4, 'Z', 'a', 'i', ' ', 3, 'L', 'u', ' ', 3, 'K', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'C', 'e', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'K', 'u', 'a', 'i', ' ', 5, 'C', 'h', 'a', 'i', ' ', 5, 'N', 'i', 'n', 'g', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 3, 'W', 'u', ' ', 4, 'H', 'o', 'u', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Z', 'u', 'o', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'L', 'u', ' ', 3, 'J', 'u', ' ', 4, 'S', 'h', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'T', 'u', 'o', ' ', 3, 'B', 'o', ' ', 4, 'N', 'a', 'n', ' ', 4, 'H', 'a', 'o', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'T', 'u', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'X', 'i', ' ', 3, 'C', 'u', ' ', 2, 'E', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'X', 'u', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'K', 'u', ' ', 3, 'W', 'u', ' ', 4, 'J', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'F', 'u', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'Z', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'L', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 4, 'P', 'a', 'i', ' ', 3, 'S', 'u', ' ', 3, 'F', 'u', ' ', 3, 'X', 'i', ' ', 3, 'L', 'i', ' ', 3, 'F', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'B', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 3, 'S', 'i', ' ', 4, 'X', 'i', 'a', ' ', 4, 'X', 'i', 'n', ' ', 4, 'X', 'i', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'T', 'i', ' ', 4, 'C', 'h', 'e', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'L', 'i', 'a', ' ', 3, 'L', 'i', ' ', 4, 'L', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'u', ' ', 3, 'F', 'u', ' ', 3, 'H', 'e', ' ', 3, 'J', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'P', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'C', 'h', 'u', ' ', 4, 'F', 'e', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 3, 'A', 'n', ' ', 4, 'B', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'X', 'i', 'n', ' ', 3, 'B', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'C', 'u', 'i', ' ', 4, 'L', 'i', 'a', ' ', 4, 'W', 'a', 'n', ' ', 4, 'L', 'a', 'i', ' ', 5, 'C', 'a', 'n', 'g', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'G', 'e', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 4, 'S', 'h', 'u', ' ', 4, 'M', 'e', 'n', ' ', 4, 'D', 'a', 'o', ' ', 4, 'T', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 5, 'C', 'h', 'u', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'H', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'T', 'i', ' ', 4, 'G', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 4, 'S', 'u', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'K', 'o', 'n', 'g', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'J', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'N', 'i', ' ', 4, 'L', 'u', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'W', 'e', 'i', ' ', 4, 'L', 'u', 'o', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'L', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 4, 'B', 'e', 'n', ' ', 3, 'W', 'u', ' ', 3, 'J', 'u', ' ', 4, 'N', 'a', 'i', ' ', 4, 'C', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 3, 'Y', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'S', 'h', 'a', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'N', 'u', 'a', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'J', 'i', 'a', ' ', 4, 'J', 'i', 'e', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'R', 'u', 'o', ' ', 3, 'T', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'W', 'o', ' ', 2, 'E', ' ', 4, 'X', 'i', 'e', ' ', 4, 'C', 'h', 'e', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'K', 'a', 'n', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'C', 'h', 'a', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'B', 'e', 'i', ' ', 3, 'Y', 'e', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'C', 'i', ' ', 3, 'F', 'u', ' ', 3, 'B', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'X', 'u', 'n', ' ', 3, 'S', 'i', ' ', 5, 'D', 'u', 'a', 'n', ' ', 3, 'C', 'e', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'O', 'u', ' ', 4, 'T', 'o', 'u', ' ', 4, 'T', 'o', 'u', ' ', 4, 'B', 'e', 'i', ' ', 3, 'Z', 'a', ' ', 3, 'L', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'W', 'e', 'i', ' ', 4, 'F', 'e', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 4, 'S', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'S', 'u', ' ', 4, 'X', 'i', 'a', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 3, 'R', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'G', 'o', 'u', ' ', 3, 'M', 'a', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'o', ' ', 4, 'J', 'i', 'e', ' ', 3, 'X', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 5, 'C', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'u', ' ', 4, 'S', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'T', 'a', 'n', ' ', 4, 'S', 'u', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'F', 'a', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 4, 'D', 'a', 'i', ' ', 4, 'Z', 'a', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'B', 'i', 'n', ' ', 4, 'C', 'h', 'u', ' ', 4, 'N', 'u', 'o', ' ', 4, 'C', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 4, 'C', 'u', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'S', 'o', 'n', 'g', ' ', 3, 'A', 'o', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 4, 'C', 'o', 'u', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 4, 'S', 'h', 'a', ' ', 4, 'H', 'a', 'n', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'D', 'i', ' ', 3, 'X', 'i', ' ', 3, 'L', 'u', ' ', 4, 'B', 'e', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'M', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'T', 'u', 'i', ' ', 4, 'Z', 'u', 'n', ' ', 3, 'P', 'u', ' ', 3, 'X', 'i', ' ', 4, 'L', 'a', 'o', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'J', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'u', ' ', 5, 'S', 'e', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 2, 'E', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 3, 'B', 'o', ' ', 3, 'G', 'u', ' ', 3, 'S', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'M', 'i', 'n', ' ', 3, 'Y', 'e', ' ', 4, 'J', 'i', 'n', ' ', 4, 'J', 'i', 'a', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'P', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'A', 'i', ' ', 4, 'S', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'u', 'n', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'K', 'u', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 4, 'D', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'a', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'B', 'i', 'n', ' ', 3, 'A', 'n', ' ', 3, 'R', 'u', ' ', 4, 'T', 'a', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'C', 'h', 'a', 'i', ' ', 4, 'L', 'a', 'n', ' ', 3, 'N', 'i', ' ', 4, 'J', 'i', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'W', 'u', ' ', 5, 'N', 'i', 'n', 'g', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'N', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'L', 'i', 'e', ' ', 4, 'L', 'e', 'i', ' ', 3, 'L', 'u', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'o', ' ', 3, 'D', 'u', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'S', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'H', 'a', 'o', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'L', 'i', ' ', 5, 'T', 'e', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'R', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 4, 'H', 'u', 'i', ' ', 3, 'L', 'i', ' ', 4, 'L', 'u', 'o', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'N', 'u', 'o', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 5, 'N', 'a', 'n', 'g', ' ', 3, 'E', 'r', ' ', 3, 'W', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'D', 'u', 'i', ' ', 3, 'K', 'e', ' ', 4, 'D', 'u', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'T', 'u', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'E', 'r', ' ', 4, 'D', 'u', 'i', ' ', 3, 'E', 'r', ' ', 4, 'X', 'i', 'n', ' ', 3, 'T', 'u', ' ', 3, 'S', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'D', 'o', 'u', ' ', 4, 'F', 'e', 'n', ' ', 4, 'M', 'a', 'o', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'D', 'o', 'u', ' ', 4, 'B', 'a', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'R', 'u', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'N', 'e', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'B', 'a', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'L', 'i', 'u', ' ', 3, 'X', 'i', ' ', 4, 'L', 'a', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 3, 'J', 'u', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 6, 'P', 'p', 'w', 'u', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'M', 'a', 'o', ' ', 4, 'R', 'a', 'n', ' ', 4, 'N', 'e', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'R', 'a', 'n', ' ', 3, 'C', 'e', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 3, 'C', 'e', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'G', 'u', 'a', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'M', 'a', 'o', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'M', 'o', 'u', ' ', 4, 'G', 'o', 'u', ' ', 3, 'X', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'M', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'K', 'a', 'n', ' ', 4, 'J', 'u', 'n', ' ', 5, 'N', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'M', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'J', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'K', 'o', 'u', ' ', 4, 'L', 'a', 'm', ' ', 3, 'F', 'u', ' ', 4, 'X', 'i', 'e', ' ', 3, 'M', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'T', 'a', 'i', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'H', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 3, 'H', 'u', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 5, 'L', 'e', 'n', 'g', ' ', 4, 'P', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'M', 'i', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'L', 'i', 'e', ' ', 4, 'X', 'i', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 4, 'M', 'e', 'i', ' ', 3, 'T', 'u', ' ', 3, 'Q', 'i', ' ', 3, 'G', 'u', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'C', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'i', ' ', 5, 'C', 'a', 'n', 'g', ' ', 5, 'M', 'i', 'n', 'g', ' ', 6, 'Z', 'h', 'u', 'e', 'n', ' ', 4, 'C', 'u', 'i', ' ', 3, 'S', 'i', ' ', 4, 'D', 'u', 'o', ' ', 4, 'J', 'i', 'n', ' ', 4, 'L', 'i', 'n', ' ', 4, 'L', 'i', 'n', ' ', 5, 'N', 'i', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'D', 'u', ' ', 3, 'J', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'J', 'u', ' ', 4, 'C', 'h', 'u', ' ', 5, 'T', 'a', 'k', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'M', 'o', 'k', ' ', 3, 'C', 'i', ' ', 3, 'F', 'u', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'K', 'a', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'K', 'a', 'i', ' ', 4, 'G', 'a', 'n', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'T', 'u', ' ', 3, 'A', 'o', ' ', 4, 'C', 'h', 'u', ' ', 3, 'J', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'D', 'a', 'o', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'D', 'a', 'o', ' ', 4, 'R', 'e', 'n', ' ', 4, 'R', 'e', 'n', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'i', ' ', 4, 'K', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'C', 'u', 'n', ' ', 4, 'C', 'h', 'u', ' ', 4, 'W', 'e', 'n', ' ', 3, 'J', 'i', ' ', 4, 'D', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'a', ' ', 4, 'W', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'L', 'i', 'e', ' ', 4, 'L', 'i', 'u', ' ', 3, 'Z', 'e', ' ', 5, 'G', 'a', 'n', 'g', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'C', 'h', 'u', ' ', 3, 'Q', 'u', ' ', 3, 'J', 'u', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'P', 'a', 'n', ' ', 4, 'B', 'i', 'e', ' ', 4, 'J', 'i', 'e', ' ', 4, 'J', 'i', 'e', ' ', 4, 'B', 'a', 'o', ' ', 3, 'L', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'B', 'i', 'e', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'a', ' ', 4, 'G', 'e', 'n', ' ', 4, 'D', 'a', 'o', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 3, 'K', 'u', ' ', 4, 'D', 'u', 'o', ' ', 3, 'E', 'r', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'S', 'h', 'u', 'a', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 3, 'C', 'i', ' ', 3, 'K', 'e', ' ', 4, 'J', 'i', 'e', ' ', 4, 'G', 'u', 'i', ' ', 3, 'C', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'K', 'a', 'i', ' ', 4, 'D', 'u', 'o', ' ', 3, 'J', 'i', ' ', 3, 'T', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'L', 'o', 'u', ' ', 4, 'G', 'e', 'n', ' ', 3, 'Z', 'e', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'C', 'u', 'o', ' ', 4, 'X', 'u', 'e', ' ', 3, 'K', 'e', ' ', 3, 'L', 'a', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'C', 'u', 'o', ' ', 3, 'L', 'i', ' ', 3, 'T', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'P', 'o', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 3, 'B', 'o', ' ', 3, 'J', 'i', ' ', 4, 'D', 'u', 'o', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'B', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'J', 'u', ' ', 4, 'H', 'u', 'o', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 5, 'D', 'u', 'a', 'n', ' ', 3, 'W', 'u', ' ', 4, 'G', 'u', 'a', ' ', 3, 'F', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'G', 'e', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'K', 'a', 'i', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'T', 'u', 'a', 'n', ' ', 3, 'L', 'u', ' ', 3, 'L', 'i', ' ', 4, 'F', 'o', 'u', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'K', 'o', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'G', 'u', 'a', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'J', 'u', 'e', ' ', 4, 'H', 'u', 'a', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'P', 'i', ' ', 4, 'L', 'i', 'u', ' ', 4, 'G', 'u', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'G', 'u', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 3, 'J', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'C', 'u', 'a', 'n', ' ', 3, 'M', 'o', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'a', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 3, 'W', 'u', ' ', 4, 'M', 'a', 'i', ' ', 4, 'L', 'i', 'e', ' ', 4, 'J', 'i', 'n', ' ', 5, 'K', 'e', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'N', 'u', ' ', 4, 'J', 'i', 'e', ' ', 3, 'Q', 'u', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'M', 'i', 'a', 'o', ' ', 3, 'L', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'L', 'a', 'o', ' ', 4, 'L', 'a', 'o', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'K', 'o', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'W', 'a', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'M', 'o', 'u', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 4, 'L', 'i', 'e', ' ', 3, 'H', 'e', ' ', 4, 'S', 'h', 'i', ' ', 3, 'K', 'e', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'H', 'a', 'o', ' ', 3, 'B', 'o', ' ', 4, 'M', 'i', 'n', ' ', 4, 'C', 'h', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'K', 'e', ' ', 4, 'X', 'u', 'n', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'L', 'u', ' ', 4, 'P', 'o', 'u', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'L', 'a', 'i', ' ', 3, 'L', 'e', ' ', 4, 'K', 'a', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'X', 'u', ' ', 3, 'X', 'u', ' ', 4, 'K', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'u', 'n', ' ', 5, 'W', 'e', 'n', 'g', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'L', 'a', 'o', ' ', 3, 'M', 'u', ' ', 3, 'L', 'u', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 3, 'J', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'u', 'e', ' ', 4, 'F', 'a', 'n', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'J', 'u', ' ', 4, 'D', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'M', 'a', 'i', ' ', 4, 'X', 'u', 'n', ' ', 4, 'X', 'u', 'n', ' ', 3, 'L', 'u', ' ', 3, 'L', 'i', ' ', 4, 'C', 'h', 'e', ' ', 5, 'R', 'a', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'B', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'J', 'i', 'u', ' ', 4, 'B', 'a', 'o', ' ', 4, 'G', 'o', 'u', ' ', 3, 'W', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'M', 'w', 'u', 'n', ' ', 4, 'N', 'a', 'y', ' ', 4, 'G', 'a', 'i', ' ', 4, 'G', 'a', 'i', ' ', 4, 'B', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'J', 'u', ' ', 4, 'T', 'a', 'o', ' ', 3, 'G', 'e', ' ', 3, 'P', 'u', ' ', 3, 'A', 'n', ' ', 4, 'P', 'a', 'o', ' ', 3, 'F', 'u', ' ', 5, 'G', 'o', 'n', 'g', ' ', 3, 'D', 'a', ' ', 4, 'J', 'i', 'u', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'B', 'i', ' ', 4, 'H', 'u', 'a', ' ', 4, 'B', 'e', 'i', ' ', 4, 'N', 'a', 'o', ' ', 4, 'C', 'h', 'i', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'Z', 'a', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'K', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'H', 'u', ' ', 4, 'X', 'i', 'a', ' ', 3, 'Q', 'u', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Q', 'i', 'e', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 3, 'H', 'u', ' ', 4, 'T', 'o', 'u', ' ', 4, 'G', 'u', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'D', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'S', 'u', 'a', 'n', ' ', 3, 'D', 'u', ' ', 4, 'J', 'i', 'u', ' ', 3, 'Q', 'u', ' ', 3, 'X', 'i', ' ', 3, 'P', 'i', ' ', 3, 'Q', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'Q', 'i', 'a', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'N', 'i', ' ', 3, 'Q', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'X', 'i', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'N', 'i', 'a', 'n', ' ', 3, 'S', 'a', ' ', 3, 'Z', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'H', 'u', 'i', ' ', 4, 'B', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'X', 'i', ' ', 4, 'W', 'a', 'n', ' ', 4, 'H', 'u', 'a', ' ', 4, 'X', 'i', 'e', ' ', 4, 'W', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 3, 'Z', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'X', 'i', 'e', ' ', 4, 'D', 'a', 'n', ' ', 4, 'M', 'a', 'i', ' ', 4, 'N', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'B', 'o', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 3, 'B', 'u', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'B', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'Q', 'i', 'a', ' ', 3, 'L', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'L', 'u', ' ', 3, 'X', 'i', ' ', 4, 'G', 'u', 'a', ' ', 3, 'W', 'o', ' ', 4, 'X', 'i', 'e', ' ', 4, 'J', 'i', 'e', ' ', 4, 'J', 'i', 'e', ' ', 4, 'W', 'e', 'i', ' ', 4, 'A', 'n', 'g', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'M', 'a', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 3, 'X', 'u', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 3, 'W', 'u', ' ', 3, 'J', 'i', ' ', 2, 'E', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'X', 'i', ' ', 4, 'H', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 2, 'E', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'H', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'a', ' ', 3, 'Y', 'a', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'S', 'h', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'H', 'e', ' ', 3, 'Y', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'C', 'e', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'T', 'i', ' ', 3, 'L', 'i', ' ', 4, 'S', 'h', 'e', ' ', 4, 'H', 'o', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'Z', 'u', 'i', ' ', 4, 'C', 'u', 'o', ' ', 4, 'F', 'e', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'C', 'e', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'J', 'u', 'e', ' ', 4, 'S', 'h', 'a', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'A', 'o', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'S', 'i', ' ', 3, 'L', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'S', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'Q', 'u', ' ', 3, 'Q', 'u', ' ', 3, 'U', 'k', ' ', 4, 'L', 'e', 'i', ' ', 3, 'D', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 4, 'C', 'a', 'n', ' ', 4, 'C', 'a', 'n', ' ', 4, 'C', 'a', 'n', ' ', 4, 'C', 'a', 'n', ' ', 3, 'A', 'i', ' ', 4, 'D', 'a', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'C', 'h', 'a', ' ', 3, 'J', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'F', 'a', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 5, 'G', 'u', 'a', 'i', ' ', 3, 'B', 'a', ' ', 3, 'F', 'a', ' ', 4, 'R', 'u', 'o', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'Q', 'u', ' ', 5, 'S', 'h', 'o', 'u', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'J', 'i', 'a', ' ', 4, 'P', 'a', 'n', ' ', 4, 'S', 'o', 'u', ' ', 4, 'G', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 4, 'S', 'o', 'u', ' ', 4, 'D', 'i', 'e', ' ', 4, 'R', 'u', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'K', 'o', 'u', ' ', 3, 'G', 'u', ' ', 3, 'J', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'a', ' ', 4, 'T', 'a', 'o', ' ', 4, 'K', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'B', 'a', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'K', 'e', ' ', 4, 'T', 'a', 'i', ' ', 4, 'C', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'P', 'o', ' ', 4, 'X', 'i', 'e', ' ', 4, 'H', 'a', 'o', ' ', 3, 'S', 'i', ' ', 4, 'T', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 3, 'L', 'e', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'M', 'i', 'e', ' ', 3, 'X', 'u', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 3, 'G', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'Z', 'i', ' ', 3, 'H', 'e', ' ', 3, 'J', 'i', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'C', 'u', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'H', 'o', 'u', ' ', 3, 'L', 'i', ' ', 3, 'T', 'u', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'X', 'i', 'a', ' ', 3, 'Y', 'e', ' ', 3, 'L', 'u', ' ', 2, 'A', ' ', 3, 'M', 'a', ' ', 3, 'O', 'u', ' ', 4, 'X', 'u', 'e', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'u', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'L', 'i', 'n', ' ', 4, 'T', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'F', 'e', 'i', ' ', 3, 'B', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'J', 'i', 'e', ' ', 3, 'B', 'u', ' ', 4, 'F', 'o', 'u', ' ', 3, 'B', 'a', ' ', 4, 'D', 'u', 'n', ' ', 4, 'F', 'e', 'n', ' ', 2, 'E', ' ', 4, 'H', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'H', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'W', 'u', ' ', 3, 'W', 'u', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'N', 'e', ' ', 4, 'X', 'u', 'e', ' ', 3, 'X', 'i', ' ', 5, 'C', 'h', 'u', 'i', ' ', 4, 'D', 'o', 'u', ' ', 4, 'W', 'e', 'n', ' ', 4, 'H', 'o', 'u', ' ', 3, 'O', 'u', ' ', 3, 'W', 'u', ' ', 4, 'G', 'a', 'o', ' ', 3, 'Y', 'a', ' ', 4, 'J', 'u', 'n', ' ', 3, 'L', 'u', ' ', 2, 'E', ' ', 3, 'G', 'e', ' ', 4, 'M', 'e', 'i', ' ', 3, 'A', 'i', ' ', 3, 'Q', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'G', 'a', 'o', ' ', 3, 'F', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'N', 'e', ' ', 4, 'T', 'u', 'n', ' ', 3, 'F', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'D', 'a', 'i', ' ', 3, 'O', 'u', ' ', 3, 'L', 'i', ' ', 4, 'B', 'a', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'K', 'u', 'a', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 2, 'E', ' ', 4, 'S', 'h', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'P', 'e', 'n', ' ', 4, 'W', 'e', 'n', ' ', 3, 'N', 'i', ' ', 2, 'M', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'R', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'D', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'S', 'h', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'T', 'i', 'e', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 3, 'G', 'u', ' ', 3, 'Z', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'X', 'u', ' ', 3, 'H', 'e', ' ', 4, 'N', 'a', 'o', ' ', 4, 'X', 'i', 'a', ' ', 4, 'P', 'e', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'H', 'u', ' ', 5, 'M', 'i', 'n', 'g', ' ', 3, 'D', 'a', ' ', 3, 'Q', 'u', ' ', 3, 'J', 'u', ' ', 4, 'G', 'e', 'm', ' ', 3, 'Z', 'a', ' ', 4, 'T', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'P', 'o', 'u', ' ', 4, 'P', 'a', 'o', ' ', 3, 'B', 'i', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'H', 'e', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'H', 'e', ' ', 4, 'H', 'a', 'i', ' ', 4, 'J', 'i', 'u', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'W', 'a', ' ', 3, 'K', 'a', ' ', 3, 'G', 'u', ' ', 3, 'K', 'a', ' ', 4, 'Z', 'u', 'o', ' ', 3, 'B', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'T', 'h', 'a', ' ', 3, 'S', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'E', 'r', ' ', 2, 'E', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'L', 'i', 'e', ' ', 3, 'Z', 'i', ' ', 4, 'M', 'i', 'e', ' ', 3, 'M', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'J', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'G', 'e', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'K', 'e', ' ', 4, 'H', 'u', 'i', ' ', 4, 'K', 'u', 'a', ' ', 5, 'H', 'u', 'a', 'i', ' ', 4, 'T', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 2, 'E', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'u', ' ', 4, 'W', 'a', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'L', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'A', 'i', ' ', 4, 'P', 'i', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 3, 'W', 'a', ' ', 3, 'H', 'a', ' ', 4, 'Z', 'a', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'D', 'i', ' ', 4, 'P', 'a', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'A', 'i', ' ', 4, 'H', 'e', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 3, 'D', 'a', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'B', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'H', 'u', 'a', ' ', 6, 'S', 'a', 's', 'o', 'u', ' ', 5, 'K', 'u', 'a', 'i', ' ', 4, 'D', 'u', 'o', ' ', 3, 'J', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'M', 'o', 'u', ' ', 3, 'Y', 'o', ' ', 4, 'H', 'a', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'P', 'o', 'u', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'G', 'e', ' ', 2, 'E', ' ', 4, 'C', 'h', 'i', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'L', 'i', ' ', 3, 'N', 'a', ' ', 3, 'Z', 'u', ' ', 3, 'H', 'e', ' ', 3, 'K', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'o', ' ', 3, 'B', 'o', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'Z', 'h', 'a', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 3, 'B', 'a', ' ', 4, 'M', 'i', 'e', ' ', 3, 'L', 'e', ' ', 4, 'S', 'u', 'i', ' ', 4, 'F', 'o', 'u', ' ', 3, 'B', 'u', ' ', 4, 'H', 'a', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'o', ' ', 3, 'G', 'e', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'G', 'u', ' ', 3, 'G', 'u', ' ', 4, 'B', 'a', 'i', ' ', 4, 'H', 'a', 'n', ' ', 4, 'S', 'u', 'o', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'A', 'i', ' ', 4, 'J', 'i', 'a', ' ', 3, 'T', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'X', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'C', 'h', 'e', ' ', 3, 'W', 'u', ' ', 4, 'Z', 'a', 'o', ' ', 3, 'Y', 'a', ' ', 4, 'D', 'o', 'u', ' ', 3, 'Q', 'i', ' ', 3, 'D', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'M', 'a', ' ', 4, 'M', 'a', 'l', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'D', 'o', 'u', ' ', 4, 'K', 'e', 's', ' ', 4, 'L', 'a', 'o', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'a', ' ', 3, 'J', 'i', ' ', 4, 'Z', 'u', 'o', ' ', 3, 'W', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'H', 'u', ' ', 3, 'Q', 'i', ' ', 5, 'S', 'h', 'o', 'u', ' ', 4, 'W', 'e', 'i', ' ', 5, 'S', 'h', 'u', 'a', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'E', 'r', ' ', 3, 'L', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'A', 'n', ' ', 4, 'J', 'i', 'e', ' ', 3, 'Y', 'o', ' ', 5, 'N', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'i', ' ', 4, 'S', 'h', 'a', ' ', 3, 'X', 'i', ' ', 4, 'T', 'u', 'o', ' ', 3, 'H', 'u', ' ', 3, 'A', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'N', 'o', 'u', ' ', 4, 'K', 'e', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'D', 'i', ' ', 5, 'H', 'e', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 2, 'A', ' ', 5, 'X', 'i', 'a', 'o', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'T', 'u', 'n', ' ', 3, 'W', 'u', ' ', 4, 'W', 'e', 'n', ' ', 4, 'C', 'u', 'i', ' ', 4, 'S', 'h', 'a', ' ', 3, 'H', 'u', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'T', 'a', 'o', ' ', 4, 'D', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 3, 'Z', 'i', ' ', 3, 'B', 'i', ' ', 4, 'C', 'u', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'H', 'e', ' ', 3, 'Y', 'a', ' ', 3, 'Q', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'P', 'e', 'i', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'P', 'i', ' ', 4, 'S', 'h', 'a', ' ', 3, 'L', 'a', ' ', 3, 'Z', 'e', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'a', ' ', 3, 'P', 'a', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'S', 'e', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 4, 'G', 'u', 'o', ' ', 4, 'L', 'u', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'D', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 3, 'B', 'o', ' ', 5, 'D', 'i', 'n', 'g', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 3, 'T', 'i', ' ', 3, 'A', 'n', ' ', 4, 'J', 'i', 'u', ' ', 4, 'D', 'a', 'n', ' ', 3, 'K', 'e', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 4, 'N', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'L', 'a', ' ', 4, 'J', 'i', 'e', ' ', 4, 'H', 'o', 'u', ' ', 4, 'H', 'a', 'n', ' ', 4, 'D', 'i', 'e', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'C', 'h', 'a', 'i', ' ', 4, 'W', 'a', 'i', ' ', 3, 'R', 'e', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'W', 'o', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'H', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'H', 'e', ' ', 3, 'J', 'i', ' ', 4, 'K', 'u', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 4, 'S', 'h', 'a', ' ', 3, 'X', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'D', 'u', ' ', 4, 'N', 'i', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'S', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 4, 'P', 'e', 'n', ' ', 4, 'C', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'o', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'W', 'e', 'i', ' ', 5, 'M', 'i', 'a', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'P', 'e', 'n', ' ', 5, 'P', 'h', 'o', 's', ' ', 4, 'K', 'u', 'i', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'L', 'o', 'u', ' ', 3, 'K', 'u', ' ', 4, 'S', 'a', 'o', ' ', 4, 'H', 'u', 'o', ' ', 3, 'T', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'H', 'e', ' ', 2, 'A', ' ', 4, 'X', 'i', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'S', 'e', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'S', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'u', 'o', ' ', 3, 'M', 'a', ' ', 4, 'C', 'h', 'a', ' ', 4, 'H', 'a', 'i', ' ', 3, 'K', 'e', ' ', 3, 'T', 'a', ' ', 5, 'S', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'R', 'u', ' ', 4, 'S', 'o', 'u', ' ', 3, 'W', 'a', ' ', 3, 'J', 'i', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'G', 'e', ' ', 3, 'Z', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'L', 'u', 'o', ' ', 5, 'W', 'e', 'n', 'g', ' ', 3, 'W', 'a', ' ', 3, 'S', 'i', ' ', 4, 'C', 'h', 'i', ' ', 4, 'H', 'a', 'o', ' ', 4, 'S', 'u', 'o', ' ', 4, 'J', 'i', 'a', ' ', 4, 'H', 'a', 'i', ' ', 4, 'S', 'u', 'o', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'N', 'i', 'e', ' ', 3, 'H', 'e', ' ', 4, 'C', 'i', 's', ' ', 4, 'S', 'a', 'i', ' ', 3, 'N', 'g', ' ', 3, 'G', 'e', ' ', 3, 'N', 'a', ' ', 4, 'D', 'i', 'a', ' ', 3, 'A', 'i', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'B', 'i', ' ', 3, 'A', 'o', ' ', 3, 'A', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'C', 'u', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'M', 'o', ' ', 4, 'S', 'o', 'u', ' ', 4, 'S', 'o', 'u', ' ', 4, 'T', 'a', 'n', ' ', 3, 'D', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'K', 'a', 'i', ' ', 4, 'T', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 4, 'C', 'a', 'o', ' ', 4, 'J', 'i', 'a', ' ', 3, 'A', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'L', 'o', 'u', ' ', 3, 'G', 'a', ' ', 3, 'G', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'H', 'u', ' ', 4, 'H', 'u', 'i', ' ', 4, 'G', 'u', 'o', ' ', 3, 'O', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Z', 'e', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'X', 'u', ' ', 3, 'P', 'o', ' ', 3, 'D', 'e', ' ', 3, 'M', 'a', ' ', 3, 'M', 'a', ' ', 3, 'H', 'u', ' ', 4, 'L', 'e', 'i', ' ', 3, 'D', 'u', ' ', 3, 'G', 'a', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'S', 'a', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'M', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'H', 'u', 'a', ' ', 4, 'M', 'a', 'i', ' ', 4, 'R', 'a', 'n', ' ', 4, 'Z', 'u', 'o', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'L', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'K', 'u', 'i', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'S', 'i', ' ', 4, 'H', 'a', 'o', ' ', 3, 'F', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'X', 'i', ' ', 4, 'X', 'i', 'u', ' ', 4, 'T', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 3, 'M', 'o', ' ', 4, 'X', 'u', 'n', ' ', 2, 'E', ' ', 4, 'Z', 'u', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'C', 'u', ' ', 4, 'D', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'T', 'u', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'Y', 'e', ' ', 3, 'X', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'H', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'X', 'u', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'P', 'u', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'N', 'i', 'e', ' ', 3, 'L', 'u', ' ', 3, 'S', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'D', 'a', ' ', 4, 'D', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'J', 'i', 'n', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'H', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 2, 'E', ' ', 4, 'Z', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'A', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'P', 'e', 'n', ' ', 4, 'D', 'a', 'o', ' ', 3, 'G', 'e', ' ', 4, 'X', 'i', 'n', ' ', 4, 'D', 'u', 'n', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'S', 'i', 'n', ' ', 4, 'S', 'a', 'i', ' ', 3, 'P', 'i', ' ', 3, 'P', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'N', 'i', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'L', 'a', 'n', ' ', 3, 'T', 'a', ' ', 4, 'H', 'u', 'o', ' ', 3, 'R', 'u', ' ', 4, 'H', 'a', 'o', ' ', 4, 'X', 'i', 'a', ' ', 3, 'Y', 'a', ' ', 4, 'D', 'u', 'o', ' ', 3, 'X', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'J', 'i', ' ', 4, 'J', 'i', 'n', ' ', 4, 'H', 'a', 'o', ' ', 3, 'T', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'C', 'a', ' ', 3, 'T', 'i', ' ', 3, 'L', 'u', ' ', 4, 'H', 'u', 'i', ' ', 3, 'B', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'N', 'i', 'e', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'H', 'u', ' ', 3, 'M', 'o', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'L', 'i', ' ', 4, 'L', 'i', 'u', ' ', 5, 'H', 'a', 'a', 'i', ' ', 5, 'N', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'M', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'L', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'D', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'P', 'i', 'n', ' ', 3, 'P', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 3, 'M', 'o', ' ', 3, 'X', 'i', ' ', 4, 'D', 'u', 'o', ' ', 3, 'K', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'R', 'a', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'L', 'a', ' ', 3, 'T', 'a', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'u', 'o', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'C', 'a', ' ', 3, 'L', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'i', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'L', 'u', 'o', ' ', 5, 'N', 'a', 'n', 'g', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'S', 'u', ' ', 3, 'X', 'i', ' ', 3, 'S', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Z', 'a', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'L', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 5, 'N', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'S', 'i', ' ', 4, 'N', 'i', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'X', 'i', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'N', 'a', 'n', ' ', 5, 'T', 'u', 'a', 'n', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'D', 'u', 'n', ' ', 5, 'K', 'a', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'H', 'u', ' ', 4, 'H', 'u', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'G', 'u', 'o', ' ', 4, 'K', 'u', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 3, 'T', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'L', 'u', 'n', ' ', 4, 'G', 'u', 'o', ' ', 4, 'Q', 'u', 'n', ' ', 3, 'R', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'G', 'u', ' ', 4, 'G', 'u', 'o', ' ', 4, 'T', 'a', 'i', ' ', 4, 'G', 'u', 'o', ' ', 3, 'T', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'G', 'u', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'H', 'u', 'n', ' ', 3, 'P', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'H', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'L', 'u', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'o', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'K', 'u', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 2, 'E', ' ', 3, 'T', 'u', ' ', 3, 'T', 'u', ' ', 3, 'T', 'u', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'L', 'u', 'e', ' ', 4, 'H', 'u', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 3, 'T', 'u', ' ', 3, 'Y', 'a', ' ', 3, 'T', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'P', 'u', ' ', 3, 'L', 'u', ' ', 4, 'I', 'r', 'i', ' ', 3, 'Y', 'a', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'G', 'e', ' ', 3, 'Y', 'u', ' ', 3, 'W', 'u', ' ', 4, 'G', 'u', 'i', ' ', 3, 'P', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'D', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'Q', 'i', 'a', ' ', 7, 'A', 'k', 'u', 't', 's', 'u', ' ', 5, 'Y', 'a', 'm', 'a', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'N', 'i', 'e', ' ', 3, 'M', 'o', ' ', 3, 'J', 'i', ' ', 4, 'J', 'i', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'B', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'T', 'o', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'F', 'e', 'n', ' ', 4, 'J', 'u', 'n', ' ', 5, 'K', 'e', 'n', 'g', ' ', 4, 'T', 'u', 'n', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 4, 'B', 'e', 'n', ' ', 4, 'T', 'a', 'n', ' ', 4, 'K', 'a', 'n', ' ', 3, 'P', 'i', ' ', 4, 'Z', 'u', 'o', ' ', 5, 'K', 'e', 'n', 'g', ' ', 3, 'B', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'D', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'D', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'B', 'a', ' ', 3, 'W', 'u', ' ', 4, 'F', 'e', 'n', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'P', 'o', ' ', 4, 'P', 'a', 'n', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'K', 'u', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'T', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'T', 'u', 'o', ' ', 4, 'G', 'a', 'n', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'a', ' ', 3, 'N', 'i', ' ', 4, 'T', 'a', 'i', ' ', 3, 'P', 'i', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'F', 'o', ' ', 3, 'A', 'o', ' ', 4, 'L', 'i', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'M', 'u', ' ', 3, 'K', 'e', ' ', 4, 'G', 'o', 'u', ' ', 4, 'X', 'u', 'e', ' ', 3, 'B', 'a', ' ', 4, 'C', 'h', 'i', ' ', 4, 'C', 'h', 'e', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'F', 'u', ' ', 3, 'H', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'C', 'h', 'u', 'i', ' ', 3, 'L', 'a', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'A', 'o', ' ', 4, 'T', 'a', 'y', ' ', 4, 'P', 'a', 'o', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 3, 'K', 'e', ' ', 3, 'L', 'u', ' ', 3, 'C', 'i', ' ', 4, 'C', 'h', 'i', ' ', 4, 'L', 'e', 'i', ' ', 4, 'G', 'a', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'H', 'o', 'u', ' ', 4, 'D', 'u', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'F', 'u', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'G', 'u', 'i', ' ', 4, 'C', 'h', 'a', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'F', 'a', ' ', 4, 'G', 'o', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'D', 'i', 'e', ' ', 4, 'X', 'i', 'e', ' ', 4, 'K', 'e', 'n', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'o', 'u', ' ', 2, 'E', ' ', 3, 'H', 'a', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'K', 'u', 'a', ' ', 4, 'T', 'a', 'o', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'K', 'a', 'i', ' ', 5, 'G', 'a', 'k', 'e', ' ', 4, 'N', 'a', 'o', ' ', 3, 'A', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'P', 'e', 'i', ' ', 3, 'B', 'a', ' ', 3, 'Y', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'H', 'a', 'n', ' ', 3, 'X', 'u', ' ', 5, 'C', 'h', 'u', 'i', ' ', 4, 'C', 'e', 'n', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'A', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 4, 'J', 'i', 'a', ' ', 3, 'D', 'i', ' ', 4, 'M', 'a', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'L', 'e', 'i', ' ', 4, 'L', 'i', 'e', ' ', 3, 'B', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'G', 'o', 'm', 'i', ' ', 3, 'B', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'X', 'u', 'n', ' ', 4, 'G', 'u', 'o', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 5, 'N', 'i', 'a', 'n', ' ', 3, 'D', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'B', 'u', ' ', 3, 'Y', 'a', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'S', 'u', 'i', ' ', 3, 'P', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 3, 'J', 'u', ' ', 4, 'L', 'u', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'K', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 4, 'T', 'a', 'n', ' ', 3, 'A', 'n', ' ', 4, 'C', 'a', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'B', 'e', 'n', 'g', ' ', 4, 'K', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'D', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'P', 'e', 'i', ' ', 3, 'J', 'i', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'S', 'a', 'o', ' ', 3, 'J', 'u', ' ', 3, 'N', 'i', ' ', 3, 'K', 'u', ' ', 3, 'K', 'e', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'K', 'u', 'n', ' ', 3, 'N', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'D', 'u', 'i', ' ', 4, 'J', 'i', 'n', ' ', 5, 'G', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 2, 'E', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'G', 'u', ' ', 3, 'T', 'u', ' ', 5, 'L', 'e', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'A', 'n', ' ', 4, 'D', 'u', 'o', ' ', 4, 'N', 'a', 'o', ' ', 3, 'T', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'H', 'u', 'n', ' ', 3, 'B', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'o', ' ', 4, 'D', 'i', 'e', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'H', 'o', 'u', ' ', 4, 'B', 'a', 'o', ' ', 4, 'B', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 3, 'D', 'i', ' ', 4, 'M', 'a', 'o', ' ', 4, 'J', 'i', 'e', ' ', 5, 'R', 'u', 'a', 'n', ' ', 2, 'E', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'K', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 2, 'E', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'B', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'M', 'e', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'D', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'G', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'P', 'y', 'e', 'n', 'g', ' ', 7, 'T', 'o', 'r', 'i', 'd', 'e', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'L', 'e', 'n', 'g', ' ', 5, 'D', 'u', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 5, 'K', 'u', 'a', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'T', 'a', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'K', 'a', 'i', ' ', 3, 'S', 'u', ' ', 3, 'S', 'u', ' ', 4, 'S', 'h', 'i', ' ', 3, 'M', 'i', ' ', 3, 'T', 'a', ' ', 5, 'W', 'e', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'T', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Q', 'u', 'e', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'S', 'a', 'i', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'D', 'u', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'W', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 3, 'G', 'e', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'A', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'K', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'L', 'i', 'u', ' ', 4, 'A', 'm', 'a', ' ', 5, 'L', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'C', 'u', ' ', 3, 'L', 'u', ' ', 3, 'O', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 3, 'M', 'o', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 4, 'L', 'o', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'M', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'S', 'h', 'u', ' ', 3, 'D', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'K', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'X', 'i', ' ', 4, 'G', 'u', 'o', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 3, 'D', 'i', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'M', 'u', ' ', 4, 'C', 'u', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'T', 'a', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 3, 'X', 'u', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'B', 'a', ' ', 3, 'P', 'u', ' ', 5, 'K', 'u', 'a', 'i', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'F', 'a', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 3, 'M', 'o', ' ', 4, 'D', 'u', 'n', ' ', 4, 'D', 'u', 'n', ' ', 4, 'D', 'u', 'n', ' ', 3, 'D', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'T', 'a', 'n', ' ', 5, 'D', 'e', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'F', 'e', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 3, 'D', 'a', ' ', 3, 'Y', 'e', ' ', 4, 'S', 'h', 'o', ' ', 5, 'M', 'a', 'm', 'a', ' ', 3, 'Y', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'K', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'P', 'i', ' ', 3, 'B', 'i', ' ', 5, 'D', 'i', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'B', 'o', ' ', 4, 'T', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'J', 'u', ' ', 5, 'H', 'u', 'a', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'R', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'H', 'e', ' ', 3, 'A', 'i', ' ', 3, 'Y', 'a', ' ', 4, 'D', 'a', 'o', ' ', 4, 'H', 'a', 'o', ' ', 5, 'R', 'u', 'a', 'n', ' ', 5, 'M', 'a', 'm', 'a', ' ', 4, 'L', 'e', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'L', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'H', 'u', 'a', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'R', 'u', 'i', ' ', 3, 'L', 'i', ' ', 4, 'L', 'i', 'n', ' ', 5, 'R', 'a', 'n', 'g', ' ', 4, 'T', 'e', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 3, 'B', 'a', ' ', 4, 'S', 'h', 'i', ' ', 4, 'R', 'e', 'n', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'M', 'a', 'i', ' ', 3, 'K', 'e', ' ', 4, 'Z', 'h', 'u', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'H', 'u', ' ', 3, 'H', 'u', ' ', 4, 'K', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'H', 'u', ' ', 3, 'X', 'u', ' ', 4, 'K', 'u', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'Z', 'u', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'G', 'u', ' ', 4, 'C', 'h', 'u', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'B', 'e', 'i', ' ', 4, 'C', 'a', 'y', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'S', 'u', 'i', ' ', 4, 'Q', 'u', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'X', 'i', 'a', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 4, 'N', 'a', 'o', ' ', 4, 'X', 'i', 'a', ' ', 4, 'K', 'u', 'i', ' ', 3, 'X', 'i', ' ', 4, 'W', 'a', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 3, 'S', 'u', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 3, 'Y', 'e', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'U', 'y', 's', ' ', 4, 'G', 'o', 'u', ' ', 4, 'G', 'o', 'u', ' ', 3, 'Q', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'H', 'u', 'o', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'D', 'a', ' ', 3, 'Z', 'e', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'T', 'a', 'i', ' ', 3, 'F', 'u', ' ', 5, 'G', 'u', 'a', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'H', 'a', 'n', 'g', ' ', 4, 'G', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 4, 'B', 'e', 'n', ' ', 4, 'T', 'a', 'i', ' ', 4, 'T', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'B', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'K', 'u', 'a', ' ', 4, 'J', 'i', 'a', ' ', 4, 'D', 'u', 'o', ' ', 4, 'K', 'w', 'u', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'J', 'i', 'a', ' ', 3, 'P', 'a', ' ', 3, 'E', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'D', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'P', 'a', 'o', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'N', 'a', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 4, 'F', 'e', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'K', 'a', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'B', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'T', 'a', 'o', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'B', 'e', 'n', ' ', 3, 'X', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'X', 'u', 'n', ' ', 5, 'K', 'e', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'A', 'o', ' ', 4, 'S', 'h', 'e', ' ', 5, 'W', 'e', 'n', 'g', ' ', 4, 'P', 'a', 'n', ' ', 3, 'A', 'o', ' ', 3, 'W', 'u', ' ', 3, 'A', 'o', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'F', 'e', 'n', ' ', 4, 'H', 'u', 'o', ' ', 3, 'B', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 3, 'N', 'u', ' ', 3, 'N', 'u', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'N', 'a', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'T', 'a', ' ', 4, 'J', 'i', 'u', ' ', 4, 'N', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 4, 'H', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 3, 'J', 'i', ' ', 5, 'S', 'h', 'u', 'o', ' ', 3, 'R', 'u', ' ', 4, 'F', 'e', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 3, 'M', 'a', ' ', 4, 'D', 'a', 'n', ' ', 4, 'R', 'e', 'n', ' ', 3, 'F', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'W', 'e', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'P', 'a', ' ', 3, 'D', 'u', ' ', 3, 'J', 'i', ' ', 5, 'K', 'e', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'M', 'i', 'a', 'o', ' ', 4, 'P', 'e', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'N', 'i', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'N', 'a', ' ', 4, 'X', 'i', 'n', ' ', 4, 'F', 'e', 'n', ' ', 3, 'B', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'T', 'u', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'F', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'u', 'i', ' ', 3, 'D', 'u', ' ', 3, 'B', 'a', ' ', 3, 'N', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'D', 'a', ' ', 4, 'N', 'a', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'T', 'o', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 2, 'E', ' ', 4, 'M', 'e', 'i', ' ', 3, 'M', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'B', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'Q', 'i', 'e', ' ', 2, 'E', ' ', 3, 'H', 'e', ' ', 3, 'X', 'u', ' ', 3, 'F', 'a', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'M', 'i', 'n', ' ', 4, 'B', 'a', 'n', ' ', 3, 'M', 'u', ' ', 3, 'F', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 3, 'Z', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'R', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 3, 'G', 'u', ' ', 3, 'S', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'J', 'u', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'P', 'i', 'n', ' ', 4, 'R', 'e', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 3, 'J', 'i', ' ', 4, 'G', 'a', 'i', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 4, 'K', 'u', 'o', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'G', 'o', 'u', ' ', 3, 'M', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'J', 'u', 'n', ' ', 4, 'K', 'u', 'a', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'L', 'i', 'e', ' ', 4, 'P', 'e', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'G', 'u', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'W', 'a', ' ', 4, 'L', 'o', 'u', ' ', 3, 'Y', 'a', ' ', 4, 'R', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'L', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'S', 'u', 'o', ' ', 3, 'W', 'u', ' ', 4, 'W', 'e', 'i', ' ', 3, 'K', 'e', ' ', 4, 'L', 'a', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 5, 'D', 'i', 'n', 'g', ' ', 6, 'N', 'i', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'N', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'N', 'u', 'o', ' ', 4, 'P', 'e', 'i', ' ', 4, 'N', 'e', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'H', 'a', 'n', ' ', 3, 'D', 'i', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 2, 'E', ' ', 4, 'P', 'i', 'n', ' ', 4, 'T', 'u', 'i', ' ', 4, 'H', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'W', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'S', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'W', 'a', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'Q', 'u', ' ', 5, 'S', 'h', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'D', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'A', 'i', ' ', 2, 'E', ' ', 2, 'E', ' ', 4, 'L', 'o', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'P', 'o', 'u', ' ', 3, 'J', 'u', ' ', 3, 'P', 'o', ' ', 4, 'C', 'a', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'H', 'u', 'i', ' ', 3, 'F', 'u', ' ', 2, 'E', ' ', 3, 'W', 'o', ' ', 4, 'T', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'J', 'i', 'e', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'N', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'H', 'u', ' ', 3, 'W', 'a', ' ', 4, 'L', 'a', 'i', ' ', 3, 'B', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'F', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'L', 'u', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'K', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Y', 'a', ' ', 3, 'J', 'u', ' ', 3, 'L', 'i', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'H', 'w', 'a', ' ', 4, 'H', 'u', 'a', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'W', 'u', ' ', 4, 'N', 'a', 'n', ' ', 4, 'R', 'u', 'o', ' ', 4, 'J', 'i', 'a', ' ', 4, 'T', 'o', 'u', ' ', 3, 'X', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'W', 'e', 'i', ' ', 3, 'T', 'i', ' ', 4, 'R', 'o', 'u', ' ', 4, 'M', 'e', 'i', ' ', 4, 'D', 'a', 'n', ' ', 5, 'R', 'u', 'a', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'W', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'M', 'a', 'o', ' ', 3, 'F', 'u', ' ', 4, 'J', 'i', 'e', ' ', 5, 'D', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'A', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'W', 'e', 'i', ' ', 4, 'M', 'e', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'T', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'T', 'u', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 4, 'R', 'a', 'n', ' ', 3, 'S', 'i', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'W', 'a', ' ', 4, 'J', 'i', 'u', ' ', 3, 'H', 'u', ' ', 3, 'A', 'o', ' ', 4, 'B', 'o', 'u', ' ', 3, 'X', 'u', ' ', 4, 'T', 'o', 'u', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'P', 'i', ' ', 3, 'X', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'R', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'L', 'i', 'u', ' ', 4, 'M', 'e', 'i', ' ', 4, 'P', 'a', 'n', ' ', 3, 'A', 'o', ' ', 3, 'M', 'a', ' ', 4, 'G', 'o', 'u', ' ', 4, 'K', 'u', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'J', 'i', 'a', ' ', 4, 'S', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'M', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'J', 'i', ' ', 3, 'S', 'u', ' ', 5, 'N', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'T', 'a', 'o', ' ', 5, 'P', 'a', 'n', 'g', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'N', 'a', 'o', ' ', 4, 'B', 'a', 'o', ' ', 3, 'A', 'i', ' ', 3, 'P', 'i', ' ', 4, 'P', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 4, 'L', 'e', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'K', 'a', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'N', 'i', ' ', 3, 'L', 'i', ' ', 3, 'D', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'C', 'e', ' ', 4, 'H', 'a', 'n', ' ', 4, 'N', 'e', 'n', ' ', 4, 'L', 'a', 'o', ' ', 3, 'M', 'o', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'H', 'u', ' ', 3, 'H', 'u', ' ', 3, 'A', 'o', ' ', 4, 'N', 'e', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'M', 'a', ' ', 4, 'P', 'i', 'e', ' ', 3, 'G', 'u', ' ', 3, 'W', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'T', 'u', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'M', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'a', ' ', 4, 'G', 'u', 'i', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'X', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'H', 'u', 'a', ' ', 3, 'X', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'R', 'a', 'o', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'M', 'e', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'F', 'u', ' ', 4, 'S', 'h', 'i', ' ', 3, 'B', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'S', 'u', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'n', ' ', 5, 'N', 'i', 'a', 'o', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'a', 'n', ' ', 3, 'A', 'i', ' ', 6, 'N', 'i', 'a', 'n', 'g', ' ', 5, 'N', 'e', 'n', 'g', ' ', 3, 'M', 'a', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'J', 'i', 'n', ' ', 3, 'C', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'P', 'i', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'X', 'u', ' ', 4, 'N', 'a', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'T', 'a', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'C', 'a', 'n', ' ', 5, 'N', 'i', 'a', 'o', ' ', 3, 'W', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'K', 'a', 'k', 'a', ' ', 3, 'M', 'a', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'N', 'i', ' ', 3, 'D', 'u', ' ', 4, 'L', 'i', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 6, 'N', 'i', 'a', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'M', 'i', ' ', 3, 'L', 'i', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'L', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'J', 'u', 'e', ' ', 4, 'J', 'u', 'e', ' ', 5, 'K', 'o', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'Z', 'i', ' ', 3, 'Z', 'i', ' ', 4, 'C', 'u', 'n', ' ', 4, 'S', 'u', 'n', ' ', 3, 'F', 'u', ' ', 4, 'B', 'e', 'i', ' ', 3, 'Z', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'X', 'i', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'S', 'i', ' ', 4, 'T', 'a', 'i', ' ', 4, 'B', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'G', 'u', ' ', 3, 'N', 'u', ' ', 4, 'X', 'u', 'e', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'H', 'a', 'i', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'S', 'u', 'n', ' ', 5, 'H', 'u', 'a', 'i', ' ', 4, 'M', 'i', 'e', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 3, 'Z', 'i', ' ', 3, 'N', 'i', ' ', 3, 'F', 'u', ' ', 3, 'Z', 'i', ' ', 3, 'L', 'i', ' ', 4, 'X', 'u', 'e', ' ', 3, 'B', 'o', ' ', 3, 'R', 'u', ' ', 4, 'L', 'a', 'i', ' ', 4, 'N', 'i', 'e', ' ', 4, 'N', 'i', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'T', 'a', ' ', 4, 'G', 'u', 'i', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'S', 'h', 'o', 'u', ' ', 3, 'A', 'n', ' ', 3, 'T', 'u', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 4, 'R', 'o', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 3, 'M', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'B', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'K', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Q', 'u', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'B', 'a', 'o', ' ', 4, 'H', 'a', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'a', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'R', 'o', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'M', 'i', ' ', 4, 'K', 'o', 'u', ' ', 5, 'K', 'u', 'a', 'n', ' ', 4, 'B', 'i', 'n', ' ', 3, 'S', 'u', ' ', 4, 'C', 'a', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'J', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'J', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'M', 'i', ' ', 4, 'K', 'o', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'N', 'i', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'H', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'S', 'h', 'i', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'B', 'a', 'o', ' ', 5, 'K', 'u', 'a', 'n', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'M', 'o', ' ', 4, 'C', 'h', 'a', ' ', 3, 'J', 'u', ' ', 4, 'G', 'u', 'a', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'H', 'u', ' ', 3, 'W', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'X', 'i', 'e', ' ', 5, 'K', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'J', 'u', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'B', 'a', 'o', ' ', 4, 'Q', 'i', 'n', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'B', 'a', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'C', 'u', 'n', ' ', 4, 'D', 'u', 'i', ' ', 3, 'S', 'i', ' ', 4, 'X', 'u', 'n', ' ', 4, 'D', 'a', 'o', ' ', 3, 'L', 'u', ' ', 4, 'D', 'u', 'i', ' ', 5, 'S', 'h', 'o', 'u', ' ', 3, 'P', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'S', 'h', 'e', ' ', 3, 'K', 'e', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Z', 'u', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'S', 'h', 'u', ' ', 4, 'D', 'u', 'i', ' ', 4, 'D', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'E', 'r', ' ', 3, 'E', 'r', ' ', 3, 'E', 'r', ' ', 3, 'G', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'M', 'o', ' ', 3, 'G', 'a', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 3, 'G', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'K', 'u', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'u', ' ', 4, 'G', 'a', 'n', ' ', 3, 'G', 'u', ' ', 4, 'G', 'a', 'n', ' ', 4, 'T', 'u', 'i', ' ', 4, 'G', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'K', 'a', 'o', ' ', 3, 'N', 'i', ' ', 4, 'J', 'i', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'N', 'i', 'a', 'o', ' ', 3, 'J', 'u', ' ', 3, 'P', 'i', ' ', 5, 'C', 'e', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'B', 'i', ' ', 3, 'J', 'u', ' ', 4, 'J', 'i', 'e', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 3, 'T', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'W', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'X', 'i', 'e', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'X', 'i', ' ', 3, 'N', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'M', 'a', 'n', ' ', 2, 'E', ' ', 4, 'L', 'o', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'T', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'S', 'h', 'u', ' ', 4, 'X', 'i', 'e', ' ', 3, 'T', 'u', ' ', 3, 'L', 'u', ' ', 3, 'L', 'u', ' ', 3, 'X', 'i', ' ', 5, 'C', 'e', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'J', 'u', ' ', 4, 'X', 'i', 'e', ' ', 3, 'J', 'u', ' ', 4, 'J', 'u', 'e', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'J', 'u', 'e', ' ', 4, 'S', 'h', 'u', ' ', 3, 'X', 'i', ' ', 4, 'C', 'h', 'e', ' ', 4, 'T', 'u', 'n', ' ', 3, 'N', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'X', 'u', 'e', ' ', 5, 'N', 'a', 't', 'a', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'R', 'e', 'n', ' ', 3, 'W', 'u', ' ', 4, 'H', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'h', 'u', ' ', 4, 'S', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'B', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'A', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 3, 'W', 'u', ' ', 4, 'J', 'i', 'e', ' ', 2, 'E', ' ', 3, 'J', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'C', 'e', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'C', 'h', 'a', ' ', 4, 'J', 'i', 'e', ' ', 3, 'Q', 'u', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'A', 'o', ' ', 4, 'L', 'a', 'n', ' ', 4, 'D', 'a', 'o', ' ', 3, 'B', 'a', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'Z', 'u', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'J', 'u', ' ', 5, 'G', 'a', 'n', 'g', ' ', 3, 'K', 'e', ' ', 4, 'G', 'o', 'u', ' ', 4, 'X', 'u', 'e', ' ', 4, 'B', 'e', 'i', ' ', 3, 'L', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'J', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'X', 'i', 'u', ' ', 4, 'J', 'i', 'a', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'T', 'u', 'o', ' ', 4, 'P', 'e', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'D', 'a', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'Q', 'u', ' ', 3, 'H', 'u', ' ', 3, 'P', 'o', ' ', 4, 'M', 'i', 'n', ' ', 3, 'A', 'n', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Y', 'u', 'r', 'i', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'C', 'e', 'm', ' ', 4, 'K', 'u', 'i', ' ', 4, 'X', 'i', 'u', ' ', 4, 'M', 'a', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'X', 'u', 'e', ' ', 3, 'Y', 'i', ' ', 5, 'K', 'u', 'r', 'a', ' ', 3, 'H', 'e', ' ', 3, 'K', 'e', ' ', 4, 'L', 'u', 'o', ' ', 2, 'E', ' ', 3, 'F', 'u', ' ', 4, 'X', 'u', 'n', ' ', 4, 'D', 'i', 'e', ' ', 3, 'L', 'u', ' ', 3, 'A', 'n', ' ', 3, 'E', 'r', ' ', 4, 'G', 'a', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'M', 'u', ' ', 4, 'S', 'h', 'i', ' ', 3, 'A', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'H', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'M', 'i', ' ', 3, 'L', 'i', ' ', 3, 'J', 'i', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'S', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 2, 'E', ' ', 2, 'E', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'e', ' ', 3, 'B', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'Q', 'u', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'N', 'a', 'o', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'D', 'a', 'o', ' ', 5, 'S', 'h', 'e', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'T', 'u', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'J', 'u', 'n', ' ', 4, 'H', 'a', 'o', ' ', 4, 'X', 'i', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'K', 'a', 'n', ' ', 4, 'L', 'a', 'o', ' ', 4, 'L', 'a', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'K', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 3, 'T', 'a', ' ', 4, 'L', 'i', 'n', ' ', 4, 'H', 'u', 'a', ' ', 3, 'J', 'u', ' ', 4, 'L', 'a', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'M', 'i', 'n', ' ', 4, 'K', 'u', 'n', ' ', 4, 'K', 'u', 'n', ' ', 3, 'Z', 'u', ' ', 3, 'G', 'u', ' ', 4, 'C', 'u', 'i', ' ', 3, 'Y', 'a', ' ', 3, 'Y', 'a', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'n', ' ', 4, 'L', 'u', 'n', ' ', 5, 'L', 'e', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 4, 'D', 'u', 'o', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'G', 'u', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'P', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 5, 'B', 'e', 'n', 'g', ' ', 3, 'Z', 'u', ' ', 4, 'J', 'u', 'e', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'G', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Z', 'e', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'D', 'u', 'n', ' ', 3, 'T', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 2, 'E', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'K', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 4, 'G', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'a', ' ', 4, 'S', 'u', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 10, 'Y', 'a', 'm', 'a', 's', 'h', 'i', 'n', 'a', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 9, 'K', 'e', 'w', 'a', 's', 'h', 'i', 'i', ' ', 4, 'L', 'o', 'u', ' ', 3, 'T', 'u', ' ', 4, 'D', 'u', 'i', ' ', 3, 'X', 'i', ' ', 5, 'W', 'e', 'n', 'g', ' ', 5, 'C', 'a', 'n', 'g', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 3, 'A', 'i', ' ', 4, 'L', 'i', 'u', ' ', 3, 'W', 'u', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'Z', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'C', 'u', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'N', 'i', 'e', ' ', 4, 'C', 'u', 'o', ' ', 3, 'J', 'i', ' ', 4, 'T', 'a', 'o', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'K', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'D', 'i', 'e', ' ', 4, 'C', 'e', 'n', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'T', 'u', ' ', 4, 'L', 'o', 'u', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'A', 'o', ' ', 4, 'C', 'a', 'o', ' ', 3, 'Q', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'Z', 'u', 'i', ' ', 4, 'Z', 'u', 'i', ' ', 4, 'D', 'a', 'o', ' ', 4, 'D', 'a', 'o', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'B', 'o', ' ', 5, 'L', 'o', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'e', 'n', 'g', ' ', 3, 'B', 'o', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'L', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'n', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'D', 'u', 'o', ' ', 4, 'Z', 'u', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'J', 'u', 'e', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'u', 'e', ' ', 4, 'N', 'a', 'o', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'i', ' ', 2, 'E', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'J', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'K', 'e', ' ', 3, 'X', 'i', ' ', 3, 'D', 'i', ' ', 3, 'A', 'o', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'N', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'D', 'a', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Z', 'a', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'J', 'i', 'e', ' ', 3, 'L', 'i', ' ', 4, 'S', 'u', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'J', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'N', 'a', 'o', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'o', ' ', 5, 'C', 'u', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'N', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 5, 'C', 'h', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'L', 'i', 'e', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'Z', 'u', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'J', 'u', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'K', 'e', 'k', ' ', 3, 'W', 'u', ' ', 4, 'P', 'w', 'u', ' ', 4, 'P', 'w', 'u', ' ', 5, 'C', 'h', 'a', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'S', 'i', ' ', 3, 'B', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'i', 'n', ' ', 4, 'X', 'u', 'n', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'P', 'h', 'a', 's', ' ', 4, 'X', 'u', 'n', ' ', 4, 'J', 'i', 'n', ' ', 3, 'F', 'u', ' ', 3, 'Z', 'a', ' ', 3, 'B', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'B', 'u', ' ', 5, 'D', 'i', 'n', 'g', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 4, 'S', 'h', 'i', ' ', 4, 'F', 'e', 'n', ' ', 3, 'P', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'X', 'i', ' ', 3, 'H', 'u', ' ', 4, 'D', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 3, 'M', 'a', ' ', 4, 'P', 'e', 'i', ' ', 3, 'P', 'a', ' ', 4, 'T', 'i', 'e', ' ', 3, 'F', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'B', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'D', 'i', ' ', 3, 'M', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'Q', 'i', 'a', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'R', 'u', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 4, 'D', 'a', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Q', 'u', 'n', ' ', 3, 'X', 'i', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 4, 'G', 'u', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'a', ' ', 4, 'W', 'a', 'n', ' ', 4, 'D', 'a', 'i', ' ', 4, 'W', 'e', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'a', ' ', 3, 'Q', 'i', ' ', 3, 'Z', 'e', ' ', 4, 'G', 'u', 'o', ' ', 4, 'M', 'a', 'o', ' ', 3, 'D', 'u', ' ', 4, 'H', 'o', 'u', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'X', 'u', ' ', 3, 'M', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'W', 'o', ' ', 3, 'F', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'P', 'i', 'n', 'g', ' ', 7, 'T', 'a', 'z', 'u', 'n', 'a', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'P', 'a', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'D', 'a', 'o', ' ', 3, 'M', 'i', ' ', 4, 'J', 'i', 'a', ' ', 5, 'T', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 3, 'M', 'u', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'G', 'u', 'o', ' ', 3, 'Z', 'e', ' ', 3, 'M', 'u', ' ', 5, 'B', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'H', 'u', ' ', 4, 'F', 'a', 'n', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'B', 'i', ' ', 4, 'H', 'e', 'i', ' ', 3, 'M', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'M', 'i', 'e', ' ', 4, 'C', 'h', 'u', ' ', 4, 'J', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'J', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'P', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'Z', 'e', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'M', 'o', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'B', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'D', 'u', 'n', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 3, 'Y', 'a', ' ', 4, 'B', 'a', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'X', 'u', ' ', 3, 'L', 'u', ' ', 3, 'W', 'u', ' ', 3, 'K', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'P', 'a', 'o', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 5, 'M', 'i', 'a', 'o', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'C', 'i', ' ', 3, 'F', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'P', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'X', 'i', 'u', ' ', 3, 'D', 'u', ' ', 4, 'Z', 'u', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'T', 'u', ' ', 4, 'G', 'u', 'i', ' ', 3, 'K', 'u', ' ', 5, 'P', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'B', 'u', ' ', 5, 'D', 'i', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'L', 'a', 'i', ' ', 4, 'B', 'e', 'i', ' ', 3, 'J', 'i', ' ', 3, 'A', 'n', ' ', 4, 'S', 'h', 'u', ' ', 5, 'K', 'a', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'T', 'u', 'o', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'M', 'i', 'a', 'o', ' ', 4, 'S', 'o', 'u', ' ', 3, 'C', 'e', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 4, 'J', 'i', 'u', ' ', 3, 'H', 'e', ' ', 4, 'H', 'u', 'i', ' ', 4, 'L', 'i', 'u', ' ', 4, 'S', 'h', 'a', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'S', 'o', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'P', 'o', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'u', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'A', 'o', ' ', 4, 'K', 'u', 'o', ' ', 4, 'L', 'o', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'D', 'a', 'i', ' ', 3, 'L', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'h', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'T', 'u', ' ', 3, 'S', 'i', ' ', 4, 'X', 'i', 'n', ' ', 5, 'M', 'i', 'a', 'o', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'F', 'e', 'i', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'K', 'o', 'c', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'B', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 4, 'L', 'i', 'n', ' ', 4, 'L', 'i', 'n', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'L', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'D', 'i', ' ', 3, 'P', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'N', 'a', 'i', ' ', 4, 'H', 'u', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'K', 'a', 'i', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 3, 'J', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 3, 'B', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'E', 'r', ' ', 4, 'S', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'E', 'r', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'H', 'u', ' ', 3, 'F', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'T', 'u', 'i', ' ', 4, 'C', 'h', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'B', 'a', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'D', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 4, 'T', 'a', 'o', ' ', 3, 'F', 'u', ' ', 3, 'D', 'i', ' ', 3, 'M', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'H', 'u', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'N', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'M', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'W', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'R', 'u', 'o', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'D', 'u', 'n', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'D', 'a', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'B', 'i', ' ', 3, 'B', 'i', ' ', 4, 'S', 'h', 'e', ' ', 4, 'D', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'G', 'o', 'u', ' ', 4, 'S', 'e', 'i', ' ', 3, 'F', 'a', ' ', 3, 'B', 'i', ' ', 4, 'K', 'o', 'u', ' ', 5, 'N', 'a', 'g', 'i', ' ', 4, 'B', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'D', 'a', 'n', ' ', 4, 'K', 'u', 'o', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'M', 'i', ' ', 4, 'K', 'u', 'o', ' ', 4, 'W', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 4, 'G', 'u', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'L', 'u', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'H', 'u', 'o', ' ', 4, 'H', 'u', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'W', 'e', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'C', 'a', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'B', 'i', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'o', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 3, 'J', 'i', ' ', 5, 'P', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'e', ' ', 3, 'B', 'i', ' ', 4, 'C', 'h', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'F', 'u', ' ', 5, 'W', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'C', 'u', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 3, 'X', 'i', ' ', 4, 'X', 'u', 'n', ' ', 4, 'H', 'e', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'i', ' ', 3, 'L', 'u', ' ', 4, 'H', 'o', 'u', ' ', 3, 'W', 'a', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'X', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'T', 'u', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'L', 'a', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'D', 'e', ' ', 4, 'P', 'a', 'i', ' ', 3, 'X', 'i', ' ', 3, 'Q', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'L', 'a', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'X', 'i', 'e', ' ', 4, 'J', 'i', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'J', 'i', 'a', ' ', 5, 'B', 'i', 'a', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'X', 'u', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'P', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 3, 'X', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'C', 'h', 'i', ' ', 3, 'D', 'e', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'B', 'i', 'e', ' ', 3, 'D', 'e', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'H', 'u', 'i', ' ', 4, 'M', 'e', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'o', ' ', 3, 'Q', 'u', ' ', 4, 'X', 'i', 'n', ' ', 4, 'S', 'h', 'u', ' ', 3, 'B', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'e', ' ', 4, 'R', 'e', 'n', ' ', 4, 'D', 'a', 'o', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'G', 'a', 'i', ' ', 3, 'J', 'i', ' ', 4, 'R', 'e', 'n', ' ', 4, 'R', 'e', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 3, 'T', 'e', ' ', 3, 'T', 'e', ' ', 4, 'G', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'C', 'u', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'X', 'i', ' ', 4, 'F', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 4, 'M', 'i', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 3, 'W', 'u', ' ', 3, 'J', 'i', ' ', 3, 'W', 'u', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'e', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'W', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'C', 'u', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'T', 'a', 'i', ' ', 4, 'T', 'u', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'n', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 4, 'N', 'i', 'u', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'n', ' ', 5, 'K', 'a', 'n', 'g', ' ', 3, 'H', 'u', ' ', 4, 'K', 'a', 'i', ' ', 4, 'F', 'e', 'n', ' ', 5, 'H', 'u', 'a', 'i', ' ', 4, 'T', 'a', 'i', ' ', 5, 'S', 'o', 'n', 'g', ' ', 3, 'W', 'u', ' ', 3, 'O', 'u', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'J', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'B', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'M', 'i', 'n', ' ', 4, 'P', 'e', 'i', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'Z', 'e', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'K', 'o', 'u', ' ', 4, 'B', 'a', 'n', ' ', 3, 'N', 'u', ' ', 4, 'N', 'a', 'o', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'P', 'a', ' ', 3, 'B', 'u', ' ', 4, 'T', 'i', 'e', ' ', 3, 'G', 'u', ' ', 3, 'H', 'u', ' ', 3, 'J', 'u', ' ', 3, 'D', 'a', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'S', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'D', 'i', ' ', 4, 'D', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'T', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'F', 'u', ' ', 3, 'J', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'N', 'i', ' ', 5, 'G', 'u', 'a', 'i', ' ', 3, 'F', 'u', ' ', 3, 'X', 'i', ' ', 3, 'B', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Q', 'i', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'X', 'u', ' ', 4, 'C', 'h', 'u', ' ', 3, 'P', 'i', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 4, 'T', 'a', 'n', ' ', 8, 'K', 'o', 'r', 'a', 'e', 'r', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'D', 'u', 'i', ' ', 3, 'K', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'h', 'i', ' ', 4, 'R', 'e', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'X', 'i', ' ', 4, 'L', 'a', 'o', ' ', 5, 'H', 'e', 'n', 'g', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'M', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'X', 'i', 'e', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'o', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'D', 'i', 'e', ' ', 4, 'H', 'a', 'o', ' ', 5, 'K', 'o', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 5, 'H', 'e', 'n', 'g', ' ', 3, 'X', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'u', ' ', 2, 'S', ' ', 4, 'K', 'u', 'a', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'C', 'h', 'i', ' ', 4, 'J', 'i', 'a', ' ', 3, 'Y', 'i', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'i', ' ', 4, 'L', 'i', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'X', 'u', ' ', 4, 'C', 'h', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'N', 'u', ' ', 4, 'H', 'e', 'n', ' ', 3, 'E', 'n', ' ', 3, 'K', 'e', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'Q', 'i', 'a', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'K', 'e', 'n', ' ', 3, 'D', 'e', ' ', 4, 'H', 'u', 'i', ' ', 2, 'E', ' ', 5, 'K', 'y', 'u', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'K', 'a', 'i', ' ', 3, 'C', 'e', ' ', 4, 'N', 'a', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'P', 'i', ' ', 4, 'K', 'u', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'J', 'i', 'e', ' ', 3, 'X', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'L', 'i', 'n', ' ', 3, 'T', 'i', ' ', 4, 'H', 'a', 'n', ' ', 4, 'H', 'a', 'o', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'T', 'i', ' ', 3, 'B', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'X', 'i', ' ', 4, 'B', 'e', 'i', ' ', 4, 'M', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 3, 'W', 'u', ' ', 3, 'W', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'L', 'i', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'L', 'i', ' ', 4, 'N', 'i', 'n', ' ', 4, 'N', 'a', 'o', ' ', 2, 'E', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'W', 'u', ' ', 4, 'M', 'i', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 4, 'B', 'e', 'i', ' ', 4, 'D', 'u', 'o', ' ', 4, 'C', 'u', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'M', 'e', 'n', ' ', 3, 'L', 'i', ' ', 3, 'J', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'D', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 5, 'K', 'o', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'L', 'u', 'n', ' ', 3, 'X', 'i', ' ', 4, 'K', 'a', 'n', ' ', 4, 'K', 'u', 'n', ' ', 3, 'N', 'i', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'D', 'u', 'n', ' ', 4, 'G', 'u', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 3, 'J', 'i', ' ', 4, 'L', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'H', 'u', 'o', ' ', 3, 'H', 'e', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 3, 'T', 'i', ' ', 3, 'T', 'i', ' ', 4, 'N', 'i', 'e', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'B', 'u', ' ', 4, 'H', 'u', 'n', ' ', 3, 'X', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'H', 'u', 'i', ' ', 2, 'E', ' ', 4, 'R', 'u', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 4, 'C', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'D', 'e', ' ', 4, 'B', 'e', 'i', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'C', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 4, 'N', 'a', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 4, 'D', 'i', 'e', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'n', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'R', 'e', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'C', 'e', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'T', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'B', 'e', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'G', 'e', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'B', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 3, 'B', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'K', 'a', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 2, 'E', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'M', 'o', 'u', ' ', 3, 'K', 'e', ' ', 3, 'K', 'e', ' ', 3, 'Y', 'u', ' ', 3, 'A', 'i', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'N', 'u', 'o', ' ', 4, 'G', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'S', 'a', 'i', ' ', 5, 'L', 'e', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'K', 'u', 'i', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'S', 'u', ' ', 3, 'S', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'S', 'o', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 3, 'G', 'u', ' ', 3, 'J', 'u', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'N', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'K', 'a', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'C', 'a', 'o', ' ', 4, 'S', 'u', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'B', 'o', ' ', 4, 'K', 'a', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'H', 'u', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'S', 'a', 'o', ' ', 4, 'T', 'a', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'C', 'i', ' ', 3, 'X', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'T', 'a', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'e', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'o', ' ', 3, 'M', 'o', ' ', 3, 'M', 'u', ' ', 4, 'G', 'u', 'o', ' ', 4, 'C', 'h', 'i', ' ', 4, 'C', 'a', 'n', ' ', 4, 'C', 'a', 'n', ' ', 4, 'C', 'a', 'n', ' ', 4, 'C', 'u', 'i', ' ', 4, 'M', 'i', 'n', ' ', 3, 'T', 'e', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'A', 'o', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'J', 'i', 'u', ' ', 4, 'H', 'u', 'i', ' ', 4, 'K', 'a', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'O', 'u', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'L', 'u', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'e', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'K', 'a', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'L', 'o', 'u', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'T', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'u', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'B', 'e', 'i', ' ', 4, 'B', 'i', 'e', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 4, 'D', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'u', 'i', ' ', 4, 'D', 'u', 'i', ' ', 3, 'S', 'u', ' ', 4, 'J', 'u', 'e', ' ', 3, 'C', 'e', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'F', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 4, 'L', 'a', 'o', ' ', 4, 'L', 'a', 'o', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'W', 'u', ' ', 4, 'C', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 3, 'C', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'P', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'h', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'N', 'a', 'o', ' ', 4, 'D', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'W', 'a', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'C', 'a', 'o', ' ', 4, 'K', 'e', 'n', ' ', 4, 'X', 'i', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'A', 'o', ' ', 4, 'M', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'L', 'i', 'n', ' ', 3, 'S', 'e', ' ', 4, 'J', 'u', 'n', ' ', 5, 'H', 'u', 'a', 'i', ' ', 4, 'M', 'e', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'A', 'i', ' ', 4, 'L', 'i', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'G', 'u', 'a', ' ', 4, 'X', 'i', 'a', ' ', 4, 'C', 'h', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'D', 'a', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'A', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'D', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'M', 'o', ' ', 4, 'L', 'a', 'n', ' ', 4, 'M', 'e', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'N', 'u', 'o', ' ', 4, 'N', 'u', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'B', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'F', 'u', ' ', 4, 'L', 'i', 'u', ' ', 4, 'M', 'i', 'e', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'R', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'J', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'e', ' ', 3, 'Y', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 3, 'M', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'G', 'a', 'n', 'g', ' ', 3, 'G', 'e', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'W', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'S', 'h', 'u', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'W', 'o', ' ', 4, 'J', 'i', 'e', ' ', 3, 'G', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'J', 'i', 'a', ' ', 4, 'D', 'i', 'e', ' ', 4, 'Z', 'e', 'i', ' ', 4, 'J', 'i', 'a', ' ', 3, 'J', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'K', 'a', 'n', ' ', 3, 'J', 'i', ' ', 4, 'K', 'u', 'i', ' ', 4, 'G', 'a', 'i', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'G', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 3, 'Y', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'L', 'u', ' ', 3, 'X', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 4, 'D', 'a', 'i', ' ', 3, 'Q', 'u', ' ', 3, 'H', 'u', ' ', 3, 'H', 'u', ' ', 3, 'H', 'u', ' ', 2, 'E', ' ', 4, 'S', 'h', 'i', ' ', 3, 'L', 'i', ' ', 4, 'M', 'a', 'o', ' ', 3, 'H', 'u', ' ', 3, 'L', 'i', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'H', 'u', ' ', 4, 'F', 'e', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 2, 'T', ' ', 4, 'C', 'a', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'L', 'e', ' ', 3, 'B', 'u', ' ', 3, 'B', 'a', ' ', 3, 'D', 'a', ' ', 5, 'R', 'e', 'n', 'g', ' ', 3, 'F', 'u', ' ', 7, 'H', 'a', 'm', 'e', 'r', 'u', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'T', 'u', 'o', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'o', ' ', 5, 'K', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'K', 'u', ' ', 4, 'H', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'C', 'h', 'a', ' ', 3, 'Y', 'i', ' ', 3, 'G', 'u', ' ', 4, 'K', 'o', 'u', ' ', 3, 'W', 'u', ' ', 4, 'T', 'u', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'R', 'e', 'n', ' ', 4, 'K', 'u', 'o', ' ', 4, 'M', 'e', 'n', ' ', 4, 'S', 'a', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'N', 'i', 'u', ' ', 4, 'B', 'a', 'n', ' ', 4, 'C', 'h', 'e', ' ', 4, 'R', 'a', 'o', ' ', 3, 'X', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 3, 'Y', 'u', ' ', 3, 'F', 'u', ' ', 3, 'A', 'o', ' ', 3, 'X', 'i', ' ', 3, 'P', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Z', 'i', ' ', 2, 'E', ' ', 4, 'D', 'u', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'J', 'u', ' ', 4, 'W', 'e', 'n', ' ', 3, 'H', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'J', 'u', 'e', ' ', 3, 'B', 'a', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'W', 'a', 'n', ' ', 3, 'N', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'Z', 'h', 'u', 'a', ' ', 4, 'P', 'o', 'u', ' ', 4, 'T', 'o', 'u', ' ', 4, 'D', 'o', 'u', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'P', 'o', 'u', ' ', 3, 'F', 'u', ' ', 4, 'P', 'a', 'o', ' ', 3, 'B', 'a', ' ', 3, 'A', 'o', ' ', 3, 'Z', 'e', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'K', 'o', 'u', ' ', 4, 'L', 'u', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'H', 'u', ' ', 4, 'B', 'a', 'o', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 3, 'P', 'u', ' ', 3, 'P', 'i', ' ', 4, 'T', 'a', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'o', ' ', 3, 'H', 'e', ' ', 3, 'N', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'D', 'i', ' ', 4, 'C', 'h', 'i', ' ', 3, 'P', 'i', ' ', 3, 'Z', 'a', ' ', 3, 'M', 'o', ' ', 3, 'M', 'o', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'Y', 'a', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'Q', 'u', ' ', 4, 'M', 'i', 'n', ' ', 4, 'C', 'h', 'u', ' ', 4, 'J', 'i', 'a', ' ', 3, 'F', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'D', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'i', ' ', 3, 'M', 'u', ' ', 5, 'N', 'i', 'a', 'n', ' ', 3, 'L', 'a', ' ', 3, 'F', 'u', ' ', 4, 'P', 'a', 'o', ' ', 4, 'B', 'a', 'n', ' ', 4, 'P', 'a', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'N', 'a', ' ', 5, 'G', 'u', 'a', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 4, 'T', 'u', 'o', ' ', 3, 'B', 'a', ' ', 4, 'T', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 3, 'A', 'o', ' ', 3, 'J', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'P', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'B', 'a', 'i', ' ', 4, 'B', 'a', 'i', ' ', 3, 'D', 'i', ' ', 3, 'N', 'i', ' ', 3, 'J', 'u', ' ', 4, 'K', 'u', 'o', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 5, 'N', 'i', 'n', 'g', ' ', 3, 'B', 'o', ' ', 3, 'Z', 'e', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'H', 'e', 'n', ' ', 4, 'G', 'u', 'a', ' ', 4, 'S', 'h', 'i', ' ', 4, 'J', 'i', 'e', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'N', 'i', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 6, 'S', 'h', 'u', 'a', 'n', ' ', 4, 'C', 'u', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'K', 'a', 'o', ' ', 4, 'C', 'h', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'C', 'e', ' ', 4, 'H', 'u', 'i', ' ', 4, 'P', 'i', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'N', 'a', ' ', 3, 'B', 'o', ' ', 4, 'C', 'h', 'i', ' ', 4, 'G', 'u', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'K', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'A', 'n', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'G', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'K', 'u', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'R', 'u', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'L', 'i', 'e', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'L', 'u', ' ', 4, 'D', 'i', 'e', ' ', 3, 'W', 'a', ' ', 4, 'J', 'u', 'e', ' ', 8, 'M', 'u', 's', 'h', 'i', 'r', 'u', ' ', 3, 'J', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'L', 'u', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 5, 'Z', 'h', 'u', 'a', ' ', 3, 'T', 'a', ' ', 4, 'X', 'i', 'e', ' ', 4, 'N', 'a', 'o', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'X', 'u', 'n', ' ', 3, 'K', 'u', ' ', 3, 'A', 'i', ' ', 4, 'T', 'u', 'o', ' ', 4, 'N', 'u', 'o', ' ', 4, 'C', 'u', 'o', ' ', 3, 'B', 'o', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'T', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 4, 'S', 'u', 'o', ' ', 5, 'K', 'e', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'J', 'u', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'N', 'u', 'o', ' ', 4, 'W', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'C', 'h', 'a', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'W', 'u', ' ', 4, 'J', 'u', 'n', ' ', 4, 'J', 'i', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'K', 'u', 'n', ' ', 4, 'H', 'u', 'o', ' ', 3, 'T', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'P', 'o', 'u', ' ', 3, 'L', 'e', ' ', 3, 'B', 'a', ' ', 4, 'H', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'N', 'i', 'e', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'Z', 'e', ' ', 5, 'S', 'o', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 4, 'J', 'u', 'e', ' ', 3, 'B', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'B', 'u', ' ', 4, 'Z', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 3, 'L', 'u', ' ', 4, 'S', 'o', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'L', 'a', 'o', ' ', 4, 'S', 'u', 'n', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'D', 'a', 'o', ' ', 4, 'W', 'a', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'e', ' ', 4, 'L', 'i', 'e', ' ', 4, 'M', 'i', 'n', ' ', 4, 'M', 'e', 'n', ' ', 3, 'F', 'u', ' ', 4, 'B', 'a', 'i', ' ', 3, 'J', 'u', ' ', 4, 'D', 'a', 'o', ' ', 3, 'W', 'o', ' ', 3, 'A', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'u', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'T', 'u', ' ', 4, 'B', 'e', 'n', ' ', 3, 'N', 'a', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'N', 'u', 'o', ' ', 3, 'Z', 'u', ' ', 3, 'W', 'o', ' ', 3, 'X', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'S', 'a', 'o', ' ', 4, 'L', 'u', 'n', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'D', 'u', 'o', ' ', 5, 'S', 'h', 'o', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'P', 'o', 'u', ' ', 3, 'D', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'n', ' ', 3, 'J', 'i', ' ', 4, 'T', 'a', 'o', ' ', 4, 'Q', 'i', 'a', ' ', 3, 'Q', 'i', ' ', 4, 'P', 'a', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'a', ' ', 4, 'J', 'u', 'e', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'a', ' ', 3, 'Y', 'i', ' ', 4, 'H', 'u', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'L', 'u', 'e', ' ', 4, 'C', 'a', 'i', ' ', 4, 'T', 'a', 'n', ' ', 4, 'C', 'h', 'e', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 3, 'T', 'i', ' ', 5, 'K', 'o', 'n', 'g', ' ', 4, 'T', 'u', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'C', 'u', 'o', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'J', 'u', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'K', 'e', 'n', ' ', 4, 'B', 'a', 'i', ' ', 5, 'S', 'h', 'o', 'u', ' ', 4, 'J', 'i', 'e', ' ', 3, 'L', 'u', ' ', 4, 'G', 'u', 'o', ' ', 5, 'H', 'a', 'b', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'D', 'a', 'n', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'S', 'a', 'o', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'N', 'u', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'J', 'i', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'N', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'R', 'o', 'u', ' ', 3, 'P', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'S', 'a', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'o', ' ', 3, 'T', 'i', ' ', 4, 'N', 'i', 'e', ' ', 4, 'C', 'h', 'a', ' ', 4, 'S', 'h', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'S', 'h', 'u', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 3, 'A', 'n', ' ', 3, 'X', 'u', ' ', 3, 'Y', 'a', ' ', 3, 'W', 'o', ' ', 3, 'K', 'e', ' ', 6, 'C', 'h', 'u', 'a', 'i', ' ', 3, 'J', 'i', ' ', 3, 'T', 'i', ' ', 3, 'L', 'a', ' ', 3, 'L', 'a', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'K', 'a', 'i', ' ', 4, 'J', 'i', 'u', ' ', 4, 'J', 'i', 'u', ' ', 3, 'T', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'H', 'u', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'o', ' ', 4, 'S', 'h', 'e', ' ', 4, 'X', 'i', 'e', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 4, 'C', 'h', 'a', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'B', 'e', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'L', 'a', 'n', ' ', 4, 'W', 'e', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'G', 'e', ' ', 4, 'L', 'o', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'G', 'o', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'S', 'u', 'n', ' ', 4, 'S', 'u', 'n', ' ', 3, 'B', 'o', ' ', 4, 'C', 'h', 'u', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'B', 'e', 'n', 'g', ' ', 4, 'C', 'u', 'o', ' ', 4, 'S', 'a', 'o', ' ', 3, 'K', 'e', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'D', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'N', 'u', ' ', 4, 'X', 'i', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'S', 'o', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'G', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'u', 'o', ' ', 5, 'S', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 4, 'M', 'i', 'e', ' ', 2, 'E', ' ', 5, 'C', 'h', 'u', 'i', ' ', 4, 'N', 'u', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'T', 'a', ' ', 4, 'J', 'i', 'e', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'P', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 3, 'D', 'a', ' ', 3, 'L', 'i', ' ', 4, 'T', 'a', 'o', ' ', 3, 'H', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'W', 'a', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 2, 'E', ' ', 3, 'X', 'i', ' ', 4, 'N', 'u', 'o', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'G', 'e', ' ', 3, 'W', 'u', ' ', 3, 'E', 'n', ' ', 4, 'S', 'h', 'e', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'e', ' ', 4, 'S', 'h', 'u', ' ', 4, 'B', 'a', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'B', 'i', 'n', ' ', 4, 'S', 'o', 'u', ' ', 4, 'T', 'a', 'n', ' ', 3, 'S', 'a', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'S', 'u', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'o', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 3, 'D', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'S', 'o', 'u', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'L', 'u', 'o', ' ', 4, 'L', 'o', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'G', 'a', 'i', ' ', 3, 'H', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'a', ' ', 4, 'C', 'u', 'i', ' ', 4, 'N', 'a', 'i', ' ', 3, 'M', 'o', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'A', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'N', 'i', 'e', ' ', 4, 'M', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'K', 'o', 'u', ' ', 4, 'S', 'h', 'u', ' ', 4, 'S', 'u', 'o', ' ', 5, 'T', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'M', 'o', ' ', 3, 'M', 'o', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'K', 'e', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'o', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'G', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'L', 'u', 'e', ' ', 3, 'J', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 4, 'P', 'i', 'e', ' ', 4, 'P', 'i', 'e', ' ', 4, 'L', 'a', 'o', ' ', 4, 'D', 'u', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'R', 'u', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'u', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'S', 'a', ' ', 4, 'N', 'a', 'o', ' ', 5, 'H', 'e', 'n', 'g', ' ', 3, 'S', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'D', 'a', ' ', 4, 'Z', 'u', 'n', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'C', 'a', 'o', ' ', 4, 'D', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 4, 'C', 'h', 'e', ' ', 3, 'B', 'o', ' ', 4, 'C', 'h', 'e', ' ', 4, 'J', 'u', 'e', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'B', 'e', 'n', ' ', 3, 'F', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'B', 'o', ' ', 4, 'C', 'u', 'o', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'T', 'u', 'o', ' ', 3, 'P', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'D', 'u', 'n', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 3, 'L', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'C', 'u', 'a', 'n', ' ', 3, 'T', 'a', ' ', 4, 'H', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'u', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 4, 'K', 'u', 'o', ' ', 3, 'L', 'u', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'Z', 'e', ' ', 3, 'P', 'u', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'J', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 4, 'C', 'a', 'o', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'K', 'u', 'a', 'i', ' ', 4, 'D', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'G', 'e', ' ', 3, 'P', 'i', ' ', 3, 'B', 'o', ' ', 3, 'A', 'o', ' ', 3, 'J', 'u', ' ', 3, 'Y', 'e', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'S', 'o', 'u', ' ', 3, 'M', 'i', ' ', 3, 'J', 'i', ' ', 4, 'T', 'a', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'D', 'a', 'o', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 3, 'C', 'a', ' ', 3, 'J', 'u', ' ', 3, 'Y', 'e', ' ', 3, 'R', 'u', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'N', 'i', ' ', 3, 'H', 'u', ' ', 3, 'J', 'i', ' ', 4, 'B', 'i', 'n', ' ', 5, 'N', 'i', 'n', 'g', ' ', 3, 'G', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'K', 'u', 'o', ' ', 3, 'M', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'L', 'i', 'e', ' ', 4, 'T', 'a', 'n', ' ', 4, 'B', 'a', 'i', ' ', 4, 'S', 'o', 'u', ' ', 3, 'L', 'u', ' ', 4, 'L', 'u', 'e', ' ', 4, 'R', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'P', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 3, 'S', 'a', ' ', 4, 'S', 'h', 'u', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'N', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'J', 'u', 'n', ' ', 4, 'H', 'u', 'o', ' ', 3, 'L', 'i', ' ', 3, 'L', 'a', ' ', 4, 'H', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'L', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 5, 'R', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'C', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'S', 'h', 'e', ' ', 4, 'L', 'u', 'o', ' ', 4, 'J', 'u', 'n', ' ', 3, 'M', 'i', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 3, 'L', 'i', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'W', 'a', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'J', 'u', 'e', ' ', 4, 'L', 'a', 'n', ' ', 3, 'L', 'i', ' ', 5, 'N', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'G', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'X', 'i', 'n', ' ', 3, 'P', 'u', ' ', 4, 'S', 'u', 'i', ' ', 5, 'S', 'h', 'o', 'u', ' ', 4, 'K', 'a', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'G', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 5, 'F', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'B', 'o', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'K', 'o', 'u', ' ', 4, 'M', 'i', 'n', ' ', 3, 'W', 'u', ' ', 3, 'G', 'u', ' ', 3, 'H', 'e', ' ', 3, 'C', 'e', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'M', 'i', ' ', 4, 'C', 'h', 'u', ' ', 3, 'G', 'e', ' ', 3, 'D', 'i', ' ', 3, 'X', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'M', 'i', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'J', 'i', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'D', 'u', 'o', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'h', 'i', ' ', 3, 'A', 'o', ' ', 4, 'B', 'a', 'i', ' ', 3, 'X', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'D', 'u', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 3, 'B', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'G', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 3, 'K', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'D', 'u', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'D', 'o', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'D', 'u', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 4, 'M', 'i', 'n', ' ', 4, 'S', 'h', 'u', ' ', 3, 'A', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'A', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'D', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'F', 'u', ' ', 4, 'S', 'h', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'Q', 'u', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'S', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 3, 'L', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'W', 'e', 'n', ' ', 4, 'X', 'u', 'e', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 4, 'B', 'i', 'n', ' ', 4, 'J', 'u', 'e', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'B', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'L', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'D', 'o', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'a', ' ', 3, 'H', 'u', ' ', 4, 'X', 'i', 'e', ' ', 4, 'J', 'i', 'a', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'W', 'o', ' ', 4, 'T', 'o', 'u', ' ', 4, 'C', 'h', 'u', ' ', 4, 'J', 'i', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'F', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'D', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'S', 'i', ' ', 4, 'X', 'i', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'L', 'i', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'C', 'h', 'u', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 5, 'H', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'P', 'e', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'M', 'y', 'e', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 3, 'L', 'u', ' ', 4, 'P', 'e', 'i', ' ', 3, 'P', 'i', ' ', 4, 'L', 'i', 'u', ' ', 3, 'F', 'u', ' ', 5, 'F', 'a', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'N', 'i', ' ', 3, 'Z', 'u', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'L', 'i', 'u', ' ', 5, 'S', 'h', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'E', 's', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'F', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'F', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'W', 'u', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 4, 'H', 'u', 'o', ' ', 3, 'R', 'i', ' ', 4, 'D', 'a', 'n', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'X', 'i', 'e', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'X', 'u', 'n', ' ', 3, 'X', 'u', ' ', 3, 'X', 'u', ' ', 3, 'X', 'u', ' ', 4, 'G', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 4, 'T', 'a', 'i', ' ', 3, 'D', 'i', ' ', 3, 'X', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'M', 'i', 'n', ' ', 4, 'M', 'i', 'n', ' ', 4, 'T', 'u', 'n', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'W', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'B', 'e', 'i', ' ', 4, 'A', 'n', 'g', ' ', 3, 'Z', 'e', ' ', 4, 'B', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'K', 'u', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'H', 'u', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'o', ' ', 4, 'G', 'u', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 4, 'F', 'e', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'H', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'X', 'i', ' ', 4, 'X', 'i', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Z', 'e', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'J', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'P', 'e', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'H', 'a', 'o', ' ', 4, 'M', 'e', 'i', ' ', 4, 'Z', 'u', 'o', ' ', 3, 'M', 'o', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'H', 'u', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'F', 'e', 'i', ' ', 4, 'D', 'i', 'e', ' ', 4, 'M', 'a', 'o', ' ', 3, 'N', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'A', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'A', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 3, 'X', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'J', 'i', 'n', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'G', 'a', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'Y', 'e', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 4, 'J', 'u', 'n', ' ', 4, 'W', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'K', 'u', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'X', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'B', 'u', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'W', 'u', ' ', 4, 'H', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'a', 'o', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'W', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'P', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'X', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'X', 'i', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'A', 'n', ' ', 4, 'W', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'H', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'i', 'a', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'F', 'u', ' ', 4, 'M', 'i', 'n', ' ', 4, 'K', 'u', 'i', ' ', 3, 'H', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'D', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'M', 'a', 'o', ' ', 4, 'N', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'N', 'u', 'a', 'n', ' ', 3, 'A', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'S', 'u', 'o', ' ', 4, 'J', 'i', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'K', 'a', 'i', ' ', 4, 'G', 'a', 'o', ' ', 5, 'W', 'e', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'H', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'A', 'i', ' ', 3, 'J', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'M', 'e', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'H', 'a', 'o', ' ', 3, 'M', 'u', ' ', 3, 'M', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'N', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 4, 'B', 'a', 'o', ' ', 4, 'H', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'P', 'i', 'e', ' ', 4, 'L', 'i', 'n', ' ', 4, 'T', 'u', 'n', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'T', 'a', 'i', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'L', 'i', ' ', 4, 'T', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'F', 'e', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'H', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'S', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'B', 'a', 'o', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'a', 'n', ' ', 3, 'A', 'i', ' ', 3, 'Y', 'e', ' ', 3, 'R', 'u', ' ', 4, 'S', 'h', 'u', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'P', 'u', ' ', 3, 'L', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'D', 'i', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 3, 'L', 'u', ' ', 3, 'X', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'N', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'Q', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 3, 'H', 'u', ' ', 3, 'H', 'e', ' ', 4, 'S', 'h', 'u', ' ', 4, 'C', 'a', 'o', ' ', 4, 'C', 'a', 'o', ' ', 7, 'N', 'o', 'b', 'o', 'r', 'u', ' ', 4, 'M', 'a', 'n', ' ', 5, 'C', 'e', 'n', 'g', ' ', 5, 'C', 'e', 'n', 'g', ' ', 3, 'T', 'i', ' ', 4, 'Z', 'u', 'i', ' ', 4, 'C', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'F', 'e', 'n', ' ', 3, 'P', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'R', 'u', 'a', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'B', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 3, 'Q', 'u', ' ', 3, 'N', 'u', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'u', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'T', 'u', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'M', 'u', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 3, 'M', 'o', ' ', 4, 'B', 'e', 'n', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'R', 'e', 'n', ' ', 3, 'B', 'a', ' ', 3, 'P', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'a', 'o', ' ', 3, 'L', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'J', 'i', ' ', 4, 'J', 'i', 'u', ' ', 3, 'B', 'i', ' ', 4, 'X', 'i', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'C', 'i', ' ', 4, 'S', 'h', 'a', ' ', 6, 'E', 'b', 'u', 'r', 'i', ' ', 3, 'Z', 'a', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'a', 'n', ' ', 3, 'W', 'u', ' ', 4, 'C', 'h', 'a', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'F', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'Z', 'i', ' ', 3, 'L', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'C', 'a', 'i', ' ', 4, 'C', 'u', 'n', ' ', 4, 'R', 'e', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'T', 'u', 'o', ' ', 3, 'D', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'G', 'u', ' ', 5, 'G', 'o', 'n', 'g', ' ', 3, 'D', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'M', 'o', 'k', 'u', ' ', 5, 'S', 'o', 'm', 'a', ' ', 6, 'T', 'o', 'c', 'h', 'i', ' ', 4, 'L', 'a', 'i', ' ', 5, 'S', 'u', 'g', 'i', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'M', 'a', ' ', 5, 'M', 'i', 'a', 'o', ' ', 3, 'S', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'H', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 4, 'B', 'e', 'i', ' ', 4, 'J', 'i', 'e', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'G', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 4, 'Q', 'u', 'n', ' ', 3, 'P', 'a', ' ', 4, 'S', 'h', 'u', ' ', 4, 'H', 'u', 'a', ' ', 4, 'X', 'i', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'B', 'a', 'n', ' ', 5, 'S', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'J', 'i', 'n', ' ', 4, 'G', 'o', 'u', ' ', 3, 'J', 'i', ' ', 4, 'M', 'a', 'o', ' ', 3, 'P', 'i', ' ', 3, 'B', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'A', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'F', 'u', ' ', 4, 'N', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'H', 'u', ' ', 3, 'Y', 'a', ' ', 4, 'D', 'o', 'u', ' ', 4, 'X', 'u', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'L', 'i', 'n', ' ', 4, 'R', 'u', 'i', ' ', 2, 'E', ' ', 4, 'M', 'e', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'G', 'u', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'W', 'a', 'k', 'u', ' ', 4, 'D', 'o', 'u', ' ', 4, 'S', 'h', 'u', ' ', 4, 'Z', 'a', 'o', ' ', 3, 'L', 'i', ' ', 5, 'H', 'a', 'z', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 6, 'M', 'a', 't', 's', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'N', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'K', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'X', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'G', 'u', 'a', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'a', ' ', 4, 'J', 'i', 'a', ' ', 4, 'G', 'o', 'u', ' ', 3, 'F', 'u', ' ', 3, 'M', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 4, 'S', 'h', 'i', ' ', 4, 'N', 'i', 'e', ' ', 3, 'B', 'i', ' ', 4, 'D', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'N', 'i', ' ', 3, 'L', 'a', ' ', 3, 'H', 'e', ' ', 4, 'P', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 3, 'C', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 3, 'B', 'o', ' ', 4, 'M', 'o', 'u', ' ', 4, 'G', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'R', 'a', 'n', ' ', 4, 'R', 'o', 'u', ' ', 4, 'M', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'X', 'i', 'a', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'J', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'N', 'a', 'n', ' ', 5, 'N', 'i', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'C', 'h', 'a', ' ', 4, 'D', 'a', 'n', ' ', 3, 'G', 'u', ' ', 3, 'P', 'u', ' ', 4, 'J', 'i', 'u', ' ', 3, 'A', 'o', ' ', 3, 'F', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'B', 'o', ' ', 4, 'D', 'u', 'o', ' ', 3, 'K', 'e', ' ', 4, 'N', 'a', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'B', 'i', ' ', 4, 'L', 'i', 'u', ' ', 5, 'C', 'h', 'a', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'S', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'P', 'e', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'G', 'u', 'a', 'i', ' ', 4, 'C', 'h', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'J', 'u', 'e', ' ', 4, 'J', 'i', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'L', 'i', 'u', ' ', 4, 'M', 'e', 'i', ' ', 4, 'H', 'o', 'y', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'L', 'u', ' ', 6, 'S', 'a', 'y', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'L', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 4, 'X', 'u', 'n', ' ', 6, 'S', 'h', 'u', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'L', 'i', ' ', 3, 'S', 'u', ' ', 4, 'G', 'u', 'a', ' ', 4, 'K', 'a', 'n', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'R', 'e', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'B', 'o', ' ', 4, 'R', 'e', 'n', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'X', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'E', 'r', ' ', 3, 'E', 'r', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'F', 'a', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'K', 'a', 'o', ' ', 4, 'L', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'H', 'e', ' ', 4, 'G', 'e', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'C', 'h', 'i', ' ', 3, 'G', 'e', ' ', 4, 'Z', 'a', 'i', ' ', 5, 'L', 'u', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'J', 'i', 'e', ' ', 5, 'H', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 4, 'T', 'a', 'o', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'R', 'u', ' ', 3, 'A', 'n', ' ', 3, 'A', 'n', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'K', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'S', 'a', 'n', 'g', ' ', 5, 'S', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'J', 'i', 'u', ' ', 4, 'X', 'u', 'e', ' ', 4, 'D', 'u', 'o', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'Z', 'a', 'n', ' ', 6, 'K', 'a', 's', 'e', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'M', 'a', 's', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 4, 'N', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'H', 'u', 'a', ' ', 5, 'K', 'u', 'a', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 4, 'S', 'u', 'o', ' ', 4, 'S', 'h', 'a', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'B', 'e', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'a', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'B', 'o', ' ', 4, 'B', 'e', 'n', ' ', 3, 'F', 'u', ' ', 4, 'R', 'u', 'i', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 3, 'X', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'L', 'i', 'u', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'W', 'e', 'n', ' ', 4, 'J', 'u', 'n', ' ', 4, 'G', 'a', 'n', ' ', 3, 'C', 'u', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'M', 'e', 'i', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'D', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'T', 'u', ' ', 4, 'Z', 'a', 'o', ' ', 3, 'A', 'o', ' ', 3, 'G', 'u', ' ', 3, 'B', 'i', ' ', 3, 'D', 'i', ' ', 4, 'H', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'R', 'e', 'n', ' ', 4, 'B', 'e', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'W', 'a', 'n', ' ', 4, 'N', 'u', 'o', ' ', 4, 'J', 'i', 'a', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'L', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'C', 'e', 'n', ' ', 4, 'F', 'e', 'n', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'W', 'u', ' ', 3, 'L', 'i', ' ', 3, 'L', 'i', ' ', 4, 'D', 'o', 'u', ' ', 4, 'C', 'e', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 3, 'J', 'u', ' ', 3, 'T', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'K', 'u', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'S', 'h', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 7, 'F', 'u', 'm', 'o', 't', 'o', ' ', 8, 'S', 'h', 'i', 'k', 'i', 'm', 'i', ' ', 4, 'T', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'L', 'a', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'C', 'a', 'i', ' ', 4, 'G', 'u', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'T', 'e', ' ', 4, 'F', 'e', 'i', ' ', 4, 'P', 'a', 'i', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'P', 'o', 'u', ' ', 4, 'H', 'u', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Z', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'L', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'G', 'u', ' ', 4, 'H', 'u', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 3, 'D', 'i', ' ', 3, 'X', 'i', ' ', 4, 'F', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'e', 'n', ' ', 4, 'R', 'e', 'n', ' ', 5, 'C', 'h', 'u', 'i', ' ', 5, 'L', 'e', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'F', 'u', ' ', 3, 'K', 'e', ' ', 4, 'L', 'a', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 4, 'Z', 'o', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 4, 'F', 'e', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'N', 'i', 'e', ' ', 4, 'W', 'a', 'n', ' ', 4, 'G', 'u', 'o', ' ', 3, 'L', 'u', ' ', 4, 'H', 'a', 'o', ' ', 4, 'J', 'i', 'e', ' ', 3, 'Y', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'J', 'u', ' ', 3, 'J', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Z', 'u', 'o', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'Y', 'a', ' ', 3, 'J', 'u', ' ', 4, 'B', 'e', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'Z', 'i', ' ', 4, 'B', 'i', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'u', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 7, 'K', 'u', 'n', 'u', 'g', 'i', ' ', 7, 'M', 'o', 'm', 'i', 'j', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 3, 'X', 'i', ' ', 3, 'D', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 7, 'K', 'u', 'n', 'u', 'g', 'i', ' ', 5, 'S', 'o', 'k', 'o', ' ', 6, 'S', 'h', 'i', 'd', 'e', ' ', 4, 'L', 'u', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'K', 'e', 'n', ' ', 6, 'M', 'y', 'e', 'n', 'g', ' ', 5, 'T', 'a', 'f', 'u', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'T', 'u', 'o', ' ', 4, 'S', 'e', 'n', ' ', 4, 'D', 'u', 'o', ' ', 3, 'Y', 'e', ' ', 4, 'F', 'o', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'H', 'e', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'W', 'o', ' ', 5, 'P', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'H', 'u', 'o', ' ', 3, 'X', 'u', ' ', 4, 'R', 'u', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'L', 'a', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'B', 'e', 'n', ' ', 4, 'H', 'u', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'K', 'u', 'i', ' ', 3, 'S', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 4, 'T', 'u', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'M', 'u', ' ', 4, 'M', 'a', 'o', ' ', 4, 'C', 'h', 'u', ' ', 3, 'H', 'u', ' ', 3, 'H', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'L', 'e', 'n', 'g', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'N', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'M', 'e', 'i', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'P', 'i', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 3, 'J', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'Y', 'e', ' ', 4, 'C', 'h', 'u', ' ', 5, 'S', 'h', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'o', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'M', 'e', 'i', ' ', 3, 'D', 'i', ' ', 3, 'J', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'K', 'a', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'R', 'o', 'u', ' ', 5, 'H', 'e', 'n', 'g', ' ', 4, 'L', 'o', 'u', ' ', 3, 'L', 'e', ' ', 6, 'H', 'a', 'z', 'o', 'u', ' ', 8, 'K', 'a', 't', 's', 'u', 'r', 'a', ' ', 4, 'P', 'i', 'n', ' ', 5, 'M', 'u', 'r', 'o', ' ', 4, 'G', 'a', 'i', ' ', 4, 'T', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'L', 'u', ' ', 3, 'J', 'u', ' ', 7, 'S', 'a', 'k', 'a', 'k', 'i', ' ', 3, 'P', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'J', 'i', 'a', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'N', 'a', 'i', ' ', 3, 'M', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'G', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'T', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'a', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 5, 'M', 'i', 'n', 'g', ' ', 3, 'S', 'u', ' ', 4, 'J', 'i', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'J', 'i', 'e', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'M', 'a', ' ', 4, 'S', 'u', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'C', 'u', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'L', 'i', 'u', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 3, 'S', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'T', 'a', ' ', 3, 'K', 'e', ' ', 3, 'X', 'i', ' ', 3, 'G', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'K', 'a', 'o', ' ', 4, 'G', 'a', 'o', ' ', 4, 'S', 'u', 'n', ' ', 4, 'P', 'a', 'n', ' ', 4, 'T', 'a', 'o', ' ', 3, 'G', 'e', ' ', 4, 'X', 'u', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'N', 'o', 'u', ' ', 3, 'J', 'i', ' ', 5, 'S', 'h', 'u', 'o', ' ', 4, 'G', 'o', 'u', ' ', 5, 'C', 'h', 'u', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'a', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'i', ' ', 4, 'M', 'e', 'i', ' ', 3, 'X', 'u', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'G', 'a', 'o', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 6, 'H', 'a', 's', 'h', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 6, 'K', 'a', 's', 'h', 'i', ' ', 4, 'O', 'r', 'i', ' ', 4, 'B', 'i', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'X', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'o', ' ', 4, 'G', 'a', 'i', ' ', 4, 'G', 'a', 'i', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'a', ' ', 3, 'C', 'u', ' ', 4, 'S', 'e', 'n', ' ', 4, 'C', 'u', 'i', ' ', 5, 'B', 'e', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'H', 'u', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'H', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'N', 'i', 'e', ' ', 4, 'G', 'a', 'o', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'C', 'a', 'o', ' ', 4, 'M', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 3, 'D', 'i', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'L', 'e', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'X', 'i', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'F', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'J', 'i', ' ', 4, 'S', 'u', 'o', ' ', 4, 'L', 'e', 'i', ' ', 3, 'L', 'u', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 3, 'M', 'i', ' ', 4, 'L', 'o', 'u', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'S', 'u', ' ', 3, 'K', 'e', ' ', 4, 'S', 'h', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'L', 'u', ' ', 4, 'J', 'i', 'u', ' ', 4, 'S', 'h', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'S', 'h', 'u', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'M', 'e', 'n', ' ', 3, 'M', 'o', ' ', 5, 'N', 'i', 'a', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'S', 'h', 'a', ' ', 3, 'X', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 7, 'H', 'o', 'k', 'u', 's', 'o', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'T', 'a', 'r', 'a', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'E', 'r', ' ', 4, 'X', 'i', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'P', 'u', ' ', 4, 'S', 'h', 'u', ' ', 4, 'H', 'u', 'a', ' ', 4, 'K', 'u', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Z', 'u', 'n', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'X', 'u', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'F', 'a', ' ', 4, 'G', 'a', 'n', ' ', 3, 'M', 'o', ' ', 3, 'W', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'N', 'a', 'o', ' ', 4, 'L', 'i', 'n', ' ', 4, 'L', 'i', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'R', 'u', 'n', ' ', 4, 'F', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'T', 'u', 'o', ' ', 4, 'L', 'a', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'S', 'h', 'u', 'n', ' ', 4, 'T', 'u', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'J', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'S', 'u', ' ', 4, 'J', 'u', 'e', ' ', 4, 'J', 'u', 'e', ' ', 4, 'T', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'J', 'i', ' ', 4, 'N', 'u', 'o', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'T', 'u', 'o', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'R', 'u', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'R', 'a', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 4, 'C', 'e', 'n', ' ', 3, 'G', 'u', ' ', 4, 'L', 'i', 'u', ' ', 4, 'L', 'a', 'o', ' ', 4, 'G', 'a', 'o', ' ', 4, 'C', 'h', 'u', ' ', 5, 'Z', 'u', 's', 'a', ' ', 5, 'N', 'u', 'd', 'e', ' ', 3, 'C', 'a', ' ', 4, 'S', 'a', 'n', ' ', 3, 'J', 'i', ' ', 4, 'D', 'o', 'u', ' ', 5, 'S', 'h', 'o', 'u', ' ', 3, 'L', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'T', 'a', ' ', 4, 'S', 'h', 'u', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'X', 'i', ' ', 4, 'S', 'u', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 3, 'J', 'u', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'P', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'B', 'o', ' ', 3, 'B', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'u', ' ', 5, 'Z', 'h', 'u', 'a', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'J', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'J', 'i', 'a', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'D', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'S', 'h', 'e', ' ', 4, 'L', 'i', 'n', ' ', 7, 'K', 'u', 'n', 'u', 'g', 'i', ' ', 4, 'C', 'h', 'a', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'T', 'a', 'o', ' ', 4, 'T', 'a', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'T', 'o', 'a', 'n', ' ', 4, 'B', 'i', 'n', ' ', 4, 'H', 'u', 'o', ' ', 3, 'J', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'M', 'i', ' ', 5, 'N', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'G', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'E', 'r', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'M', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'G', 'u', 'i', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'J', 'i', ' ', 4, 'K', 'u', 'i', ' ', 3, 'P', 'o', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'C', 'h', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 4, 'L', 'e', 'i', ' ', 3, 'S', 'a', ' ', 3, 'L', 'u', ' ', 3, 'L', 'i', ' ', 5, 'C', 'u', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'M', 'i', 'e', ' ', 4, 'H', 'u', 'i', ' ', 3, 'O', 'u', ' ', 3, 'L', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'G', 'a', 'o', ' ', 3, 'D', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'F', 'e', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'S', 'o', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'T', 'a', 'm', 'o', ' ', 4, 'C', 'h', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'L', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'J', 'i', 'e', ' ', 2, 'E', ' ', 3, 'S', 'u', ' ', 5, 'H', 'u', 'a', 'i', ' ', 4, 'N', 'i', 'e', ' ', 3, 'Y', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'L', 'a', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'K', 'w', 'i', ' ', 3, 'J', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'N', 'o', 'n', 'g', ' ', 3, 'B', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'J', 'u', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'e', ' ', 4, 'W', 'e', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 5, 'C', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'L', 'u', 'o', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 3, 'E', 'm', ' ', 4, 'L', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'L', 'e', 'i', ' ', 3, 'L', 'i', ' ', 3, 'B', 'a', ' ', 5, 'N', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 6, 'T', 's', 'u', 'k', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'C', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'O', 'u', ' ', 3, 'X', 'u', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'C', 'h', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'K', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'u', 'e', ' ', 3, 'X', 'i', ' ', 3, 'X', 'u', ' ', 4, 'X', 'i', 'a', ' ', 3, 'Y', 'u', ' ', 5, 'K', 'u', 'a', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'K', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'u', 'o', ' ', 3, 'X', 'i', ' ', 3, 'A', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'H', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'K', 'u', 'a', 'n', ' ', 4, 'K', 'a', 'n', ' ', 5, 'K', 'u', 'a', 'n', ' ', 4, 'K', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'a', ' ', 4, 'G', 'u', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'X', 'i', 'n', ' ', 4, 'X', 'i', 'e', ' ', 3, 'Y', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'G', 'e', ' ', 3, 'W', 'u', ' ', 4, 'T', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 3, 'O', 'u', ' ', 3, 'H', 'u', ' ', 3, 'T', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'P', 'e', 'n', ' ', 3, 'X', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'X', 'u', ' ', 3, 'X', 'i', ' ', 4, 'S', 'e', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'K', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'C', 'h', 'u', 'o', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'C', 'i', ' ', 3, 'B', 'u', ' ', 3, 'W', 'u', ' ', 3, 'Q', 'i', ' ', 3, 'B', 'u', ' ', 3, 'B', 'u', ' ', 4, 'W', 'a', 'i', ' ', 3, 'J', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 3, 'S', 'e', ' ', 4, 'C', 'h', 'i', ' ', 3, 'S', 'e', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'L', 'i', ' ', 4, 'C', 'u', 'o', ' ', 3, 'Y', 'u', ' ', 3, 'L', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'D', 'a', 'i', ' ', 4, 'D', 'a', 'i', ' ', 3, 'S', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'M', 'o', ' ', 3, 'M', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'M', 'o', ' ', 3, 'C', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'X', 'u', ' ', 4, 'X', 'u', 'n', ' ', 4, 'S', 'h', 'u', ' ', 4, 'C', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'Q', 'i', 'a', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'S', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'F', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Y', 'e', ' ', 4, 'C', 'a', 'n', ' ', 4, 'H', 'u', 'n', ' ', 4, 'D', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'e', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'W', 'e', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'B', 'i', 'n', ' ', 3, 'T', 'i', ' ', 4, 'J', 'i', 'n', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'C', 'u', ' ', 4, 'H', 'u', 'i', ' ', 5, 'C', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'D', 'a', 'n', ' ', 3, 'D', 'u', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'B', 'i', 'n', ' ', 3, 'D', 'u', ' ', 8, 'T', 's', 'u', 'k', 'u', 's', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 3, 'O', 'u', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'h', 'a', ' ', 4, 'Q', 'u', 'e', ' ', 3, 'K', 'e', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'J', 'u', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 3, 'G', 'u', ' ', 4, 'Q', 'u', 'e', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'O', 'u', ' ', 4, 'H', 'u', 'i', ' ', 5, 'D', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'W', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'M', 'u', ' ', 4, 'M', 'e', 'i', ' ', 4, 'M', 'e', 'i', ' ', 3, 'A', 'i', ' ', 4, 'Z', 'u', 'o', ' ', 3, 'D', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'B', 'i', ' ', 3, 'B', 'i', ' ', 3, 'B', 'i', ' ', 3, 'P', 'i', ' ', 3, 'P', 'i', ' ', 3, 'B', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 3, 'P', 'u', ' ', 8, 'M', 'u', 's', 'h', 'i', 'r', 'u', ' ', 4, 'J', 'i', 'a', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'S', 'a', 'i', ' ', 3, 'M', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'X', 'u', 'n', ' ', 3, 'E', 'r', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'M', 'u', ' ', 4, 'H', 'a', 'o', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'D', 'o', 'u', ' ', 8, 'M', 'u', 's', 'h', 'i', 'r', 'u', ' ', 4, 'T', 'a', 'n', ' ', 4, 'P', 'e', 'i', ' ', 3, 'J', 'u', ' ', 4, 'D', 'u', 'o', ' ', 4, 'C', 'u', 'i', ' ', 3, 'B', 'i', ' ', 4, 'S', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 4, 'S', 'u', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'T', 'u', 'o', ' ', 3, 'H', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'T', 'a', ' ', 4, 'S', 'a', 'n', ' ', 3, 'L', 'u', ' ', 3, 'M', 'u', ' ', 3, 'L', 'i', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'P', 'u', ' ', 4, 'L', 'u', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'S', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 3, 'Q', 'u', ' ', 4, 'D', 'i', 'e', ' ', 4, 'S', 'h', 'i', ' ', 3, 'D', 'i', ' ', 4, 'M', 'i', 'n', ' ', 4, 'J', 'u', 'e', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'P', 'i', 'e', ' ', 4, 'N', 'a', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'D', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 3, 'R', 'i', ' ', 4, 'N', 'e', 'i', ' ', 3, 'F', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'X', 'i', ' ', 4, 'H', 'a', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'A', 'n', ' ', 3, 'Y', 'a', ' ', 3, 'K', 'e', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'D', 'a', 'n', ' ', 3, 'L', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'S', 'h', 'u', 'i', ' ', 4, 'S', 'a', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'D', 'a', 'n', 'g', ' ', 10, 'S', 'h', 'i', 't', 'a', 'm', 'i', 'z', 'u', ' ', 3, 'L', 'e', ' ', 3, 'N', 'i', ' ', 4, 'T', 'u', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'B', 'i', 'n', ' ', 3, 'Z', 'e', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'C', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'h', 'a', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'W', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'D', 'a', 'i', ' ', 3, 'X', 'i', ' ', 4, 'T', 'u', 'o', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'Q', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'P', 'a', 'i', ' ', 4, 'H', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'W', 'u', ' ', 4, 'X', 'u', 'n', ' ', 3, 'S', 'i', ' ', 3, 'R', 'u', ' ', 5, 'G', 'o', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 3, 'W', 'u', ' ', 7, 'T', 's', 'u', 'c', 'h', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'M', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'R', 'u', 'i', ' ', 4, 'J', 'u', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'T', 'a', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'J', 'i', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 4, 'W', 'e', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 5, 'H', 'a', 'n', 'g', ' ', 5, 'N', 'i', 'o', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'F', 'e', 'n', ' ', 3, 'X', 'u', ' ', 3, 'X', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'W', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'H', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'D', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'D', 'u', 'n', ' ', 3, 'H', 'u', ' ', 4, 'H', 'u', 'o', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'M', 'u', ' ', 4, 'R', 'o', 'u', ' ', 4, 'M', 'e', 'i', ' ', 3, 'T', 'a', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'W', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'S', 'h', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'P', 'e', 'i', ' ', 4, 'P', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'Z', 'a', ' ', 4, 'G', 'o', 'u', ' ', 4, 'L', 'i', 'u', ' ', 4, 'M', 'e', 'i', ' ', 3, 'Z', 'e', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'O', 'u', ' ', 3, 'L', 'i', ' ', 4, 'L', 'u', 'n', ' ', 5, 'C', 'a', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 3, 'H', 'u', ' ', 3, 'M', 'o', ' ', 4, 'M', 'e', 'i', ' ', 4, 'S', 'h', 'u', ' ', 3, 'J', 'u', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'T', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 3, 'H', 'e', ' ', 3, 'L', 'i', ' ', 3, 'M', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'F', 'a', ' ', 4, 'F', 'e', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'G', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'S', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 3, 'J', 'u', ' ', 4, 'X', 'i', 'e', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'i', 'a', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'B', 'o', ' ', 4, 'H', 'u', 'i', ' ', 3, 'M', 'i', ' ', 4, 'B', 'e', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'C', 'h', 'u', ' ', 3, 'L', 'e', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'G', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 3, 'F', 'a', ' ', 4, 'M', 'a', 'o', ' ', 3, 'S', 'i', ' ', 3, 'H', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'C', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 3, 'S', 'u', ' ', 5, 'N', 'i', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'P', 'a', 'o', ' ', 3, 'B', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'S', 'i', ' ', 3, 'N', 'i', ' ', 3, 'J', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'Z', 'h', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'X', 'u', 'e', ' ', 3, 'F', 'u', ' ', 4, 'P', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 4, 'T', 'a', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'B', 'e', 'n', 'g', ' ', 4, 'X', 'u', 'e', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'B', 'o', ' ', 4, 'X', 'i', 'e', ' ', 3, 'P', 'o', ' ', 3, 'Z', 'e', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Z', 'u', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'H', 'o', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'L', 'i', 'e', ' ', 3, 'S', 'i', ' ', 3, 'J', 'i', ' ', 3, 'E', 'r', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'F', 'u', ' ', 3, 'S', 'a', ' ', 4, 'S', 'u', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'W', 'u', ' ', 3, 'X', 'i', ' ', 4, 'K', 'a', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 3, 'A', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'M', 'o', 'u', ' ', 4, 'L', 'e', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'M', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 3, 'M', 'o', ' ', 4, 'W', 'e', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'X', 'i', 'e', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'X', 'u', ' ', 5, 'S', 'h', 'u', 'o', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'T', 'a', 'o', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'J', 'u', ' ', 3, 'E', 'r', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'R', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 3, 'W', 'a', ' ', 4, 'Q', 'i', 'a', ' ', 4, 'P', 'a', 'i', ' ', 3, 'W', 'u', ' ', 3, 'Q', 'u', ' ', 4, 'L', 'i', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'i', 'a', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'C', 'e', ' ', 4, 'P', 'a', 'l', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'J', 'i', ' ', 4, 'L', 'i', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'H', 'u', 'n', ' ', 3, 'H', 'u', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 4, 'J', 'i', 'n', ' ', 4, 'L', 'i', 'e', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'J', 'u', 'n', ' ', 4, 'H', 'a', 'n', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'X', 'i', ' ', 3, 'B', 'o', ' ', 4, 'D', 'o', 'u', ' ', 4, 'W', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'P', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 4, 'H', 'a', 'o', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 3, 'L', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'F', 'u', ' ', 3, 'W', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'L', 'a', 'o', ' ', 4, 'H', 'a', 'i', ' ', 4, 'J', 'i', 'n', ' ', 4, 'J', 'i', 'a', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'W', 'e', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 4, 'S', 'u', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'P', 'e', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'T', 'u', ' ', 4, 'K', 'u', 'n', ' ', 4, 'P', 'i', 'n', ' ', 4, 'N', 'i', 'e', ' ', 4, 'H', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'e', ' ', 5, 'N', 'i', 'a', 'n', ' ', 3, 'T', 'u', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 2, 'E', ' ', 3, 'S', 'u', ' ', 4, 'T', 'u', 'n', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'C', 'e', 'n', ' ', 3, 'T', 'i', ' ', 3, 'L', 'i', ' ', 5, 'S', 'h', 'u', 'i', ' ', 3, 'S', 'i', ' ', 4, 'L', 'e', 'i', ' ', 5, 'S', 'h', 'u', 'i', ' ', 4, 'T', 'a', 'o', ' ', 3, 'D', 'u', ' ', 4, 'L', 'a', 'o', ' ', 4, 'L', 'a', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'W', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'D', 'i', ' ', 4, 'R', 'u', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 3, 'S', 'e', ' ', 3, 'F', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'o', 'u', ' ', 6, 'S', 'h', 'u', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 5, 'C', 'h', 'u', 'o', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 5, 'K', 'o', 'n', 'g', ' ', 3, 'W', 'o', ' ', 4, 'H', 'a', 'n', ' ', 4, 'T', 'u', 'o', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'H', 'e', ' ', 3, 'W', 'o', ' ', 3, 'J', 'u', ' ', 4, 'G', 'a', 'n', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 3, 'T', 'a', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'D', 'e', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'G', 'u', ' ', 4, 'G', 'u', 'o', ' ', 4, 'H', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'H', 'a', 'o', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 3, 'Q', 'i', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 3, 'L', 'u', ' ', 4, 'N', 'a', 'o', ' ', 3, 'J', 'u', ' ', 4, 'T', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'P', 'i', ' ', 4, 'D', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'N', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'L', 'u', ' ', 4, 'G', 'a', 'n', ' ', 3, 'M', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'L', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'C', 'u', 'i', ' ', 3, 'Q', 'u', ' ', 5, 'H', 'u', 'a', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'N', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'W', 'a', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'L', 'a', 'i', ' ', 4, 'H', 'u', 'n', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'M', 'i', ' ', 4, 'B', 'e', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'n', ' ', 3, 'R', 'e', ' ', 4, 'F', 'e', 'i', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'K', 'e', ' ', 3, 'J', 'i', ' ', 4, 'S', 'h', 'e', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 7, 'S', 'h', 'i', 'b', 'u', 'i', ' ', 3, 'L', 'u', ' ', 3, 'Z', 'i', ' ', 3, 'D', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 3, 'P', 'i', ' ', 5, 'T', 'a', 'n', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'R', 'o', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'N', 'u', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 3, 'D', 'u', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'B', 'o', ' ', 3, 'W', 'o', ' ', 3, 'W', 'o', ' ', 3, 'D', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'W', 'e', 'n', ' ', 3, 'R', 'u', ' ', 4, 'X', 'i', 'e', ' ', 3, 'C', 'e', ' ', 4, 'W', 'e', 'i', ' ', 3, 'G', 'e', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'M', 'i', ' ', 3, 'K', 'e', ' ', 4, 'M', 'a', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'H', 'u', 'n', ' ', 4, 'N', 'a', 'i', ' ', 4, 'K', 'u', 'i', ' ', 4, 'S', 'h', 'i', ' ', 2, 'E', ' ', 4, 'P', 'a', 'i', ' ', 4, 'M', 'e', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'M', 'e', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'C', 'o', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'C', 'a', 'n', ' ', 5, 'T', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'M', 'o', ' ', 3, 'X', 'u', ' ', 3, 'J', 'i', ' ', 4, 'P', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'H', 'u', ' ', 5, 'F', 'e', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'J', 'i', 'e', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'B', 'i', ' ', 4, 'M', 'i', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'T', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'S', 'u', 'e', 'i', ' ', 4, 'J', 'i', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'o', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'u', 'i', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'N', 'i', 'e', ' ', 3, 'Z', 'i', ' ', 4, 'W', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'M', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 6, 'R', 'a', 't', 's', 'u', ' ', 4, 'K', 'u', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'X', 'u', ' ', 3, 'L', 'u', ' ', 4, 'G', 'u', 'i', ' ', 4, 'G', 'a', 'i', ' ', 3, 'P', 'o', ' ', 4, 'J', 'i', 'n', ' ', 4, 'G', 'u', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'S', 'u', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'K', 'e', ' ', 4, 'T', 'a', 'i', ' ', 3, 'D', 'a', ' ', 3, 'W', 'a', ' ', 4, 'L', 'i', 'u', ' ', 4, 'G', 'o', 'u', ' ', 4, 'S', 'a', 'o', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'S', 'h', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'L', 'u', 'n', ' ', 3, 'M', 'a', ' ', 3, 'P', 'u', ' ', 4, 'W', 'e', 'i', ' ', 3, 'L', 'i', ' ', 4, 'C', 'a', 'i', ' ', 3, 'W', 'u', ' ', 3, 'X', 'i', ' ', 4, 'W', 'e', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'Z', 'e', ' ', 4, 'S', 'h', 'i', ' ', 3, 'S', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'S', 'o', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'X', 'i', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 3, 'S', 'u', ' ', 3, 'S', 'u', ' ', 3, 'N', 'i', ' ', 3, 'T', 'a', ' ', 4, 'S', 'h', 'i', ' ', 3, 'R', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'P', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 4, 'C', 'h', 'u', ' ', 5, 'P', 'a', 'n', 'g', ' ', 5, 'W', 'e', 'n', 'g', ' ', 5, 'C', 'a', 'n', 'g', ' ', 4, 'M', 'i', 'e', ' ', 3, 'H', 'e', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'H', 'a', 'o', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'H', 'u', 'a', ' ', 3, 'G', 'e', ' ', 3, 'Z', 'i', ' ', 4, 'T', 'a', 'o', ' ', 5, 'T', 'e', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 3, 'B', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'H', 'u', 'i', ' ', 4, 'G', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'G', 'a', 'o', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'S', 'h', 'e', ' ', 4, 'M', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'L', 'u', ' ', 4, 'L', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'B', 'i', 'n', ' ', 4, 'T', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'S', 'o', 'u', ' ', 3, 'H', 'u', ' ', 3, 'B', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'K', 'o', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'D', 'i', ' ', 3, 'M', 'i', ' ', 3, 'A', 'o', ' ', 3, 'L', 'u', ' ', 3, 'H', 'u', ' ', 3, 'H', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'G', 'u', 'n', ' ', 4, 'M', 'a', 'n', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'P', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'a', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'X', 'i', ' ', 3, 'J', 'i', ' ', 3, 'L', 'u', ' ', 3, 'L', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 4, 'G', 'u', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'L', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'G', 'a', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'C', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'Q', 'u', 'n', ' ', 5, 'T', 'u', 'a', 'n', ' ', 3, 'O', 'u', ' ', 5, 'T', 'e', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 3, 'X', 'i', ' ', 3, 'M', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'M', 'o', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'W', 'a', ' ', 3, 'L', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'M', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 3, 'X', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'K', 'u', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'C', 'u', 'i', ' ', 3, 'T', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 4, 'S', 'h', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'X', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'P', 'i', ' ', 4, 'J', 'u', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'P', 'o', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'W', 'u', ' ', 3, 'P', 'a', ' ', 3, 'J', 'i', ' ', 4, 'P', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'L', 'u', ' ', 3, 'X', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'D', 'u', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'M', 'i', 'n', ' ', 4, 'R', 'u', 'n', ' ', 3, 'S', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'D', 'i', ' ', 4, 'W', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'X', 'u', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'Y', 'i', 'e', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'T', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'S', 'a', 'n', ' ', 4, 'H', 'e', 'i', ' ', 3, 'B', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'P', 'u', ' ', 4, 'L', 'i', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'S', 'e', ' ', 3, 'S', 'e', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'a', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'L', 'a', 'o', ' ', 4, 'C', 'h', 'e', ' ', 4, 'G', 'a', 'n', ' ', 4, 'C', 'u', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 3, 'S', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'L', 'i', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'H', 'a', 'o', ' ', 3, 'H', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'O', 'k', 'i', ' ', 4, 'L', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'L', 'i', 'n', ' ', 4, 'M', 'i', 'n', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 3, 'Z', 'e', ' ', 4, 'X', 'i', 'e', ' ', 3, 'Y', 'u', ' ', 3, 'L', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'X', 'u', 'e', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'K', 'u', 'a', 'i', ' ', 4, 'C', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 3, 'A', 'o', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'P', 'i', ' ', 3, 'J', 'u', ' ', 3, 'T', 'a', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'J', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'G', 'u', 'o', ' ', 4, 'J', 'i', 'n', ' ', 4, 'F', 'e', 'n', ' ', 3, 'S', 'e', ' ', 3, 'J', 'i', ' ', 4, 'S', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'C', 'h', 'u', ' ', 3, 'T', 'a', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'L', 'a', 'i', ' ', 4, 'B', 'i', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'M', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'u', ' ', 3, 'M', 'i', ' ', 5, 'N', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'P', 'i', ' ', 3, 'J', 'i', ' ', 4, 'H', 'a', 'o', ' ', 3, 'R', 'u', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'W', 'o', ' ', 4, 'T', 'a', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'D', 'u', 'i', ' ', 3, 'C', 'i', ' ', 4, 'H', 'u', 'o', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 4, 'J', 'u', 'n', ' ', 3, 'A', 'i', ' ', 3, 'P', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'W', 'e', 'i', ' ', 4, 'B', 'i', 'n', ' ', 3, 'G', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'H', 'a', 'm', 'a', ' ', 4, 'K', 'u', 'o', ' ', 4, 'F', 'e', 'i', ' ', 5, 'B', 'o', 'k', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'L', 'u', 'o', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'L', 'u', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'S', 'i', ' ', 4, 'J', 'i', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'D', 'u', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'P', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'M', 'o', ' ', 4, 'L', 'i', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'P', 'u', ' ', 3, 'S', 'e', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'G', 'u', ' ', 4, 'B', 'i', 'n', ' ', 4, 'H', 'u', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'H', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'X', 'i', 'e', ' ', 5, 'H', 'u', 'a', 'i', ' ', 4, 'H', 'a', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'L', 'a', 'i', ' ', 4, 'D', 'u', 'i', ' ', 4, 'F', 'a', 'n', ' ', 3, 'H', 'u', ' ', 4, 'L', 'a', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'M', 'i', ' ', 3, 'J', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 4, 'L', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'D', 'a', 'i', ' ', 5, 'R', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'e', ' ', 4, 'L', 'e', 'i', ' ', 4, 'L', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'F', 'a', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'H', 'a', 'o', ' ', 6, 'H', 'y', 'e', 'n', 'g', ' ', 3, 'S', 'a', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'M', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'H', 'a', 'o', ' ', 3, 'B', 'a', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'L', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 5, 'N', 'a', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'H', 'u', 'o', ' ', 3, 'S', 'i', ' ', 4, 'M', 'i', 'e', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'H', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'Z', 'a', 'o', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'X', 'i', 'e', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'C', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 4, 'N', 'i', 'u', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'n', ' ', 3, 'P', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'u', ' ', 5, 'C', 'h', 'u', 'i', ' ', 3, 'P', 'i', ' ', 4, 'K', 'a', 'i', ' ', 4, 'P', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'K', 'a', 'i', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'M', 'u', ' ', 5, 'C', 'h', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'G', 'u', 'i', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'T', 'u', 'n', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'D', 'a', ' ', 4, 'X', 'i', 'a', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'K', 'e', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'F', 'u', ' ', 3, 'B', 'a', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'J', 'u', ' ', 4, 'T', 'a', 'n', ' ', 4, 'P', 'a', 'o', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'P', 'a', 'o', ' ', 4, 'T', 'a', 'i', ' ', 4, 'T', 'a', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'H', 'u', ' ', 5, 'S', 'h', 'u', 'o', ' ', 4, 'L', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'X', 'u', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'L', 'i', 'e', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'X', 'i', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'W', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'X', 'u', 'e', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'K', 'a', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 4, 'X', 'i', 'a', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'P', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'H', 'u', 'i', ' ', 4, 'K', 'a', 'o', ' ', 4, 'F', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'Y', 'e', ' ', 4, 'H', 'u', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 3, 'R', 'e', ' ', 3, 'X', 'i', ' ', 3, 'F', 'u', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'e', ' ', 3, 'P', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 4, 'H', 'a', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'H', 'u', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'H', 'u', ' ', 3, 'X', 'i', ' ', 4, 'S', 'h', 'u', ' ', 3, 'H', 'e', ' ', 4, 'X', 'u', 'n', ' ', 3, 'K', 'u', ' ', 4, 'J', 'u', 'e', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'J', 'u', 'n', ' ', 3, 'D', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'J', 'i', ' ', 3, 'W', 'u', ' ', 4, 'H', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'M', 'e', 'n', ' ', 3, 'J', 'u', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'B', 'e', 'i', ' ', 4, 'F', 'e', 'n', ' ', 4, 'L', 'i', 'n', ' ', 4, 'K', 'u', 'n', ' ', 4, 'H', 'u', 'n', ' ', 4, 'T', 'u', 'n', ' ', 3, 'X', 'i', ' ', 4, 'C', 'u', 'i', ' ', 3, 'W', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'J', 'u', ' ', 3, 'F', 'u', ' ', 3, 'W', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'P', 'i', 'n', 'g', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'R', 'u', 'o', ' ', 3, 'X', 'i', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'X', 'i', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'u', 'e', ' ', 3, 'Y', 'u', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'R', 'a', 'n', ' ', 3, 'P', 'i', ' ', 3, 'G', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'o', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'H', 'e', ' ', 4, 'K', 'u', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'a', ' ', 4, 'H', 'u', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'W', 'e', 'i', ' ', 5, 'T', 'u', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'X', 'i', ' ', 5, 'N', 'u', 'a', 'n', ' ', 5, 'N', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'M', 'e', 'i', ' ', 4, 'S', 'h', 'a', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'e', ' ', 4, 'X', 'i', 'n', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'R', 'o', 'u', ' ', 4, 'M', 'e', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'X', 'u', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'S', 'u', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'L', 'i', 'e', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'G', 'a', 'o', ' ', 4, 'G', 'u', 'a', ' ', 4, 'B', 'a', 'o', ' ', 3, 'H', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'X', 'i', 'a', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'G', 'o', 'u', ' ', 4, 'T', 'u', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 2, 'N', ' ', 3, 'B', 'o', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 3, 'X', 'i', ' ', 3, 'W', 'u', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'H', 'e', ' ', 3, 'H', 'e', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 4, 'N', 'a', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'X', 'u', 'n', ' ', 3, 'M', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'W', 'e', 'n', ' ', 5, 'R', 'o', 'n', 'g', ' ', 8, 'O', 'o', 'z', 'u', 't', 's', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'L', 'i', 'u', ' ', 3, 'X', 'i', ' ', 3, 'B', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'L', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'L', 'o', 'u', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'H', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'A', 'o', ' ', 4, 'W', 'e', 'i', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'H', 'a', 'n', ' ', 3, 'O', 'u', ' ', 3, 'R', 'e', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 5, 'C', 'u', 'a', 'n', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'C', 'h', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'R', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'Z', 'u', 'n', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'D', 'u', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'F', 'e', 'n', ' ', 3, 'S', 'i', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 4, 'L', 'i', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'F', 'e', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'M', 'e', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'u', 'e', ' ', 4, 'L', 'a', 'n', ' ', 4, 'T', 'a', 'i', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'C', 'a', 'n', ' ', 4, 'S', 'u', 'i', ' ', 3, 'X', 'i', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'X', 'i', 'e', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'i', 'e', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'H', 'u', 'i', ' ', 6, 'T', 'a', 't', 's', 'u', ' ', 5, 'N', 'u', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 3, 'R', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'K', 'a', 'o', ' ', 4, 'X', 'u', 'n', ' ', 4, 'J', 'i', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'H', 'e', ' ', 4, 'L', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 3, 'M', 'o', ' ', 4, 'B', 'a', 'o', ' ', 4, 'R', 'u', 'o', ' ', 3, 'L', 'u', ' ', 3, 'L', 'a', ' ', 3, 'A', 'o', ' ', 4, 'X', 'u', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'o', ' ', 3, 'L', 'i', ' ', 3, 'L', 'u', ' ', 4, 'J', 'u', 'e', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'X', 'i', 'e', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 5, 'R', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'L', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'e', ' ', 3, 'M', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'C', 'u', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'h', 'u', 'a', ' ', 13, 'T', 's', 'u', 'm', 'e', 'k', 'a', 'n', 'm', 'u', 'r', 'i', ' ', 3, 'P', 'a', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'P', 'a', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'A', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'J', 'u', 'e', ' ', 4, 'J', 'u', 'e', ' ', 3, 'F', 'u', ' ', 3, 'Y', 'e', ' ', 3, 'B', 'a', ' ', 4, 'D', 'i', 'e', ' ', 3, 'Y', 'e', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'Z', 'u', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'E', 'r', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'G', 'e', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'D', 'i', 'e', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 4, 'P', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'P', 'a', 'i', ' ', 3, 'D', 'u', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'T', 'o', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'D', 'i', 'e', ' ', 5, 'B', 'a', 'n', 'g', ' ', 3, 'B', 'o', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'D', 'u', ' ', 3, 'Y', 'a', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'N', 'i', 'u', ' ', 8, 'U', 's', 'h', 'i', 'h', 'e', 'n', ' ', 4, 'P', 'i', 'n', ' ', 4, 'J', 'i', 'u', ' ', 4, 'M', 'o', 'u', ' ', 4, 'T', 'u', 'o', ' ', 3, 'M', 'u', ' ', 4, 'L', 'a', 'o', ' ', 4, 'R', 'e', 'n', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'M', 'a', 'o', ' ', 3, 'M', 'u', ' ', 5, 'G', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'G', 'e', ' ', 4, 'B', 'e', 'i', ' ', 3, 'S', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'G', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'G', 'e', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'M', 'u', ' ', 3, 'D', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 3, 'T', 'e', ' ', 3, 'X', 'i', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'K', 'e', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'G', 'u', ' ', 3, 'X', 'i', ' ', 3, 'L', 'i', ' ', 3, 'L', 'i', ' ', 4, 'P', 'o', 'u', ' ', 3, 'J', 'i', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'B', 'e', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'R', 'u', 'n', ' ', 3, 'D', 'u', ' ', 3, 'J', 'u', ' ', 4, 'J', 'i', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'n', ' ', 3, 'K', 'e', ' ', 3, 'J', 'u', ' ', 4, 'K', 'a', 'o', ' ', 4, 'C', 'h', 'u', ' ', 3, 'X', 'i', ' ', 4, 'B', 'e', 'i', ' ', 4, 'L', 'u', 'o', ' ', 4, 'J', 'i', 'e', ' ', 3, 'M', 'a', ' ', 4, 'S', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'L', 'i', ' ', 4, 'D', 'u', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 7, 'I', 'k', 'e', 'n', 'i', 'e', ' ', 3, 'L', 'i', ' ', 3, 'D', 'u', ' ', 4, 'L', 'i', 'e', ' ', 3, 'P', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'B', 'a', 'o', ' ', 3, 'X', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'K', 'u', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 3, 'B', 'a', ' ', 4, 'F', 'a', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'J', 'i', ' ', 4, 'C', 'a', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'A', 'n', ' ', 4, 'J', 'i', 'e', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 3, 'M', 'a', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'K', 'a', 'n', 'g', ' ', 3, 'B', 'o', ' ', 4, 'H', 'o', 'u', ' ', 3, 'Y', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'N', 'i', 'u', ' ', 3, 'D', 'i', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'M', 'u', ' ', 4, 'B', 'e', 'i', ' ', 3, 'P', 'i', ' ', 3, 'J', 'u', ' ', 3, 'N', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'P', 'a', 'o', ' ', 4, 'X', 'i', 'a', ' ', 4, 'T', 'u', 'o', ' ', 3, 'H', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 3, 'P', 'i', ' ', 3, 'N', 'i', ' ', 3, 'A', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'G', 'o', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'J', 'u', ' ', 4, 'D', 'a', 'n', ' ', 3, 'P', 'o', ' ', 3, 'G', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'N', 'i', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'H', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'H', 'e', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'X', 'u', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'T', 'a', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'o', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'L', 'a', 'o', ' ', 3, 'D', 'u', ' ', 4, 'X', 'i', 'a', ' ', 4, 'S', 'h', 'i', ' ', 4, 'H', 'u', 'a', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'S', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'B', 'i', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'X', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'X', 'i', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'S', 'u', 'a', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'B', 'e', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'S', 'h', 'a', ' ', 3, 'L', 'i', ' ', 4, 'H', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'P', 'a', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'B', 'a', ' ', 3, 'Q', 'i', ' ', 3, 'N', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'L', 'a', 'i', ' ', 3, 'X', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'K', 'u', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'G', 'u', 'o', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'M', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'C', 'a', 'i', ' ', 3, 'C', 'u', ' ', 4, 'S', 'h', 'e', ' ', 5, 'K', 'a', 'r', 'i', ' ', 4, 'C', 'e', 'n', ' ', 4, 'L', 'u', 'o', ' ', 3, 'H', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'W', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'M', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'T', 'u', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 4, 'N', 'a', 'o', ' ', 4, 'X', 'i', 'e', ' ', 4, 'J', 'i', 'a', ' ', 4, 'H', 'o', 'u', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'M', 'e', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'S', 'u', 'n', ' ', 3, 'B', 'o', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'a', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'S', 'o', 'u', ' ', 3, 'M', 'a', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'D', 'a', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'H', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'o', ' ', 4, 'M', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'M', 'u', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'A', 'o', ' ', 3, 'A', 'o', ' ', 4, 'H', 'a', 'o', ' ', 4, 'C', 'u', 'i', ' ', 4, 'F', 'e', 'n', ' ', 4, 'J', 'u', 'e', ' ', 3, 'B', 'i', ' ', 3, 'B', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'P', 'u', ' ', 4, 'L', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'u', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'S', 'w', 'u', ' ', 4, 'T', 'o', 'n', ' ', 3, 'X', 'i', ' ', 3, 'G', 'e', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'D', 'u', ' ', 4, 'H', 'u', 'i', ' ', 5, 'K', 'u', 'a', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 3, 'T', 'a', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'P', 'i', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'N', 'o', 'u', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'L', 'i', 'e', ' ', 4, 'N', 'a', 'o', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'o', 'u', ' ', 3, 'L', 'u', ' ', 3, 'T', 'a', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'M', 'i', ' ', 5, 'R', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'N', 'a', 'o', ' ', 4, 'L', 'u', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'J', 'u', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'o', ' ', 3, 'Z', 'i', ' ', 3, 'L', 'u', ' ', 3, 'L', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'S', 'u', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'G', 'a', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'L', 'e', ' ', 3, 'B', 'a', ' ', 3, 'J', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'D', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 4, 'J', 'i', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'M', 'a', ' ', 5, 'G', 'o', 'n', 'g', ' ', 3, 'W', 'u', ' ', 3, 'F', 'u', ' ', 4, 'W', 'e', 'n', ' ', 4, 'J', 'i', 'e', ' ', 3, 'Y', 'a', ' ', 4, 'F', 'e', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'B', 'e', 'n', 'g', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'J', 'u', 'e', ' ', 4, 'W', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 4, 'D', 'a', 'n', ' ', 3, 'P', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'A', 'n', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'B', 'o', ' ', 3, 'C', 'i', ' ', 4, 'G', 'o', 'u', ' ', 4, 'J', 'i', 'a', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'P', 'o', ' ', 3, 'C', 'i', ' ', 3, 'K', 'e', ' ', 4, 'R', 'a', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'Z', 'u', ' ', 4, 'J', 'i', 'a', ' ', 4, 'M', 'i', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'L', 'i', 'u', ' ', 3, 'B', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'J', 'u', 'e', ' ', 3, 'F', 'a', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'L', 'i', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'X', 'i', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'X', 'u', ' ', 4, 'L', 'u', 'o', ' ', 3, 'S', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'K', 'e', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'B', 'a', 'o', ' ', 3, 'E', 'r', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'X', 'i', 'a', ' ', 5, 'H', 'e', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 3, 'X', 'u', ' ', 4, 'B', 'a', 'n', ' ', 4, 'P', 'e', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'E', 'i', ' ', 4, 'H', 'u', 'n', ' ', 4, 'W', 'e', 'n', ' ', 2, 'E', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'T', 'i', ' ', 3, 'W', 'u', ' ', 3, 'W', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'J', 'u', 'n', ' ', 4, 'M', 'e', 'i', ' ', 4, 'B', 'e', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'u', 'o', ' ', 4, 'H', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'X', 'i', 'u', ' ', 3, 'F', 'u', ' ', 4, 'L', 'i', 'u', ' ', 3, 'Y', 'e', ' ', 3, 'X', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'J', 'i', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'S', 'u', 'o', ' ', 8, 'C', 'h', 'i', 'i', 's', 'a', 'i', ' ', 4, 'W', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'P', 'i', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'C', 'u', 'i', ' ', 4, 'M', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'J', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'L', 'a', 'i', ' ', 4, 'W', 'e', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'P', 'e', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'H', 'u', ' ', 3, 'Q', 'i', ' ', 2, 'E', ' ', 4, 'K', 'u', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'B', 'e', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 3, 'L', 'u', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'B', 'e', 'i', ' ', 4, 'L', 'i', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'P', 'i', ' ', 3, 'P', 'a', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'F', 'a', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'D', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'H', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'M', 'a', 'o', ' ', 4, 'M', 'e', 'i', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'T', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 4, 'R', 'o', 'u', ' ', 4, 'M', 'i', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'R', 'u', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'a', ' ', 5, 'D', 'u', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 4, 'N', 'a', 'o', ' ', 3, 'H', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'R', 'u', 'i', ' ', 3, 'S', 'e', ' ', 4, 'L', 'i', 'u', ' ', 4, 'S', 'h', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'W', 'e', 'n', ' ', 3, 'W', 'u', ' ', 4, 'J', 'i', 'n', ' ', 4, 'J', 'i', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'M', 'a', ' ', 4, 'T', 'a', 'o', ' ', 4, 'L', 'i', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'C', 'u', 'o', ' ', 4, 'J', 'u', 'e', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'A', 'i', ' ', 4, 'B', 'i', 'n', ' ', 3, 'T', 'u', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'K', 'u', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'u', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 3, 'L', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'A', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'L', 'u', ' ', 3, 'W', 'u', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'o', 'u', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 3, 'Q', 'u', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 5, 'L', 'i', 'a', 'o', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'S', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 3, 'P', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'F', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 4, 'L', 'i', 'u', ' ', 3, 'J', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'A', 'i', ' ', 3, 'B', 'i', ' ', 4, 'C', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'G', 'u', 'n', ' ', 4, 'T', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'S', 'e', ' ', 4, 'S', 'u', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'J', 'i', 'n', ' ', 3, 'L', 'u', ' ', 4, 'B', 'i', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 4, 'W', 'e', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 4, 'L', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'J', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'R', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'G', 'a', 'i', ' ', 4, 'L', 'e', 'i', ' ', 3, 'D', 'u', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'R', 'o', 'u', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'G', 'u', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'L', 'a', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'M', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'X', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'D', 'a', 'o', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'G', 'u', 'a', ' ', 3, 'B', 'o', ' ', 4, 'D', 'i', 'e', ' ', 4, 'B', 'a', 'o', ' ', 3, 'H', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'B', 'a', 'n', ' ', 5, 'R', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 3, 'W', 'a', ' ', 11, 'D', 'e', 'k', 'a', 'g', 'u', 'r', 'a', 'm', 'u', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'P', 'e', 'n', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'D', 'a', 'n', ' ', 5, 'W', 'e', 'n', 'g', ' ', 3, 'O', 'u', ' ', 12, 'D', 'e', 's', 'h', 'i', 'g', 'u', 'r', 'a', 'm', 'u', ' ', 11, 'M', 'i', 'r', 'i', 'g', 'u', 'r', 'a', 'm', 'u', ' ', 5, 'T', 'h', 'o', 'n', ' ', 3, 'H', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'C', 'i', ' ', 11, 'H', 'e', 'k', 'u', 't', 'o', 'g', 'u', 'r', 'a', ' ', 5, 'J', 'u', 'a', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 7, 'S', 'a', 'r', 'a', 'k', 'e', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'P', 'o', 'u', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 11, 'S', 'e', 'n', 'c', 'h', 'i', 'g', 'u', 'r', 'a', ' ', 3, 'C', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'L', 'o', 'u', ' ', 3, 'D', 'i', ' ', 3, 'O', 'u', ' ', 5, 'M', 'e', 'n', 'g', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 3, 'W', 'u', ' ', 3, 'P', 'i', ' ', 4, 'D', 'a', 'n', ' ', 5, 'W', 'e', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 4, 'D', 'a', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'R', 'u', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'S', 'u', ' ', 4, 'S', 'e', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 3, 'L', 'u', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'N', 'i', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'J', 'i', 'a', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'N', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'a', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'B', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'L', 'i', 'u', ' ', 4, 'X', 'u', 'n', ' ', 4, 'L', 'i', 'u', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'M', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'F', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'J', 'i', 'e', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'F', 'u', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'M', 'u', ' ', 4, 'T', 'a', 'p', ' ', 4, 'P', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'W', 'a', ' ', 3, 'D', 'a', ' ', 4, 'N', 'a', 'n', ' ', 4, 'L', 'i', 'u', ' ', 4, 'B', 'e', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'C', 'h', 'u', ' ', 3, 'M', 'u', ' ', 3, 'M', 'u', ' ', 3, 'C', 'e', ' ', 4, 'C', 'e', 'n', ' ', 4, 'G', 'a', 'i', ' ', 3, 'B', 'i', ' ', 3, 'D', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'L', 'u', 'e', ' ', 3, 'Q', 'i', ' ', 4, 'L', 'u', 'e', ' ', 4, 'P', 'a', 'n', ' ', 5, 'K', 'e', 's', 'a', ' ', 4, 'F', 'a', 'n', ' ', 4, 'H', 'u', 'a', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'M', 'u', ' ', 4, 'J', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'L', 'i', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'D', 'i', 'e', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'H', 'u', 'a', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'J', 'i', ' ', 4, 'W', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 3, 'J', 'i', ' ', 4, 'C', 'h', 'a', ' ', 4, 'L', 'i', 'u', ' ', 7, 'T', 'a', 't', 'a', 'm', 'u', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'B', 'o', ' ', 4, 'D', 'i', 'e', ' ', 4, 'D', 'i', 'e', ' ', 3, 'P', 'i', ' ', 4, 'N', 'i', 'e', ' ', 4, 'D', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 4, 'S', 'h', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Y', 'i', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'N', 'a', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'B', 'i', ' ', 4, 'J', 'i', 'e', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'G', 'o', 'n', 'g', ' ', 3, 'G', 'e', ' ', 4, 'J', 'i', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'X', 'i', 'a', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'N', 'u', 'e', ' ', 3, 'L', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'B', 'a', ' ', 4, 'J', 'i', 'e', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'X', 'i', 'a', ' ', 4, 'C', 'u', 'i', ' ', 3, 'B', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'P', 'a', 'o', ' ', 3, 'P', 'i', ' ', 4, 'G', 'a', 'n', ' ', 3, 'K', 'e', ' ', 3, 'C', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'Q', 'i', ' ', 4, 'D', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'F', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'T', 'e', 'n', 'g', ' ', 3, 'J', 'u', ' ', 3, 'J', 'i', ' ', 4, 'F', 'e', 'i', ' ', 3, 'Q', 'u', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'N', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'K', 'a', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'D', 'u', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'H', 'e', 'n', ' ', 3, 'Y', 'a', ' ', 4, 'M', 'e', 'i', ' ', 4, 'D', 'o', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'T', 'u', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'P', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'S', 'u', 'a', 'n', ' ', 3, 'P', 'u', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'C', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 3, 'W', 'u', ' ', 4, 'S', 'h', 'a', ' ', 4, 'L', 'a', 'o', ' ', 5, 'S', 'h', 'o', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 3, 'M', 'a', ' ', 4, 'L', 'i', 'n', ' ', 4, 'C', 'h', 'i', ' ', 3, 'J', 'i', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'A', 'n', ' ', 4, 'C', 'h', 'i', ' ', 3, 'B', 'i', ' ', 4, 'B', 'e', 'i', ' ', 4, 'M', 'i', 'n', ' ', 3, 'G', 'u', ' ', 4, 'D', 'u', 'i', ' ', 2, 'E', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'u', 'i', ' ', 3, 'Y', 'a', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'C', 'u', ' ', 4, 'D', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 6, 'Z', 'h', 'u', 'n', 'g', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'H', 'o', 'u', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'L', 'a', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'T', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'u', 'a', ' ', 4, 'W', 'e', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'K', 'u', ' ', 4, 'J', 'i', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'u', ' ', 4, 'S', 'a', 'o', ' ', 4, 'J', 'u', 'e', ' ', 4, 'C', 'h', 'i', ' ', 3, 'X', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'W', 'e', 'n', ' ', 3, 'J', 'i', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 4, 'L', 'i', 'u', ' ', 5, 'C', 'h', 'a', 'i', ' ', 5, 'S', 'h', 'o', 'u', ' ', 4, 'N', 'u', 'e', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'D', 'a', ' ', 4, 'P', 'i', 'e', ' ', 4, 'T', 'a', 'n', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'C', 'u', ' ', 4, 'L', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 4, 'S', 'o', 'u', ' ', 4, 'S', 'u', 'o', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'L', 'o', 'u', ' ', 3, 'L', 'u', ' ', 3, 'M', 'o', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'L', 'i', 'u', ' ', 4, 'L', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'D', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'H', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'P', 'i', ' ', 4, 'L', 'e', 'i', ' ', 3, 'L', 'i', ' ', 4, 'S', 'h', 'u', ' ', 4, 'D', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 4, 'L', 'a', 'i', ' ', 4, 'P', 'i', 'e', ' ', 3, 'J', 'i', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'H', 'u', 'o', ' ', 4, 'L', 'a', 'i', ' ', 6, 'S', 'h', 'a', 'k', 'u', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Q', 'u', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 3, 'B', 'o', ' ', 4, 'G', 'u', 'i', ' ', 3, 'P', 'o', ' ', 3, 'F', 'a', ' ', 5, 'D', 'e', 'n', 'g', ' ', 3, 'F', 'a', ' ', 4, 'B', 'a', 'i', ' ', 4, 'B', 'a', 'i', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'B', 'i', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'M', 'a', 'o', ' ', 3, 'D', 'e', ' ', 3, 'P', 'a', ' ', 4, 'J', 'i', 'e', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 3, 'C', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'G', 'a', 'o', ' ', 3, 'M', 'o', ' ', 3, 'J', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'G', 'a', 'o', ' ', 3, 'A', 'i', ' ', 2, 'E', ' ', 4, 'H', 'a', 'o', ' ', 4, 'H', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'W', 'a', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'A', 'i', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'H', 'a', 'o', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'o', ' ', 3, 'Z', 'e', ' ', 4, 'C', 'u', 'i', ' ', 4, 'H', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'Y', 'e', ' ', 3, 'P', 'o', ' ', 4, 'H', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'A', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 3, 'H', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'P', 'i', ' ', 4, 'G', 'a', 'n', ' ', 4, 'P', 'a', 'o', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'J', 'u', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'C', 'u', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'G', 'u', ' ', 4, 'J', 'u', 'n', ' ', 4, 'J', 'u', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'G', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'D', 'u', ' ', 4, 'M', 'i', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'B', 'e', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'P', 'e', 'n', ' ', 3, 'H', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'H', 'e', ' ', 3, 'Y', 'i', ' ', 3, 'B', 'o', ' ', 4, 'W', 'a', 'n', ' ', 3, 'H', 'e', ' ', 4, 'A', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'H', 'e', ' ', 3, 'Y', 'u', ' ', 4, 'K', 'u', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'G', 'a', 'i', ' ', 4, 'D', 'a', 'o', ' ', 4, 'P', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'D', 'a', 'o', ' ', 3, 'L', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'J', 'i', 'n', ' ', 3, 'X', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'P', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'A', 'n', ' ', 3, 'L', 'u', ' ', 4, 'S', 'h', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'A', 'n', ' ', 3, 'G', 'u', ' ', 3, 'L', 'i', ' ', 3, 'M', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 3, 'X', 'u', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'R', 'u', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'D', 'u', 'n', ' ', 4, 'X', 'i', 'n', ' ', 3, 'X', 'i', ' ', 4, 'P', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'D', 'u', 'n', ' ', 4, 'M', 'i', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'P', 'a', 'n', ' ', 5, 'F', 'a', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'o', ' ', 4, 'D', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 4, 'M', 'a', 'o', ' ', 4, 'K', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'O', 'u', ' ', 4, 'S', 'h', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'H', 'u', 'o', ' ', 3, 'D', 'a', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'J', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'C', 'h', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 3, 'M', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'D', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'D', 'i', 'e', ' ', 3, 'Y', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'Z', 'i', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'M', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'M', 'i', ' ', 4, 'D', 'i', 'e', ' ', 3, 'Y', 'i', ' ', 3, 'E', 'r', ' ', 5, 'M', 'i', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'M', 'o', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'M', 'o', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'M', 'a', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 4, 'J', 'u', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'H', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'D', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'C', 'u', 'o', ' ', 5, 'J', 'u', 'a', 'n', ' ', 2, 'E', ' ', 4, 'W', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'K', 'u', 'n', ' ', 4, 'L', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'n', ' ', 4, 'W', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'L', 'i', 'e', ' ', 4, 'Y', 'a', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'L', 'a', 'i', ' ', 4, 'S', 'u', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'u', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'D', 'u', ' ', 3, 'B', 'i', ' ', 3, 'B', 'i', ' ', 3, 'M', 'u', ' ', 4, 'H', 'u', 'n', ' ', 3, 'N', 'i', ' ', 3, 'L', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'C', 'a', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'H', 'u', 'n', ' ', 3, 'M', 'a', ' ', 4, 'X', 'i', 'a', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'X', 'i', ' ', 4, 'G', 'u', 'n', ' ', 4, 'C', 'a', 'i', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 3, 'D', 'u', ' ', 4, 'H', 'o', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'T', 'i', ' ', 4, 'K', 'u', 'i', ' ', 4, 'G', 'a', 'o', ' ', 4, 'R', 'u', 'i', ' ', 4, 'M', 'o', 'u', ' ', 3, 'X', 'u', ' ', 3, 'F', 'a', ' ', 4, 'W', 'e', 'n', ' ', 5, 'M', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'K', 'u', 'i', ' ', 3, 'M', 'i', ' ', 5, 'W', 'e', 'n', 'g', ' ', 4, 'K', 'o', 'u', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'K', 'e', ' ', 4, 'S', 'o', 'u', ' ', 4, 'X', 'i', 'a', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'M', 'a', 'o', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 5, 'S', 'h', 'u', 'i', ' ', 3, 'Z', 'e', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'O', 'u', ' ', 3, 'M', 'o', ' ', 5, 'S', 'h', 'u', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'L', 'o', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'M', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'R', 'u', 'n', ' ', 4, 'P', 'i', 'e', ' ', 3, 'X', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'P', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'S', 'h', 'u', 'n', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'C', 'h', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'K', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 3, 'X', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'M', 'o', 'u', ' ', 4, 'L', 'i', 'n', ' ', 4, 'K', 'u', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 3, 'A', 'i', ' ', 4, 'H', 'u', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'G', 'u', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'Q', 'u', ' ', 4, 'W', 'e', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'S', 'a', 'o', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'H', 'u', 'o', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'B', 'i', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'L', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 3, 'L', 'u', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'C', 'h', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'K', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'M', 'a', 'o', ' ', 4, 'J', 'i', 'n', ' ', 4, 'L', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'S', 'h', 'u', 'o', ' ', 3, 'C', 'e', ' ', 4, 'J', 'u', 'e', ' ', 4, 'S', 'h', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'H', 'o', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'J', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'C', 'u', 'o', ' ', 5, 'D', 'u', 'a', 'n', ' ', 3, 'A', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 4, 'B', 'a', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 3, 'J', 'i', ' ', 3, 'Z', 'i', ' ', 4, 'G', 'a', 'n', ' ', 3, 'W', 'u', ' ', 4, 'T', 'u', 'o', ' ', 3, 'K', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'X', 'i', ' ', 4, 'F', 'a', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'M', 'a', ' ', 4, 'S', 'h', 'a', ' ', 4, 'D', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 3, 'L', 'i', ' ', 3, 'F', 'u', ' ', 4, 'M', 'i', 'n', ' ', 4, 'N', 'u', 'o', ' ', 4, 'H', 'u', 'o', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'K', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'F', 'e', 'n', ' ', 2, 'E', ' ', 3, 'Y', 'a', ' ', 3, 'P', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'S', 'u', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'e', ' ', 4, 'D', 'u', 'n', ' ', 4, 'P', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'F', 'a', ' ', 3, 'M', 'o', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'Q', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'L', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 3, 'D', 'i', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'A', 'i', ' ', 4, 'F', 'e', 'i', ' ', 3, 'M', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'L', 'i', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'N', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'P', 'a', 'o', ' ', 3, 'L', 'e', ' ', 3, 'P', 'o', ' ', 3, 'B', 'o', ' ', 3, 'P', 'o', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'Z', 'a', ' ', 4, 'N', 'u', 'o', ' ', 3, 'L', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 8, 'A', 'r', 'a', 'g', 'a', 'n', 'e', ' ', 4, 'C', 'h', 'u', ' ', 5, 'K', 'e', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 2, 'E', ' ', 4, 'N', 'a', 'o', ' ', 4, 'J', 'i', 'a', ' ', 3, 'L', 'u', ' ', 4, 'W', 'e', 'i', ' ', 3, 'A', 'i', ' ', 4, 'L', 'u', 'o', ' ', 4, 'K', 'e', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'X', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'o', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'K', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'X', 'i', 'a', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'I', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'e', ' ', 4, 'C', 'h', 'e', ' ', 2, 'E', ' ', 4, 'L', 'i', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'S', 'h', 'a', ' ', 4, 'K', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'K', 'a', 'k', 'i', ' ', 3, 'L', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'N', 'u', 'e', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'K', 'e', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'K', 'o', 'n', 'g', ' ', 5, 'C', 'e', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 4, 'J', 'u', 'n', ' ', 3, 'B', 'o', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'M', 'i', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'H', 'e', ' ', 3, 'L', 'u', ' ', 3, 'A', 'i', ' ', 4, 'S', 'u', 'i', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'B', 'e', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'D', 'u', 'i', ' ', 3, 'W', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'L', 'u', 'n', ' ', 4, 'W', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'P', 'e', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'R', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'D', 'i', 'e', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'D', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'J', 'i', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'K', 'e', ' ', 3, 'B', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'S', 'h', 'u', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'a', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'T', 'i', ' ', 4, 'N', 'a', 'o', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'D', 'i', ' ', 4, 'T', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 5, 'S', 'e', 'k', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'Q', 'u', 'e', ' ', 3, 'M', 'a', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'n', ' ', 3, 'S', 'u', ' ', 2, 'E', ' ', 3, 'C', 'i', ' ', 4, 'L', 'i', 'u', ' ', 3, 'S', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'a', ' ', 3, 'P', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'S', 'a', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 4, 'C', 'u', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'X', 'i', 'a', ' ', 3, 'Q', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'P', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'D', 'u', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'K', 'e', ' ', 3, 'L', 'a', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'A', 'o', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'L', 'u', ' ', 4, 'K', 'a', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'L', 'e', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'M', 'o', ' ', 3, 'Q', 'i', ' ', 4, 'C', 'u', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'J', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'L', 'a', 'o', ' ', 3, 'Q', 'u', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'L', 'i', 'n', ' ', 5, 'D', 'i', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'P', 'a', 'n', ' ', 3, 'Z', 'a', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'D', 'i', ' ', 3, 'L', 'i', ' ', 5, 'T', 'a', 'n', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'D', 'u', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'H', 'e', ' ', 4, 'H', 'u', 'o', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 4, 'L', 'e', 'i', ' ', 3, 'K', 'e', ' ', 4, 'C', 'h', 'u', ' ', 3, 'J', 'i', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'P', 'i', ' ', 3, 'P', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'P', 'i', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'A', 'i', ' ', 4, 'K', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'R', 'u', 'a', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'P', 'a', 'o', ' ', 3, 'C', 'i', ' ', 4, 'M', 'i', 'e', ' ', 3, 'C', 'a', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 4, 'L', 'e', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'L', 'i', ' ', 3, 'L', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'P', 'a', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'M', 'o', ' ', 3, 'B', 'o', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'L', 'i', ' ', 5, 'R', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'e', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'S', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'T', 'a', ' ', 3, 'M', 'a', ' ', 4, 'X', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'B', 'e', 'n', 'g', ' ', 4, 'D', 'u', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'F', 'u', ' ', 3, 'F', 'u', ' ', 3, 'M', 'i', ' ', 3, 'Z', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'S', 'u', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 4, 'Z', 'u', 'o', ' ', 3, 'Q', 'u', ' ', 3, 'H', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'S', 'u', 'i', ' ', 3, 'C', 'i', ' ', 5, 'C', 'h', 'a', 'i', ' ', 3, 'M', 'i', ' ', 3, 'L', 'u', ' ', 3, 'Y', 'u', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'G', 'u', 'i', ' ', 4, 'X', 'i', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'J', 'i', ' ', 4, 'G', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'G', 'a', 'o', ' ', 5, 'S', 'h', 'u', 'i', ' ', 4, 'J', 'i', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'G', 'a', 'i', ' ', 4, 'K', 'u', 'n', ' ', 3, 'D', 'i', ' ', 4, 'D', 'a', 'o', ' ', 4, 'H', 'u', 'o', ' ', 4, 'T', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'G', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'L', 'u', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 4, 'D', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'L', 'u', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Z', 'i', ' ', 4, 'H', 'u', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'W', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'T', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'M', 'e', 'i', ' ', 3, 'S', 'i', ' ', 3, 'D', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'G', 'a', 'o', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'S', 'i', ' ', 3, 'M', 'a', ' ', 3, 'T', 'a', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'X', 'i', ' ', 3, 'J', 'i', ' ', 3, 'S', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 5, 'K', 'u', 'a', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'L', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 3, 'N', 'i', ' ', 4, 'D', 'a', 'o', ' ', 3, 'L', 'i', ' ', 5, 'R', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'T', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 4, 'R', 'o', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'H', 'e', ' ', 3, 'T', 'u', ' ', 4, 'X', 'i', 'u', ' ', 3, 'S', 'i', ' ', 4, 'R', 'e', 'n', ' ', 3, 'T', 'u', ' ', 3, 'Z', 'i', ' ', 4, 'C', 'h', 'a', ' ', 4, 'G', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 4, 'H', 'a', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'K', 'e', ' ', 5, 'M', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'B', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'M', 'i', ' ', 3, 'K', 'u', ' ', 4, 'B', 'a', 'n', ' ', 3, 'P', 'i', ' ', 3, 'N', 'i', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'Z', 'u', ' ', 3, 'P', 'i', ' ', 3, 'B', 'a', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'M', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'S', 'h', 'u', ' ', 3, 'J', 'u', ' ', 3, 'Z', 'i', ' ', 4, 'H', 'u', 'o', ' ', 3, 'J', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'H', 'u', 'o', ' ', 3, 'H', 'e', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Z', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'R', 'e', 'n', ' ', 3, 'D', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'H', 'u', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 3, 'F', 'u', ' ', 3, 'X', 'i', ' ', 4, 'K', 'a', 'o', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 3, 'Z', 'e', ' ', 5, 'S', 'h', 'u', 'i', ' ', 3, 'L', 'u', ' ', 4, 'K', 'u', 'n', ' ', 4, 'G', 'a', 'n', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'T', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'T', 'u', ' ', 5, 'S', 'h', 'a', 'o', ' ', 5, 'S', 'h', 'u', 'i', ' ', 3, 'Y', 'a', ' ', 4, 'L', 'u', 'n', ' ', 3, 'L', 'u', ' ', 3, 'G', 'u', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'R', 'e', 'n', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'i', ' ', 3, 'J', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'K', 'u', 'n', ' ', 5, 'L', 'e', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'K', 'e', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'Z', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'S', 'u', ' ', 4, 'L', 'u', 'e', ' ', 3, 'Y', 'i', ' ', 3, 'X', 'i', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'F', 'u', ' ', 3, 'B', 'i', ' ', 4, 'N', 'u', 'o', ' ', 4, 'J', 'i', 'e', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'X', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'D', 'a', 'o', ' ', 4, 'W', 'e', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'J', 'i', ' ', 3, 'X', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'D', 'a', 'o', ' ', 4, 'J', 'i', 'a', ' ', 3, 'J', 'i', ' ', 4, 'G', 'a', 'o', ' ', 4, 'G', 'a', 'o', ' ', 3, 'G', 'u', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'J', 'i', ' ', 5, 'K', 'a', 'n', 'g', ' ', 3, 'M', 'u', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'M', 'e', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'J', 'i', ' ', 3, 'L', 'u', ' ', 3, 'S', 'u', ' ', 3, 'J', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'W', 'e', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'S', 'e', ' ', 3, 'Y', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'J', 'i', ' ', 4, 'S', 'u', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'P', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'S', 'a', 'i', ' ', 3, 'L', 'u', ' ', 4, 'S', 'u', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 3, 'S', 'e', ' ', 4, 'H', 'u', 'i', ' ', 5, 'R', 'a', 'n', 'g', ' ', 4, 'N', 'u', 'o', ' ', 3, 'Y', 'u', ' ', 4, 'B', 'i', 'n', ' ', 3, 'J', 'i', ' ', 4, 'T', 'u', 'i', ' ', 4, 'W', 'e', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 5, 'G', 'o', 'n', 'g', ' ', 3, 'L', 'u', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'R', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'X', 'u', 'e', ' ', 3, 'W', 'a', ' ', 4, 'J', 'i', 'u', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 5, 'K', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'S', 'e', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 3, 'T', 'u', ' ', 4, 'L', 'a', 'o', ' ', 4, 'Q', 'i', 'e', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'B', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'W', 'a', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'W', 'u', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'K', 'o', 'u', ' ', 5, 'C', 'u', 'a', 'n', ' ', 3, 'W', 'o', ' ', 4, 'D', 'a', 'n', ' ', 3, 'K', 'u', ' ', 3, 'K', 'e', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'X', 'u', ' ', 3, 'S', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'D', 'o', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'W', 'o', ' ', 3, 'W', 'a', ' ', 3, 'Y', 'a', ' ', 3, 'Y', 'u', ' ', 3, 'J', 'u', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'J', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'X', 'i', ' ', 3, 'W', 'u', ' ', 4, 'K', 'u', 'i', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 5, 'K', 'u', 'a', 'n', ' ', 5, 'L', 'o', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'C', 'u', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'C', 'u', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'D', 'o', 'u', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'L', 'i', ' ', 4, 'C', 'h', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'F', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'M', 'i', 'a', 'o', ' ', 3, 'J', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'S', 'i', ' ', 4, 'J', 'u', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 4, 'J', 'i', 'e', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'D', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'C', 'e', 'n', 'g', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'C', 'u', 'i', ' ', 5, 'H', 'u', 'a', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'K', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'L', 'e', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'G', 'a', 'n', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 7, 'U', 't', 's', 'u', 'b', 'o', ' ', 3, 'D', 'u', ' ', 3, 'J', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'B', 'a', ' ', 5, 'S', 'u', 'a', 'n', ' ', 3, 'J', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'S', 'u', 'n', ' ', 3, 'Y', 'a', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'H', 'u', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'C', 'e', 'n', ' ', 3, 'P', 'i', ' ', 3, 'B', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'N', 'a', ' ', 4, 'C', 'h', 'i', ' ', 3, 'G', 'u', ' ', 3, 'L', 'i', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'M', 'i', 'n', ' ', 4, 'B', 'a', 'o', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'S', 'i', ' ', 3, 'F', 'u', ' ', 3, 'C', 'e', ' ', 4, 'B', 'e', 'n', ' ', 4, 'P', 'e', 'i', ' ', 3, 'D', 'a', ' ', 3, 'Z', 'i', ' ', 3, 'D', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Z', 'e', ' ', 3, 'N', 'u', ' ', 3, 'F', 'u', ' ', 4, 'G', 'o', 'u', ' ', 4, 'F', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 3, 'G', 'e', ' ', 4, 'F', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'M', 'a', 'o', ' ', 3, 'P', 'o', ' ', 4, 'S', 'e', 'y', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 6, 'S', 'o', 'u', 'k', 'e', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 4, 'G', 'u', 'i', ' ', 3, 'Q', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'G', 'u', 'a', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'S', 'u', 'n', ' ', 3, 'R', 'u', ' ', 3, 'F', 'a', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 3, 'D', 'a', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'C', 'e', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'K', 'o', 'u', ' ', 4, 'L', 'a', 'i', ' ', 3, 'B', 'i', ' ', 5, 'S', 'h', 'a', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'C', 'e', ' ', 3, 'F', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'T', 'u', ' ', 3, 'P', 'a', ' ', 3, 'L', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'J', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'S', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'u', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'o', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'C', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'G', 'a', 'o', ' ', 5, 'K', 'u', 'a', 'i', ' ', 4, 'G', 'a', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'K', 'a', 'g', 'o', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 2, 'O', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'P', 'u', ' ', 4, 'L', 'a', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'B', 'i', ' ', 3, 'B', 'i', ' ', 3, 'B', 'i', ' ', 3, 'G', 'e', ' ', 4, 'C', 'h', 'i', ' ', 5, 'G', 'u', 'a', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'G', 'u', ' ', 4, 'C', 'h', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'a', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'L', 'u', ' ', 3, 'B', 'o', ' ', 3, 'J', 'i', ' ', 4, 'L', 'i', 'n', ' ', 5, 'S', 'u', 'a', 'n', ' ', 4, 'J', 'u', 'n', ' ', 3, 'F', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'G', 'u', ' ', 5, 'K', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'J', 'u', 'n', ' ', 5, 'C', 'h', 'u', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'C', 'e', ' ', 3, 'J', 'u', ' ', 3, 'B', 'o', ' ', 3, 'Z', 'e', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'T', 'u', 'o', ' ', 4, 'L', 'u', 'o', ' ', 4, 'D', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'R', 'u', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'S', 'u', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'H', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'L', 'u', ' ', 3, 'W', 'u', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'J', 'i', 'e', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 4, 'F', 'a', 'n', ' ', 5, 'C', 'h', 'u', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'H', 'o', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'M', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'S', 'i', 'k', ' ', 4, 'L', 'o', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'H', 'e', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'G', 'a', 'o', ' ', 4, 'F', 'e', 'i', ' ', 4, 'R', 'u', 'o', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'G', 'o', 'u', ' ', 4, 'N', 'i', 'e', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'C', 'u', 'a', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'D', 'u', ' ', 3, 'L', 'i', ' ', 3, 'B', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'C', 'h', 'u', ' ', 5, 'S', 'h', 'a', 'i', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'L', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'B', 'u', ' ', 3, 'L', 'i', ' ', 4, 'H', 'u', 'i', ' ', 3, 'B', 'i', ' ', 3, 'D', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'S', 'e', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'P', 'a', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'D', 'o', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'M', 'i', 'e', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 3, 'Z', 'e', ' ', 3, 'X', 'i', ' ', 4, 'G', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'H', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'K', 'o', 'u', ' ', 3, 'C', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'J', 'i', ' ', 4, 'G', 'u', 'i', ' ', 3, 'S', 'u', ' ', 4, 'L', 'o', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'L', 'u', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'S', 'u', 'o', ' ', 5, 'C', 'u', 'a', 'n', ' ', 7, 'S', 'a', 's', 'a', 'r', 'a', ' ', 4, 'S', 'u', 'o', ' ', 3, 'L', 'e', ' ', 5, 'D', 'u', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'a', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'B', 'o', ' ', 3, 'M', 'i', ' ', 3, 'S', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'D', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'D', 'a', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'D', 'e', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'n', ' ', 4, 'L', 'a', 'o', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'D', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'P', 'a', 'i', ' ', 5, 'H', 'a', 't', 'a', ' ', 4, 'P', 'a', 'i', ' ', 4, 'G', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'D', 'u', ' ', 3, 'L', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'B', 'o', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'S', 'a', 'i', ' ', 3, 'K', 'e', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'B', 'o', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'L', 'a', 'i', ' ', 4, 'L', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'H', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'T', 'a', 'i', ' ', 3, 'T', 'i', ' ', 3, 'M', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'J', 'i', ' ', 5, 'H', 'a', 't', 'a', ' ', 5, 'T', 'e', 'n', 'g', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'F', 'a', 'n', ' ', 4, 'S', 'o', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'K', 'u', 'j', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'T', 'e', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'L', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'T', 'u', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'L', 'a', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 8, 'S', 'h', 'i', 'n', 's', 'h', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'Y', 'u', 'e', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'D', 'u', 'a', 'n', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'S', 'i', ' ', 4, 'L', 'u', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'X', 'u', ' ', 3, 'M', 'i', ' ', 3, 'D', 'i', ' ', 4, 'F', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'N', 'u', ' ', 4, 'X', 'i', 'e', ' ', 4, 'L', 'e', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 3, 'N', 'i', ' ', 4, 'C', 'u', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'K', 'u', 'm', 'e', ' ', 3, 'B', 'i', ' ', 4, 'B', 'a', 'n', ' ', 3, 'W', 'u', ' ', 4, 'S', 'h', 'a', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'R', 'o', 'u', ' ', 4, 'F', 'e', 'n', ' ', 3, 'B', 'i', ' ', 4, 'C', 'u', 'i', ' ', 3, 'L', 'i', ' ', 4, 'C', 'h', 'i', ' ', 9, 'N', 'u', 'k', 'a', 'm', 'i', 's', 'o', ' ', 3, 'R', 'o', ' ', 3, 'B', 'a', ' ', 3, 'L', 'i', ' ', 4, 'G', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'P', 'o', ' ', 3, 'M', 'o', ' ', 3, 'C', 'u', ' ', 5, 'N', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'L', 'i', ' ', 3, 'S', 'u', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'L', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'S', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 3, 'C', 'e', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'L', 'i', 'n', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'i', ' ', 4, 'F', 'e', 'n', ' ', 3, 'J', 'i', ' ', 7, 'S', 'u', 'k', 'u', 'm', 'o', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'C', 'a', 'n', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'L', 'u', ' ', 3, 'J', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'C', 'u', 'i', ' ', 4, 'B', 'a', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'o', ' ', 6, 'K', 'o', 'u', 'j', 'i', ' ', 4, 'S', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'R', 'o', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'H', 'o', 'u', ' ', 3, 'X', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'H', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'C', 'i', ' ', 3, 'L', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'F', 'u', ' ', 3, 'N', 'i', ' ', 4, 'B', 'e', 'i', ' ', 3, 'G', 'u', ' ', 4, 'X', 'i', 'u', ' ', 4, 'G', 'a', 'o', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 7, 'S', 'u', 'k', 'u', 'm', 'o', ' ', 4, 'C', 'a', 'o', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'M', 'i', ' ', 4, 'S', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'K', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'M', 'o', ' ', 4, 'S', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 4, 'N', 'u', 'o', ' ', 3, 'X', 'i', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'B', 'o', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'N', 'u', 'o', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'u', 'o', ' ', 3, 'D', 'i', ' ', 4, 'N', 'i', 'e', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'L', 'a', 'n', ' ', 3, 'M', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'u', ' ', 3, 'X', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'J', 'i', ' ', 4, 'C', 'h', 'a', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'X', 'u', 'n', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'H', 'e', ' ', 4, 'W', 'a', 'n', ' ', 4, 'R', 'e', 'n', ' ', 4, 'W', 'e', 'n', ' ', 4, 'W', 'e', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'N', 'a', ' ', 3, 'Z', 'i', ' ', 4, 'T', 'o', 'u', ' ', 4, 'N', 'i', 'u', ' ', 4, 'F', 'o', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'S', 'h', 'u', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'P', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'S', 'h', 'a', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'J', 'i', ' ', 4, 'F', 'e', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'R', 'e', 'n', ' ', 4, 'D', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 3, 'S', 'u', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 4, 'C', 'u', 'i', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'K', 'i', 'n', 'u', ' ', 4, 'J', 'i', 'n', ' ', 3, 'F', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'C', 'i', ' ', 3, 'Z', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'L', 'e', 'i', ' ', 3, 'X', 'i', ' ', 3, 'F', 'u', ' ', 4, 'X', 'i', 'e', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'B', 'e', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'Q', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'G', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'T', 'u', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'D', 'a', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'S', 'h', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Z', 'u', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'B', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'M', 'o', ' ', 4, 'S', 'h', 'u', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'W', 'a', 't', 'a', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'R', 'e', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 4, 'J', 'i', 'e', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'G', 'u', 'a', ' ', 4, 'B', 'a', 'i', ' ', 4, 'J', 'u', 'e', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'H', 'u', ' ', 3, 'C', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'T', 'a', 'o', ' ', 4, 'X', 'i', 'e', ' ', 3, 'K', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'G', 'a', 'i', ' ', 4, 'L', 'u', 'o', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'G', 'e', 'i', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'L', 'e', 'i', ' ', 4, 'X', 'i', 'e', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'L', 'u', 'n', ' ', 4, 'D', 'i', 'e', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'S', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'L', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'S', 'h', 'u', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'W', 'a', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'X', 'i', 'u', ' ', 3, 'T', 'i', ' ', 4, 'X', 'i', 'u', ' ', 4, 'X', 'i', 'e', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'F', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 4, 'D', 'u', 'i', ' ', 4, 'K', 'u', 'n', ' ', 3, 'F', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'H', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'S', 'o', 'k', ' ', 5, 'K', 'a', 's', 'e', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 4, 'D', 'u', 'o', ' ', 3, 'L', 'i', ' ', 3, 'L', 'u', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'W', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'T', 'a', 'o', ' ', 4, 'W', 'a', 'n', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 4, 'C', 'a', 'i', ' ', 4, 'G', 'u', 'o', ' ', 4, 'C', 'u', 'i', ' ', 4, 'L', 'u', 'n', ' ', 4, 'L', 'i', 'u', ' ', 3, 'Q', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'T', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'G', 'u', 'n', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'Z', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'R', 'u', 'i', ' ', 4, 'M', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'F', 'a', 'n', ' ', 3, 'L', 'u', ' ', 3, 'X', 'u', ' ', 6, 'Y', 'i', 'n', 'g', 'l', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 7, 'K', 'a', 's', 'u', 'r', 'i', ' ', 3, 'X', 'u', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'K', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'R', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'D', 'u', 'a', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'M', 'i', 'n', ' ', 5, 'M', 'i', 'a', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'B', 'a', 'o', ' ', 3, 'S', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'F', 'u', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'o', 'u', ' ', 5, 'M', 'i', 'a', 'o', ' ', 4, 'X', 'i', 'e', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'T', 'i', ' ', 4, 'G', 'u', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'D', 'a', 'i', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'X', 'u', ' ', 5, 'N', 'a', 'w', 'a', ' ', 7, 'O', 'd', 'o', 's', 'h', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'S', 'e', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'N', 'i', ' ', 5, 'B', 'a', 'n', 'g', ' ', 3, 'G', 'u', ' ', 4, 'P', 'a', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'C', 'u', 'o', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'X', 'i', 'a', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 3, 'X', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'T', 'a', 'o', ' ', 3, 'F', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'G', 'a', 'o', ' ', 3, 'R', 'u', ' ', 3, 'H', 'u', ' ', 4, 'Z', 'a', 'i', ' ', 5, 'T', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'S', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'T', 'a', 'o', ' ', 5, 'H', 'o', 'r', 'o', ' ', 4, 'C', 'a', 'i', ' ', 3, 'B', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'C', 'u', ' ', 3, 'L', 'i', ' ', 4, 'S', 'u', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'X', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'L', 'u', ' ', 3, 'M', 'o', ' ', 5, 'P', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'M', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'S', 'u', 'i', ' ', 4, 'F', 'a', 'n', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 5, 'B', 'e', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'a', 'o', ' ', 4, 'M', 'o', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 4, 'S', 'e', 'm', ' ', 3, 'X', 'i', ' ', 5, 'J', 'u', 'n', 'g', ' ', 4, 'X', 'i', 'u', ' ', 4, 'R', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'F', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'u', 'o', ' ', 4, 'Z', 'u', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'R', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'R', 'u', 'i', ' ', 4, 'X', 'i', 'u', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'u', 'a', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'U', 'n', ' ', 3, 'D', 'a', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 3, 'X', 'i', ' ', 3, 'S', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'B', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'N', 'a', 'o', ' ', 4, 'S', 'u', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'S', 'h', 'a', 'i', ' ', 3, 'X', 'u', ' ', 3, 'J', 'i', ' ', 4, 'B', 'i', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'P', 'u', ' ', 4, 'X', 'u', 'n', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 3, 'M', 'o', ' ', 4, 'L', 'e', 'i', ' ', 4, 'X', 'i', 'e', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'X', 'u', ' ', 4, 'L', 'e', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'K', 'o', 'u', ' ', 3, 'L', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'C', 'a', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 3, 'X', 'i', ' ', 4, 'D', 'a', 'o', ' ', 4, 'L', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'S', 'i', ' ', 4, 'J', 'i', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'H', 'e', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'J', 'i', ' ', 4, 'W', 'a', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'R', 'e', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'P', 'i', ' ', 4, 'S', 'h', 'a', ' ', 5, 'G', 'a', 'n', 'g', ' ', 3, 'N', 'a', ' ', 4, 'R', 'e', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'L', 'u', 'n', ' ', 4, 'F', 'e', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'W', 'e', 'n', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'N', 'i', 'u', ' ', 4, 'S', 'h', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 3, 'F', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'Z', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'X', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'B', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 3, 'K', 'u', ' ', 4, 'R', 'a', 'o', ' ', 4, 'D', 'i', 'e', ' ', 5, 'H', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 4, 'G', 'e', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 4, 'J', 'u', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'u', ' ', 3, 'X', 'i', ' ', 4, 'S', 'u', 'i', ' ', 4, 'T', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'T', 'i', ' ', 3, 'J', 'i', ' ', 3, 'X', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'X', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'F', 'e', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'T', 'a', 'o', ' ', 4, 'L', 'i', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'W', 'a', 'n', ' ', 3, 'L', 'u', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'K', 'e', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'T', 'i', ' ', 5, 'M', 'i', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'S', 'i', ' ', 4, 'D', 'u', 'o', ' ', 5, 'D', 'u', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'G', 'o', 'u', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'D', 'i', ' ', 3, 'L', 'u', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 3, 'F', 'u', ' ', 3, 'R', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 4, 'G', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'B', 'i', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'M', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 4, 'M', 'o', 'u', ' ', 4, 'S', 'a', 'o', ' ', 4, 'X', 'i', 'e', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 4, 'F', 'o', 'u', ' ', 4, 'X', 'i', 'e', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'F', 'o', 'u', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'F', 'o', 'u', ' ', 8, 'K', 'a', 'a', 'k', 'e', 'r', 'u', ' ', 3, 'B', 'o', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'H', 'o', 'u', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'Z', 'u', 'n', ' ', 4, 'T', 'a', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'W', 'e', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 4, 'T', 'a', 'n', ' ', 3, 'L', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 3, 'F', 'u', ' ', 3, 'M', 'i', ' ', 3, 'F', 'a', ' ', 3, 'G', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'J', 'u', ' ', 4, 'M', 'a', 'o', ' ', 3, 'G', 'u', ' ', 4, 'M', 'i', 'n', ' ', 5, 'G', 'a', 'n', 'g', ' ', 3, 'B', 'a', ' ', 4, 'G', 'u', 'a', ' ', 3, 'T', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'L', 'i', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'Z', 'u', 'i', ' ', 4, 'G', 'u', 'a', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'Y', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'A', 'n', ' ', 3, 'F', 'a', ' ', 4, 'N', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 3, 'S', 'i', ' ', 3, 'P', 'i', ' ', 3, 'M', 'a', ' ', 4, 'L', 'i', 'u', ' ', 3, 'B', 'a', ' ', 3, 'F', 'a', ' ', 3, 'L', 'i', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 3, 'B', 'i', ' ', 3, 'J', 'i', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'L', 'i', 'u', ' ', 3, 'J', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'M', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'L', 'u', 'o', ' ', 3, 'P', 'i', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'M', 'i', 'e', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'T', 'a', ' ', 4, 'M', 'e', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'F', 'e', 'n', ' ', 3, 'B', 'a', ' ', 4, 'G', 'a', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'G', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'G', 'a', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'D', 'i', ' ', 4, 'X', 'i', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'Q', 'u', 'n', ' ', 4, 'Q', 'u', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 9, 'Y', 'a', 's', 'h', 'i', 'n', 'a', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'F', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'N', 'o', 'u', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'G', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'W', 'e', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 4, 'C', 'h', 'i', ' ', 4, 'C', 'u', 'i', ' ', 3, 'F', 'u', ' ', 4, 'X', 'i', 'a', ' ', 4, 'P', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'a', ' ', 3, 'Y', 'i', ' ', 3, 'P', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'L', 'i', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Q', 'u', ' ', 3, 'X', 'i', ' ', 4, 'X', 'i', 'e', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'S', 'e', ' ', 5, 'H', 'o', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'C', 'u', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'T', 'a', 'o', ' ', 4, 'S', 'h', 'a', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 5, 'P', 'i', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'o', 'u', ' ', 3, 'H', 'e', ' ', 3, 'H', 'e', ' ', 4, 'H', 'a', 'n', ' ', 3, 'A', 'o', ' ', 5, 'P', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'L', 'i', 'n', ' ', 4, 'P', 'e', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'A', 'o', ' ', 4, 'F', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'H', 'u', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'D', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'L', 'a', 'o', ' ', 4, 'K', 'a', 'o', ' ', 4, 'M', 'a', 'o', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'Q', 'i', ' ', 4, 'G', 'o', 'u', ' ', 4, 'G', 'o', 'u', ' ', 4, 'G', 'o', 'u', ' ', 4, 'D', 'i', 'e', ' ', 4, 'D', 'i', 'e', ' ', 3, 'E', 'r', ' ', 5, 'S', 'h', 'u', 'a', ' ', 5, 'R', 'u', 'a', 'n', ' ', 3, 'E', 'r', ' ', 4, 'N', 'a', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'H', 'a', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'P', 'a', ' ', 3, 'P', 'i', ' ', 4, 'C', 'h', 'i', ' ', 3, 'S', 'i', ' ', 4, 'C', 'h', 'u', ' ', 4, 'J', 'i', 'a', ' ', 3, 'J', 'u', ' ', 3, 'H', 'e', ' ', 4, 'C', 'h', 'u', ' ', 4, 'L', 'a', 'o', ' ', 4, 'L', 'u', 'n', ' ', 3, 'J', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'O', 'u', ' ', 4, 'L', 'o', 'u', ' ', 4, 'N', 'o', 'u', ' ', 4, 'G', 'o', 'u', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'Z', 'e', ' ', 4, 'L', 'o', 'u', ' ', 3, 'J', 'i', ' ', 4, 'L', 'a', 'o', ' ', 4, 'H', 'u', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'M', 'o', ' ', 5, 'H', 'u', 'a', 'i', ' ', 3, 'E', 'r', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 3, 'D', 'a', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'D', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'N', 'i', 'e', ' ', 4, 'D', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'C', 'h', 'e', ' ', 5, 'L', 'i', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'W', 'a', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'N', 'i', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'E', 'r', ' ', 3, 'Y', 'a', ' ', 4, 'D', 'i', 'e', ' ', 4, 'G', 'u', 'a', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'H', 'a', 'o', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'L', 'i', 'e', ' ', 4, 'P', 'i', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'J', 'u', ' ', 3, 'B', 'i', ' ', 3, 'D', 'i', ' ', 4, 'G', 'u', 'o', ' ', 4, 'W', 'e', 'n', ' ', 3, 'X', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'C', 'o', 'n', 'g', ' ', 8, 'S', 'h', 'i', 'k', 'a', 't', 'o', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 10, 'T', 's', 'u', 'r', 'a', 'n', 'e', 'r', 'u', ' ', 4, 'K', 'u', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'W', 'e', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'A', 'o', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 4, 'N', 'i', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'D', 'a', 'n', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'J', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'S', 'i', ' ', 3, 'S', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'S', 'u', ' ', 3, 'S', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'R', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'e', ' ', 3, 'J', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'K', 'e', 'n', ' ', 4, 'C', 'a', 'o', ' ', 3, 'G', 'e', ' ', 3, 'D', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'R', 'e', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'R', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'D', 'u', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 3, 'W', 'o', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'G', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'H', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'F', 'e', 'i', ' ', 4, 'F', 'e', 'n', ' ', 4, 'P', 'e', 'i', ' ', 5, 'P', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'F', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'N', 'a', ' ', 5, 'H', 'a', 'n', 'g', ' ', 4, 'K', 'e', 'n', ' ', 4, 'R', 'a', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'W', 'e', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'J', 'i', 'n', ' ', 3, 'P', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'K', 'e', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'T', 'a', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'D', 'i', 'e', ' ', 4, 'D', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 3, 'B', 'a', ' ', 3, 'B', 'o', ' ', 3, 'Q', 'u', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 4, 'G', 'u', 'a', ' ', 4, 'T', 'a', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'K', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'N', 'i', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 3, 'F', 'u', ' ', 5, 'P', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'P', 'e', 'i', ' ', 4, 'J', 'i', 'a', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'B', 'a', 'o', ' ', 3, 'M', 'u', ' ', 3, 'Q', 'u', ' ', 3, 'H', 'u', ' ', 3, 'K', 'e', ' ', 3, 'Y', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'X', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'K', 'a', ' ', 3, 'L', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'N', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'P', 'a', 'n', 'g', ' ', 4, 'K', 'u', 'a', ' ', 3, 'Y', 'i', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 4, 'G', 'a', 'i', ' ', 3, 'G', 'e', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 3, 'E', 'r', ' ', 2, 'E', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'n', ' ', 5, 'N', 'e', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 4, 'G', 'u', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'C', 'u', 'i', ' ', 4, 'M', 'e', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'C', 'u', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'M', 'o', ' ', 4, 'M', 'a', 'i', ' ', 3, 'J', 'i', ' ', 11, 'O', 'b', 'i', 'y', 'a', 'a', 'k', 'a', 's', 'u', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'S', 'a', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'N', 'a', 'o', ' ', 3, 'M', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'W', 'a', 'n', ' ', 3, 'B', 'o', ' ', 4, 'W', 'e', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'R', 'o', 'u', ' ', 5, 'H', 'e', 'n', 'g', ' ', 4, 'C', 'u', 'o', ' ', 4, 'L', 'i', 'e', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'X', 'i', 'e', ' ', 3, 'D', 'e', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'C', 'u', ' ', 4, 'X', 'i', 'u', ' ', 4, 'X', 'i', 'n', ' ', 4, 'T', 'u', 'o', ' ', 4, 'P', 'a', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'N', 'e', 'i', ' ', 3, 'F', 'u', ' ', 4, 'D', 'o', 'u', ' ', 4, 'T', 'u', 'o', ' ', 5, 'N', 'i', 'a', 'o', ' ', 4, 'N', 'o', 'y', ' ', 3, 'P', 'i', ' ', 3, 'G', 'u', ' ', 4, 'G', 'u', 'a', ' ', 3, 'L', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'C', 'u', 'i', ' ', 4, 'J', 'i', 'e', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'P', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'L', 'u', 'n', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'o', ' ', 4, 'K', 'u', 'i', ' ', 5, 'C', 'h', 'u', 'i', ' ', 4, 'D', 'a', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'N', 'e', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 3, 'L', 'a', ' ', 3, 'Y', 'i', ' ', 3, 'A', 'n', ' ', 4, 'R', 'e', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'F', 'u', ' ', 3, 'F', 'u', ' ', 3, 'J', 'u', ' ', 4, 'F', 'e', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'P', 'i', ' ', 4, 'G', 'u', 'o', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'M', 'e', 'i', ' ', 5, 'R', 'u', 'a', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'C', 'o', 'u', ' ', 4, 'G', 'u', 'a', ' ', 3, 'O', 'u', ' ', 3, 'D', 'i', ' ', 3, 'A', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'N', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'R', 'o', 'u', ' ', 2, 'E', ' ', 4, 'S', 'a', 'i', ' ', 3, 'T', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 4, 'J', 'i', 'a', ' ', 5, 'D', 'u', 'a', 'n', ' ', 3, 'B', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'N', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'W', 'a', ' ', 5, 'T', 'e', 'n', 'g', ' ', 4, 'T', 'u', 'i', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'L', 'u', ' ', 3, 'W', 'a', ' ', 4, 'S', 'o', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'S', 'u', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'G', 'e', ' ', 3, 'Y', 'i', ' ', 3, 'B', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'P', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'G', 'a', 'o', ' ', 3, 'L', 'u', ' ', 4, 'B', 'i', 'n', ' ', 3, 'O', 'u', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'L', 'u', ' ', 4, 'G', 'u', 'o', ' ', 5, 'P', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'u', 'a', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'M', 'o', ' ', 3, 'X', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 3, 'L', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'L', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'T', 'a', 'r', 'a', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'N', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'C', 'u', 'i', ' ', 4, 'G', 'u', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'T', 'e', 'n', 'g', ' ', 4, 'F', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'W', 'u', ' ', 4, 'C', 'u', 'i', ' ', 4, 'R', 'u', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 4, 'F', 'e', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'a', ' ', 4, 'D', 'a', 'n', ' ', 5, 'K', 'u', 'a', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'T', 'u', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 4, 'C', 'h', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'L', 'a', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'S', 'a', 'o', ' ', 4, 'T', 'u', 'n', ' ', 3, 'G', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'C', 'u', 'i', ' ', 4, 'B', 'i', 'n', ' ', 4, 'X', 'u', 'n', ' ', 3, 'R', 'u', ' ', 4, 'H', 'u', 'o', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'K', 'u', 'a', 'n', ' ', 3, 'L', 'a', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'H', 'u', 'o', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 3, 'Q', 'u', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 5, 'L', 'u', 'a', 'n', ' ', 3, 'N', 'i', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'W', 'o', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'N', 'i', 'e', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'J', 'i', ' ', 4, 'G', 'a', 'o', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'G', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'D', 'i', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'X', 'i', 'u', ' ', 4, 'T', 'a', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'J', 'i', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'h', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 4, 'J', 'i', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'J', 'u', ' ', 4, 'J', 'i', 'u', ' ', 4, 'X', 'i', 'n', ' ', 4, 'S', 'h', 'e', ' ', 4, 'S', 'h', 'e', ' ', 7, 'Y', 'a', 'd', 'o', 'r', 'u', ' ', 4, 'J', 'i', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'T', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 4, 'S', 'h', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 3, 'P', 'u', ' ', 3, 'P', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'a', ' ', 4, 'T', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'u', 'n', ' ', 4, 'X', 'i', 'a', ' ', 3, 'W', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'D', 'a', 'o', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'P', 'a', ' ', 4, 'T', 'a', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'H', 'a', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 7, 'H', 'e', 's', 'a', 'k', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'C', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'Z', 'e', ' ', 4, 'D', 'u', 'o', ' ', 3, 'B', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'G', 'e', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 3, 'L', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'F', 'u', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 3, 'B', 'o', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'o', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 4, 'D', 'i', 'e', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'a', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'a', 'o', ' ', 5, 'C', 'a', 'n', 'g', ' ', 4, 'C', 'a', 'o', ' ', 4, 'L', 'o', 'u', ' ', 4, 'D', 'a', 'i', ' ', 5, 'S', 'o', 'r', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 7, 'Y', 'o', 'f', 'u', 'n', 'e', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 3, 'L', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'i', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 3, 'L', 'u', ' ', 3, 'L', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'G', 'e', 'n', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'S', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'C', 'a', 'o', ' ', 4, 'C', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'e', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'A', 'i', ' ', 4, 'N', 'a', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'e', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'C', 'h', 'a', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'M', 'i', 'e', ' ', 4, 'G', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'S', 'h', 'u', 'o', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'T', 'u', ' ', 4, 'X', 'i', 'a', ' ', 3, 'Q', 'i', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'S', 'u', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'B', 'i', ' ', 3, 'F', 'u', ' ', 4, 'T', 'u', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'W', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'W', 'e', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'R', 'e', 'n', ' ', 4, 'F', 'o', 'u', ' ', 4, 'K', 'o', 'u', ' ', 4, 'J', 'i', 'e', ' ', 3, 'L', 'u', ' ', 3, 'X', 'u', ' ', 3, 'J', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 3, 'B', 'a', ' ', 4, 'R', 'u', 'i', ' ', 4, 'X', 'i', 'n', ' ', 3, 'J', 'i', ' ', 4, 'H', 'u', 'a', ' ', 4, 'H', 'u', 'a', ' ', 5, 'F', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'J', 'u', 'e', ' ', 4, 'G', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'A', 'o', ' ', 4, 'C', 'h', 'u', ' ', 4, 'M', 'a', 'o', ' ', 3, 'Y', 'a', ' ', 4, 'F', 'e', 'i', ' ', 5, 'R', 'e', 'n', 'g', ' ', 5, 'H', 'a', 'n', 'g', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'S', 'u', 's', 'a', ' ', 4, 'W', 'e', 'i', ' ', 3, 'L', 'i', ' ', 3, 'P', 'i', ' ', 2, 'E', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'C', 'a', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'S', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'R', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'T', 'a', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'D', 'i', ' ', 5, 'M', 'i', 'a', 'o', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'K', 'e', ' ', 3, 'M', 'u', ' ', 4, 'P', 'e', 'i', ' ', 4, 'B', 'a', 'o', ' ', 4, 'G', 'o', 'u', ' ', 4, 'M', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'u', ' ', 3, 'P', 'i', ' ', 4, 'R', 'u', 'o', ' ', 3, 'K', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'N', 'i', ' ', 3, 'B', 'o', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'B', 'e', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'J', 'u', ' ', 4, 'D', 'i', 'e', ' ', 4, 'N', 'i', 'e', ' ', 4, 'G', 'a', 'n', ' ', 3, 'H', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 3, 'F', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'G', 'u', ' ', 3, 'B', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'F', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'M', 'a', 'o', ' ', 4, 'F', 'a', 'n', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'M', 'a', 'o', ' ', 4, 'M', 'a', 'o', ' ', 3, 'B', 'a', ' ', 3, 'Z', 'i', ' ', 3, 'M', 'o', ' ', 3, 'Z', 'i', ' ', 3, 'D', 'i', ' ', 4, 'C', 'h', 'i', ' ', 3, 'J', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'o', ' ', 4, 'X', 'u', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'G', 'e', ' ', 5, 'M', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'G', 'e', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'X', 'i', 'u', ' ', 3, 'Z', 'i', ' ', 4, 'L', 'i', 'e', ' ', 3, 'W', 'u', ' ', 3, 'J', 'i', ' ', 4, 'K', 'u', 'i', ' ', 3, 'C', 'e', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 3, 'C', 'i', ' ', 4, 'G', 'o', 'u', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'F', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'Z', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'C', 'h', 'a', ' ', 3, 'F', 'a', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'R', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'X', 'u', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'K', 'u', 'a', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'G', 'a', 'i', ' ', 3, 'D', 'a', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'C', 'a', 'o', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'E', 'r', ' ', 3, 'A', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'R', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'T', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'J', 'i', 'n', ' ', 4, 'L', 'a', 'o', ' ', 4, 'S', 'h', 'u', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'D', 'a', ' ', 4, 'J', 'i', 'a', ' ', 4, 'R', 'a', 'o', ' ', 3, 'B', 'i', ' ', 3, 'Z', 'e', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'H', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 4, 'J', 'i', 'n', ' ', 4, 'S', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'M', 'a', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'D', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'C', 'h', 'u', ' ', 4, 'D', 'o', 'u', ' ', 3, 'F', 'u', ' ', 4, 'R', 'e', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'H', 'e', ' ', 3, 'B', 'i', ' ', 3, 'B', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'D', 'i', ' ', 3, 'T', 'u', ' ', 4, 'S', 'u', 'i', ' ', 4, 'S', 'u', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'W', 'u', ' ', 4, 'B', 'i', 'e', ' ', 3, 'X', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 3, 'F', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'M', 'o', ' ', 3, 'L', 'i', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'D', 'u', 'o', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'S', 'h', 'a', ' ', 4, 'S', 'u', 'o', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'J', 'u', ' ', 4, 'M', 'e', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'e', ' ', 4, 'X', 'i', 'n', ' ', 4, 'J', 'u', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'C', 'u', 'o', ' ', 4, 'W', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'C', 'u', 'o', ' ', 4, 'J', 'i', 'a', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'N', 'i', 'u', ' ', 5, 'S', 'h', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 2, 'E', ' ', 3, 'M', 'o', ' ', 4, 'W', 'e', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'N', 'a', 'n', ' ', 3, 'M', 'u', ' ', 4, 'K', 'a', 'n', ' ', 4, 'L', 'a', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'W', 'o', ' ', 6, 'U', 's', 'a', 'g', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'N', 'u', 'c', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'M', 'a', 'n', 'g', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'C', 'i', ' ', 4, 'W', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'D', 'i', ' ', 3, 'Q', 'u', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'G', 'u', ' ', 3, 'L', 'a', ' ', 3, 'L', 'u', ' ', 3, 'J', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'J', 'u', 'n', ' ', 4, 'N', 'i', 'e', ' ', 4, 'K', 'u', 'n', ' ', 3, 'H', 'e', ' ', 3, 'P', 'u', ' ', 3, 'Z', 'i', ' ', 4, 'G', 'a', 'o', ' ', 4, 'G', 'u', 'o', ' ', 3, 'F', 'u', ' ', 4, 'L', 'u', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'M', 'e', 'n', ' ', 4, 'C', 'a', 'i', ' ', 3, 'B', 'a', ' ', 3, 'L', 'i', ' ', 3, 'T', 'u', ' ', 3, 'B', 'o', ' ', 4, 'H', 'a', 'n', ' ', 4, 'B', 'a', 'o', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'D', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'P', 'u', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'T', 'a', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'a', ' ', 3, 'G', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 4, 'J', 'i', 'n', ' ', 3, 'A', 'n', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'J', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 4, 'T', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'D', 'a', 'o', ' ', 3, 'H', 'u', ' ', 3, 'Q', 'i', ' ', 3, 'H', 'e', ' ', 4, 'C', 'u', 'i', ' ', 4, 'T', 'a', 'o', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'B', 'e', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'L', 'a', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 4, 'D', 'a', 'n', ' ', 4, 'S', 'h', 'a', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 4, 'W', 'a', 'n', ' ', 3, 'C', 'e', ' ', 4, 'N', 'a', 'i', ' ', 11, 'K', 'u', 't', 'a', 'b', 'i', 'r', 'e', 'r', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'J', 'i', 'u', ' ', 4, 'T', 'i', 'e', ' ', 4, 'L', 'u', 'o', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'Y', 'a', 'j', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'S', 'a', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'K', 'e', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'F', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 3, 'Z', 'e', ' ', 3, 'W', 'o', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 3, 'A', 'n', ' ', 2, 'E', ' ', 4, 'L', 'u', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 4, 'G', 'u', 'a', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'Z', 'u', 'o', ' ', 3, 'J', 'u', ' ', 4, 'B', 'a', 'o', ' ', 4, 'R', 'o', 'u', ' ', 3, 'X', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'A', 'n', ' ', 3, 'Q', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 3, 'L', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'P', 'e', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'H', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'T', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'Z', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'G', 'e', ' ', 4, 'J', 'i', 'e', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'M', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'P', 'u', ' ', 4, 'G', 'a', 'i', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'B', 'o', ' ', 4, 'W', 'e', 'i', ' ', 3, 'P', 'a', ' ', 3, 'J', 'i', ' ', 3, 'H', 'u', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'J', 'u', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 3, 'X', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'L', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'S', 'h', 'u', ' ', 3, 'D', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 7, 'S', 'u', 'k', 'u', 'm', 'o', ' ', 4, 'X', 'u', 'e', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'K', 'a', 'i', ' ', 4, 'K', 'u', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'L', 'o', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'P', 'a', 'i', ' ', 4, 'S', 'o', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'S', 'h', 'i', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'N', 'u', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'H', 'e', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'S', 'u', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'J', 'u', ' ', 3, 'X', 'i', ' ', 5, 'P', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'u', ' ', 3, 'X', 'u', ' ', 3, 'T', 'u', ' ', 4, 'L', 'i', 'u', ' ', 3, 'W', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'Z', 'u', ' ', 3, 'P', 'o', ' ', 4, 'C', 'u', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'K', 'u', 'a', 'i', ' ', 4, 'P', 'a', 'n', ' ', 3, 'P', 'u', ' ', 3, 'P', 'u', ' ', 3, 'N', 'a', ' ', 5, 'S', 'h', 'u', 'o', ' ', 3, 'X', 'i', ' ', 4, 'F', 'e', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'J', 'i', ' ', 4, 'R', 'u', 'o', ' ', 5, 'C', 'a', 'n', 'g', ' ', 3, 'E', 'n', ' ', 3, 'M', 'i', ' ', 4, 'H', 'a', 'o', ' ', 4, 'S', 'u', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'S', 'o', 'u', ' ', 3, 'X', 'u', ' ', 4, 'L', 'i', 'u', ' ', 3, 'X', 'i', ' ', 3, 'G', 'u', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'W', 'e', 'n', 'g', ' ', 4, 'G', 'a', 'i', ' ', 4, 'C', 'u', 'o', ' ', 4, 'S', 'h', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 3, 'R', 'u', ' ', 4, 'S', 'u', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'G', 'u', 'i', ' ', 3, 'B', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'G', 'u', 'n', ' ', 3, 'Z', 'a', ' ', 4, 'X', 'i', 'u', ' ', 3, 'C', 'e', ' ', 4, 'H', 'a', 'i', ' ', 4, 'L', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'L', 'i', ' ', 4, 'C', 'a', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'M', 'o', ' ', 5, 'D', 'i', 'a', 'o', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'M', 'a', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'A', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'J', 'i', 'n', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'W', 'e', 'i', ' ', 4, 'T', 'u', 'i', ' ', 4, 'C', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'i', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'B', 'i', ' ', 3, 'L', 'u', ' ', 3, 'S', 'u', ' ', 3, 'B', 'u', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'G', 'u', 'n', ' ', 4, 'H', 'a', 'n', ' ', 3, 'D', 'i', ' ', 3, 'S', 'u', ' ', 3, 'L', 'u', ' ', 4, 'S', 'h', 'e', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'M', 'i', 'e', ' ', 4, 'X', 'u', 'n', ' ', 4, 'M', 'a', 'n', ' ', 3, 'B', 'o', ' ', 3, 'D', 'i', ' ', 4, 'C', 'u', 'o', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'S', 'e', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'H', 'u', ' ', 3, 'A', 'o', ' ', 3, 'M', 'i', ' ', 4, 'L', 'o', 'u', ' ', 3, 'C', 'u', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'C', 'a', 'i', ' ', 3, 'P', 'o', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'M', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'o', ' ', 4, 'H', 'u', 'i', ' ', 4, 'J', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'K', 'u', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'H', 'u', ' ', 4, 'S', 'h', 'a', ' ', 4, 'K', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'M', 'a', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 7, 'S', 'o', 'n', 'o', 'k', 'o', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'D', 'o', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 4, 'K', 'o', 'u', ' ', 3, 'A', 'i', ' ', 3, 'B', 'i', ' ', 3, 'L', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'J', 'i', ' ', 4, 'X', 'u', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'F', 'a', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'O', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'R', 'u', 'i', ' ', 4, 'R', 'u', 'i', ' ', 4, 'L', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'C', 'h', 'u', ' ', 4, 'H', 'u', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'M', 'a', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'B', 'a', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'Q', 'u', ' ', 3, 'L', 'u', ' ', 4, 'R', 'a', 'o', ' ', 4, 'H', 'u', 'i', ' ', 2, 'E', ' ', 5, 'T', 'e', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'F', 'a', ' ', 3, 'R', 'u', ' ', 4, 'F', 'e', 'n', ' ', 4, 'K', 'u', 'i', ' ', 5, 'S', 'h', 'u', 'n', ' ', 4, 'R', 'u', 'i', ' ', 3, 'Y', 'a', ' ', 3, 'X', 'u', ' ', 3, 'F', 'u', ' ', 4, 'J', 'u', 'e', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'S', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'X', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'S', 'u', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'S', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'X', 'i', ' ', 4, 'H', 'a', 'o', ' ', 3, 'B', 'o', ' ', 4, 'H', 'a', 'o', ' ', 3, 'A', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'J', 'i', ' ', 3, 'C', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'M', 'i', 'e', ' ', 3, 'Y', 'i', ' ', 5, 'L', 'e', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'C', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'K', 'e', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'D', 'a', ' ', 3, 'T', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 3, 'B', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'S', 'u', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 3, 'G', 'u', ' ', 4, 'X', 'i', 'e', ' ', 4, 'S', 'h', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'K', 'a', 'o', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'S', 'a', ' ', 4, 'X', 'i', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'H', 'i', 'e', ' ', 4, 'S', 'o', 'u', ' ', 4, 'S', 'h', 'u', ' ', 4, 'X', 'u', 'n', ' ', 4, 'D', 'u', 'i', ' ', 4, 'P', 'i', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'N', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'M', 'a', 'i', ' ', 3, 'R', 'u', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'T', 'a', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'E', 'r', ' ', 3, 'N', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'G', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'F', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'K', 'u', 'i', ' ', 4, 'J', 'i', 'e', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'M', 'i', ' ', 4, 'L', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 5, 'C', 'a', 'n', 'g', ' ', 5, 'M', 'i', 'a', 'o', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'O', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'S', 'u', ' ', 3, 'L', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'X', 'u', ' ', 4, 'X', 'i', 'e', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'a', ' ', 4, 'L', 'e', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'B', 'e', 'i', ' ', 5, 'T', 'e', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'M', 'o', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'F', 'a', 'n', ' ', 4, 'S', 'o', 'u', ' ', 4, 'T', 'a', 'n', ' ', 4, 'T', 'u', 'i', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 4, 'L', 'i', 'u', ' ', 4, 'H', 'u', 'i', ' ', 4, 'G', 'a', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'L', 'i', ' ', 4, 'S', 'h', 'u', ' ', 4, 'C', 'h', 'u', ' ', 3, 'A', 'i', ' ', 4, 'L', 'i', 'n', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'L', 'a', 'i', ' ', 4, 'H', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 3, 'W', 'u', ' ', 4, 'R', 'u', 'i', ' ', 4, 'R', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'H', 'e', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'S', 'u', ' ', 4, 'T', 'u', 'i', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'P', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'X', 'u', 'n', ' ', 3, 'J', 'i', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'M', 'o', ' ', 5, 'H', 'a', 'g', 'i', ' ', 3, 'S', 'u', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'N', 'i', 'e', ' ', 3, 'B', 'o', ' ', 5, 'R', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'J', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'F', 'a', 'n', ' ', 3, 'M', 'i', ' ', 4, 'L', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'L', 'a', 'n', ' ', 3, 'J', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 8, 'K', 'a', 't', 's', 'u', 'r', 'a', ' ', 4, 'L', 'e', 'i', ' ', 4, 'L', 'e', 'i', ' ', 4, 'H', 'u', 'a', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'K', 'u', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'i', ' ', 3, 'L', 'i', ' ', 3, 'J', 'i', ' ', 3, 'M', 'i', ' ', 4, 'L', 'e', 'i', ' ', 5, 'H', 'u', 'a', 'i', ' ', 4, 'L', 'u', 'o', ' ', 3, 'J', 'i', ' ', 4, 'K', 'u', 'i', ' ', 3, 'L', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'M', 'e', 'n', ' ', 4, 'B', 'i', 'e', ' ', 3, 'H', 'u', ' ', 3, 'H', 'u', ' ', 3, 'L', 'u', ' ', 4, 'N', 'u', 'e', ' ', 3, 'L', 'u', ' ', 3, 'S', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 3, 'H', 'u', ' ', 3, 'X', 'u', ' ', 4, 'C', 'u', 'o', ' ', 3, 'F', 'u', ' ', 3, 'X', 'u', ' ', 3, 'X', 'u', ' ', 3, 'L', 'u', ' ', 3, 'H', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'H', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'J', 'u', ' ', 4, 'G', 'u', 'o', ' ', 4, 'B', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 4, 'B', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'S', 'h', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'S', 'h', 'e', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'G', 'e', ' ', 4, 'S', 'u', 'i', ' ', 4, 'X', 'i', 'a', ' ', 5, 'C', 'h', 'a', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'M', 'a', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 2, 'E', ' ', 3, 'P', 'a', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'n', ' ', 4, 'W', 'e', 'n', ' ', 4, 'R', 'u', 'i', ' ', 5, 'B', 'a', 'n', 'g', ' ', 3, 'B', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'J', 'u', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'R', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'Q', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 3, 'C', 'i', ' ', 3, 'M', 'u', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 4, 'F', 'e', 'n', ' ', 5, 'H', 'a', 'n', 'g', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'Z', 'a', 'o', ' ', 3, 'F', 'u', ' ', 4, 'R', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 3, 'F', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'D', 'o', 'u', ' ', 5, 'P', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'N', 'i', ' ', 3, 'T', 'e', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'H', 'e', ' ', 4, 'H', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'L', 'i', ' ', 3, 'F', 'u', ' ', 4, 'R', 'a', 'n', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'G', 'o', 'u', ' ', 3, 'P', 'i', ' ', 3, 'B', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'B', 'i', 'e', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'G', 'u', ' ', 4, 'R', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'S', 'h', 'e', ' ', 4, 'T', 'i', 'e', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'G', 'u', ' ', 4, 'D', 'a', 'n', ' ', 3, 'G', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 4, 'M', 'o', 'u', ' ', 3, 'G', 'e', ' ', 3, 'C', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'W', 'a', ' ', 4, 'L', 'i', 'e', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'K', 'u', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'J', 'i', ' ', 3, 'H', 'a', ' ', 4, 'S', 'h', 'e', ' ', 3, 'Y', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 3, 'M', 'o', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'G', 'u', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'M', 'a', 'n', ' ', 4, 'E', 'b', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'J', 'i', 'a', ' ', 4, 'R', 'a', 'o', ' ', 3, 'S', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'L', 'i', 'e', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'S', 'h', 'a', 'o', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 5, 'S', 'h', 'u', 'i', ' ', 4, 'C', 'h', 'e', ' ', 4, 'B', 'a', 'i', ' ', 2, 'E', ' ', 4, 'H', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'F', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'W', 'u', ' ', 3, 'F', 'u', ' ', 3, 'L', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'B', 'i', ' ', 4, 'C', 'h', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'D', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'u', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'G', 'u', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 3, 'J', 'u', ' ', 3, 'M', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'J', 'u', 'n', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'M', 'e', 'n', 'g', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'S', 'i', ' ', 3, 'X', 'i', ' ', 4, 'L', 'u', 'n', ' ', 3, 'L', 'i', ' ', 4, 'D', 'i', 'e', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'T', 'a', 'o', ' ', 4, 'K', 'u', 'n', ' ', 4, 'G', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 3, 'P', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'D', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'S', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'R', 'u', 'i', ' ', 3, 'N', 'i', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'o', ' ', 4, 'W', 'a', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 2, 'E', ' ', 4, 'B', 'a', 'n', ' ', 3, 'D', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'C', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'L', 'a', ' ', 3, 'K', 'e', ' ', 3, 'J', 'i', ' ', 3, 'H', 'e', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'M', 'a', 'i', ' ', 3, 'X', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'S', 'h', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'R', 'o', 'u', ' ', 4, 'W', 'e', 'i', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'F', 'u', ' ', 5, 'R', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'M', 'a', 'o', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'T', 'i', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'L', 'a', ' ', 3, 'D', 'u', ' ', 3, 'H', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'D', 'i', 'e', ' ', 3, 'L', 'i', ' ', 4, 'G', 'u', 'a', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'J', 'u', ' ', 4, 'N', 'a', 'n', ' ', 4, 'L', 'o', 'u', ' ', 4, 'Q', 'u', 'n', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'S', 'i', ' ', 3, 'X', 'i', ' ', 3, 'C', 'i', ' ', 3, 'X', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'W', 'e', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'S', 'o', 'u', ' ', 4, 'B', 'a', 'n', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 3, 'W', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'H', 'a', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'B', 'i', ' ', 4, 'H', 'u', 'a', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'D', 'u', ' ', 4, 'N', 'a', 'i', ' ', 3, 'H', 'e', ' ', 3, 'H', 'u', ' ', 4, 'H', 'u', 'i', ' ', 3, 'M', 'a', ' ', 5, 'M', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'W', 'e', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'T', 'e', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'C', 'a', 'n', 'g', ' ', 3, 'S', 'o', ' ', 4, 'E', 'b', 'i', ' ', 4, 'M', 'a', 'n', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'C', 'a', 'o', ' ', 4, 'C', 'h', 'i', ' ', 3, 'D', 'i', ' ', 3, 'A', 'o', ' ', 3, 'L', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 3, 'Q', 'u', ' ', 3, 'P', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 4, 'L', 'o', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 4, 'W', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'W', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'M', 'a', ' ', 3, 'M', 'a', ' ', 4, 'G', 'u', 'o', ' ', 4, 'L', 'i', 'u', ' ', 4, 'M', 'a', 'o', ' ', 3, 'X', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'M', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 9, 'K', 'a', 'm', 'a', 'k', 'i', 'r', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'M', 'a', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'M', 'o', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'S', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'T', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'Q', 'u', ' ', 4, 'B', 'i', 'e', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'P', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 3, 'X', 'i', ' ', 3, 'J', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 4, 'L', 'a', 'o', ' ', 4, 'J', 'u', 'e', ' ', 4, 'J', 'u', 'e', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'R', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'M', 'o', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 3, 'S', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'X', 'i', 'e', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'D', 'a', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'C', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'e', ' ', 4, 'L', 'u', 'o', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'i', ' ', 3, 'L', 'i', ' ', 3, 'Z', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'Z', 'e', ' ', 4, 'X', 'i', 'e', ' ', 5, 'M', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 3, 'Q', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'H', 'a', 'o', ' ', 5, 'R', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'J', 'i', 'e', ' ', 4, 'B', 'i', 'n', ' ', 3, 'H', 'e', ' ', 4, 'M', 'i', 'e', ' ', 4, 'F', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'L', 'a', ' ', 3, 'M', 'i', ' ', 3, 'L', 'i', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'L', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'N', 'i', 'e', ' ', 3, 'L', 'u', ' ', 3, 'D', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 5, 'B', 'e', 'n', 'g', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'G', 'u', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'X', 'i', ' ', 4, 'C', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'D', 'u', ' ', 4, 'C', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 4, 'J', 'i', 'e', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'X', 'i', 'e', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'N', 'i', 'u', ' ', 4, 'P', 'e', 'i', ' ', 3, 'N', 'u', ' ', 4, 'X', 'i', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'M', 'o', ' ', 3, 'E', 'r', ' ', 3, 'K', 'e', ' ', 4, 'M', 'i', 'e', ' ', 3, 'X', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'K', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 3, 'H', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'D', 'a', 'o', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 4, 'D', 'a', 'o', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'B', 'u', ' ', 4, 'G', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'C', 'h', 'a', ' ', 3, 'Y', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'F', 'u', ' ', 4, 'G', 'u', 'n', ' ', 4, 'F', 'e', 'n', ' ', 6, 'S', 'h', 'u', 'a', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'N', 'a', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'D', 'a', 'n', ' ', 3, 'R', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 3, 'Q', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'R', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'R', 'e', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'J', 'i', 'n', ' ', 4, 'J', 'u', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 5, 'C', 'h', 'a', 'i', ' ', 3, 'A', 'o', ' ', 5, 'N', 'i', 'a', 'o', ' ', 4, 'H', 'u', 'i', ' ', 4, 'R', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 4, 'T', 'u', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 4, 'B', 'a', 'o', ' ', 4, 'P', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Z', 'u', 'o', ' ', 3, 'B', 'i', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'T', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'H', 'e', ' ', 4, 'S', 'h', 'u', ' ', 4, 'X', 'i', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'P', 'a', ' ', 3, 'B', 'o', ' ', 3, 'D', 'i', ' ', 3, 'W', 'a', ' ', 3, 'F', 'u', ' ', 4, 'G', 'u', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'R', 'a', 'n', ' ', 4, 'P', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'M', 'a', 'o', ' ', 4, 'T', 'u', 'o', ' ', 3, 'N', 'a', ' ', 4, 'K', 'o', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'B', 'e', 'i', ' ', 4, 'G', 'u', 'n', ' ', 3, 'X', 'i', ' ', 3, 'N', 'e', ' ', 3, 'B', 'o', ' ', 5, 'H', 'o', 'r', 'o', ' ', 3, 'F', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'h', 'i', ' ', 3, 'K', 'u', ' ', 4, 'R', 'e', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 4, 'C', 'u', 'n', ' ', 3, 'M', 'o', ' ', 4, 'J', 'i', 'e', ' ', 3, 'E', 'r', ' ', 4, 'L', 'u', 'o', ' ', 3, 'R', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'C', 'a', 'i', ' ', 4, 'L', 'i', 'e', ' ', 10, 'K', 'a', 'm', 'i', 's', 'h', 'i', 'm', 'o', ' ', 5, 'Y', 'u', 'k', 'i', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'K', 'u', 'n', ' ', 4, 'K', 'e', 'n', ' ', 5, 'N', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'u', ' ', 4, 'J', 'i', 'a', ' ', 4, 'K', 'u', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'P', 'o', 'u', ' ', 3, 'G', 'e', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'L', 'i', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'Q', 'u', 'n', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'B', 'u', ' ', 7, 'Z', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'i', ' ', 4, 'S', 'h', 'a', ' ', 4, 'Q', 'u', 'n', ' ', 3, 'L', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'K', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'F', 'o', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'G', 'u', 'n', ' ', 4, 'T', 'a', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'D', 'u', 'o', ' ', 5, 'B', 'i', 'a', 'o', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'P', 'e', 'i', ' ', 4, 'P', 'e', 'i', ' ', 4, 'F', 'e', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 4, 'G', 'u', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'D', 'u', ' ', 3, 'X', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'J', 'u', ' ', 3, 'Q', 'i', ' ', 3, 'J', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'G', 'u', 'a', ' ', 4, 'K', 'e', 'n', ' ', 4, 'C', 'h', 'e', ' ', 3, 'T', 'i', ' ', 3, 'T', 'i', ' ', 3, 'F', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'D', 'i', 'e', ' ', 4, 'K', 'u', 'n', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'u', ' ', 4, 'X', 'i', 'u', ' ', 3, 'H', 'e', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'B', 'a', 'o', ' ', 4, 'B', 'a', 'o', ' ', 3, 'F', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'B', 'e', 'i', ' ', 4, 'C', 'h', 'u', ' ', 3, 'L', 'u', ' ', 4, 'E', 'n', 'a', ' ', 6, 'H', 'i', 't', 'o', 'e', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'D', 'a', ' ', 4, 'G', 'o', 'u', ' ', 3, 'D', 'a', ' ', 5, 'H', 'u', 'a', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'R', 'u', ' ', 4, 'N', 'a', 'i', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 4, 'B', 'a', 'n', ' ', 4, 'T', 'u', 'n', ' ', 4, 'C', 'h', 'i', ' ', 5, 'S', 'a', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'o', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'i', ' ', 3, 'K', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'B', 'a', 'o', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'S', 'h', 'i', ' ', 3, 'L', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'D', 'i', 'e', ' ', 4, 'X', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'C', 'a', 'o', ' ', 3, 'J', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'S', 'e', 'n', ' ', 4, 'B', 'a', 'o', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 8, 'C', 'h', 'i', 'h', 'a', 'y', 'a', ' ', 3, 'P', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'J', 'i', ' ', 4, 'D', 'a', 'n', ' ', 3, 'Z', 'a', ' ', 4, 'F', 'a', 'n', ' ', 3, 'B', 'o', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'n', ' ', 4, 'B', 'i', 'e', ' ', 4, 'R', 'a', 'o', ' ', 4, 'M', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'A', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'G', 'u', 'i', ' ', 4, 'C', 'a', 'o', ' ', 4, 'S', 'u', 'i', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'J', 'i', 'n', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 4, 'T', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'L', 'a', 'n', ' ', 3, 'P', 'u', ' ', 3, 'R', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'S', 'h', 'u', ' ', 3, 'W', 'a', ' ', 4, 'S', 'h', 'i', ' ', 4, 'B', 'a', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'B', 'o', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'L', 'a', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'D', 'a', 'i', ' ', 7, 'T', 'a', 's', 'u', 'k', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'P', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'R', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'F', 'u', ' ', 3, 'B', 'a', ' ', 3, 'H', 'e', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 4, 'J', 'u', 'e', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 3, 'M', 'i', ' ', 3, 'M', 'i', ' ', 4, 'M', 'i', 'e', ' ', 4, 'S', 'h', 'i', ' ', 3, 'S', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 4, 'J', 'u', 'e', ' ', 3, 'M', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'J', 'u', 'n', ' ', 3, 'X', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'X', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'L', 'a', 'n', ' ', 2, 'E', ' ', 3, 'D', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'M', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'G', 'o', 'u', ' ', 3, 'Q', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 3, 'Q', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'J', 'u', 'e', ' ', 3, 'Q', 'u', ' ', 4, 'L', 'u', 'o', ' ', 4, 'L', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'D', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 3, 'M', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 3, 'J', 'i', ' ', 3, 'X', 'i', ' ', 3, 'D', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'o', 'u', ' ', 4, 'J', 'i', 'n', ' ', 3, 'Q', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'u', ' ', 4, 'J', 'i', 'n', ' ', 3, 'C', 'u', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'G', 'u', ' ', 4, 'D', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'D', 'i', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'a', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'G', 'e', ' ', 4, 'C', 'h', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'G', 'u', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 4, 'H', 'u', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'S', 'u', ' ', 3, 'N', 'i', ' ', 3, 'J', 'i', ' ', 3, 'L', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'B', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'H', 'u', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'X', 'u', 'e', ' ', 4, 'C', 'h', 'u', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'u', ' ', 4, 'J', 'u', 'e', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'C', 'h', 'a', ' ', 4, 'T', 'a', 'o', ' ', 3, 'X', 'u', ' ', 4, 'J', 'i', 'e', ' ', 3, 'Y', 'i', ' ', 4, 'R', 'e', 'n', ' ', 4, 'X', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'T', 'u', 'o', ' ', 3, 'J', 'i', ' ', 4, 'X', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 2, 'E', ' ', 4, 'F', 'e', 'n', ' ', 3, 'Y', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'X', 'i', 'n', ' ', 4, 'J', 'u', 'e', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'N', 'e', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'n', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'S', 'h', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'a', ' ', 4, 'T', 'u', 'n', ' ', 3, 'X', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'S', 'u', ' ', 4, 'C', 'h', 'i', ' ', 3, 'H', 'e', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'H', 'e', ' ', 3, 'X', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'G', 'o', 'u', ' ', 3, 'Z', 'i', ' ', 3, 'Z', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'G', 'u', ' ', 3, 'F', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'D', 'i', 'e', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'D', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'N', 'a', 'o', ' ', 4, 'P', 'a', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'G', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'u', ' ', 3, 'A', 'o', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'T', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'u', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'B', 'i', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 3, 'B', 'a', ' ', 3, 'D', 'a', ' ', 3, 'Z', 'u', ' ', 4, 'T', 'a', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'C', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'X', 'u', ' ', 4, 'X', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'H', 'e', ' ', 4, 'S', 'h', 'i', ' ', 4, 'C', 'h', 'a', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 4, 'H', 'e', 'n', ' ', 4, 'C', 'h', 'a', ' ', 4, 'G', 'o', 'u', ' ', 4, 'G', 'u', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'H', 'u', 'a', ' ', 4, 'G', 'a', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'M', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 2, 'E', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 4, 'G', 'u', 'a', ' ', 3, 'E', 'r', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'C', 'h', 'i', ' ', 4, 'L', 'e', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'K', 'u', 'a', ' ', 3, 'W', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'T', 'e', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'R', 'e', 'n', ' ', 3, 'S', 'u', ' ', 5, 'L', 'a', 'n', 'g', ' ', 2, 'E', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 2, 'E', ' ', 4, 'S', 'h', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'D', 'a', 'n', ' ', 3, 'B', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'S', 'h', 'u', 'a', ' ', 3, 'A', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'W', 'u', ' ', 4, 'G', 'a', 'o', ' ', 5, 'S', 'o', 'n', 'g', ' ', 3, 'P', 'u', ' ', 4, 'H', 'u', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'S', 'h', 'u', 'o', ' ', 3, 'D', 'u', ' ', 8, 'Y', 'a', 's', 'a', 's', 'h', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'i', ' ', 4, 'J', 'i', 'e', ' ', 3, 'K', 'e', ' ', 3, 'Q', 'u', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'S', 'u', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'C', 'h', 'i', ' ', 3, 'T', 'a', ' ', 3, 'Y', 'i', ' ', 3, 'N', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'P', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 3, 'J', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'T', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'J', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'Z', 'e', ' ', 4, 'Z', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'H', 'a', 'o', ' ', 4, 'L', 'u', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'H', 'u', 'a', 'i', ' ', 5, 'P', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'D', 'i', 'e', ' ', 3, 'X', 'u', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'H', 'u', 'n', ' ', 4, 'H', 'u', 'a', ' ', 2, 'E', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'F', 'u', ' ', 3, 'P', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'Z', 'i', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'A', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'G', 'e', ' ', 4, 'N', 'u', 'o', ' ', 3, 'Q', 'i', ' ', 4, 'M', 'o', 'u', ' ', 3, 'Y', 'e', ' ', 4, 'W', 'e', 'i', ' ', 5, 'T', 'e', 'n', 'g', ' ', 4, 'Z', 'o', 'u', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'B', 'o', ' ', 3, 'K', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 3, 'G', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'M', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'M', 'i', ' ', 3, 'X', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'N', 'u', 'e', ' ', 3, 'T', 'i', ' ', 3, 'S', 'u', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'X', 'u', 'e', ' ', 4, 'T', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 3, 'M', 'o', ' ', 3, 'M', 'o', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'M', 'i', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Z', 'e', ' ', 4, 'J', 'i', 'e', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'L', 'o', 'u', ' ', 4, 'C', 'a', 'n', ' ', 3, 'O', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'A', 'o', ' ', 3, 'A', 'o', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'Y', 'i', ' ', 3, 'H', 'u', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'H', 'a', 'n', ' ', 4, 'H', 'u', 'a', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'X', 'u', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 3, 'S', 'e', ' ', 3, 'X', 'i', ' ', 4, 'S', 'h', 'e', ' ', 4, 'D', 'u', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'N', 'a', 'o', ' ', 4, 'L', 'a', 'n', ' ', 2, 'E', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 3, 'J', 'i', ' ', 4, 'Z', 'u', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'B', 'o', ' ', 4, 'H', 'u', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 3, 'M', 'u', ' ', 4, 'Z', 'e', 'n', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'S', 'h', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'T', 'a', 'n', ' ', 4, 'Z', 'e', 'n', ' ', 3, 'P', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'T', 'a', 'n', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'J', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'N', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'A', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'P', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'H', 'u', 'a', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'R', 'a', 'n', 'g', ' ', 4, 'N', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'T', 'a', ' ', 3, 'H', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'H', 'a', 'o', ' ', 3, 'Y', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'D', 'u', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 2, 'E', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'W', 'e', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'R', 'a', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'L', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'D', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'J', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'R', 'e', 'n', ' ', 3, 'J', 'i', ' ', 4, 'J', 'i', 'e', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'T', 'a', 'o', ' ', 5, 'R', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'T', 'u', 'o', ' ', 4, 'X', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'u', 'n', ' ', 3, 'J', 'i', ' ', 4, 'R', 'e', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 3, 'O', 'u', ' ', 3, 'J', 'u', ' ', 3, 'Y', 'a', ' ', 3, 'N', 'e', ' ', 3, 'X', 'u', ' ', 2, 'E', ' ', 4, 'L', 'u', 'n', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'e', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'G', 'u', ' ', 3, 'H', 'e', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'Z', 'u', ' ', 4, 'S', 'h', 'i', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'S', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'C', 'i', ' ', 3, 'Q', 'u', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'B', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'G', 'u', 'a', ' ', 4, 'S', 'h', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'H', 'u', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'H', 'u', 'a', ' ', 4, 'D', 'a', 'n', ' ', 4, 'G', 'o', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 4, 'X', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'G', 'a', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'a', ' ', 4, 'H', 'u', 'n', ' ', 3, 'X', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'J', 'i', 'e', ' ', 3, 'W', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'W', 'u', ' ', 4, 'G', 'a', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'H', 'u', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'o', ' ', 5, 'S', 'o', 'n', 'g', ' ', 3, 'A', 'i', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'o', 'u', ' ', 4, 'N', 'u', 'o', ' ', 3, 'D', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'F', 'e', 'i', ' ', 3, 'K', 'e', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'S', 'h', 'u', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 4, 'S', 'u', 'i', ' ', 4, 'T', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'M', 'o', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'D', 'i', 'e', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'N', 'u', 'e', ' ', 3, 'Y', 'e', ' ', 4, 'W', 'e', 'i', ' ', 2, 'E', ' ', 3, 'Y', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 3, 'A', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'D', 'i', ' ', 3, 'M', 'i', ' ', 5, 'P', 'i', 'a', 'n', ' ', 3, 'X', 'u', ' ', 3, 'M', 'o', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'S', 'u', ' ', 4, 'X', 'i', 'e', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'M', 'i', ' ', 4, 'J', 'i', 'n', ' ', 4, 'M', 'a', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'M', 'i', 'u', ' ', 4, 'T', 'a', 'n', ' ', 4, 'Z', 'e', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'L', 'a', 'n', ' ', 3, 'P', 'u', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'G', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 4, 'J', 'u', 'e', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'X', 'i', ' ', 4, 'H', 'u', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'H', 'a', 'n', ' ', 3, 'D', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'D', 'o', 'u', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'L', 'i', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'S', 'h', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'C', 'h', 'u', ' ', 4, 'H', 'u', 'i', ' ', 4, 'T', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'T', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'B', 'a', ' ', 4, 'H', 'o', 'u', ' ', 2, 'E', ' ', 3, 'C', 'u', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'K', 'e', 'n', ' ', 4, 'G', 'a', 'i', ' ', 3, 'Q', 'u', ' ', 3, 'F', 'u', ' ', 3, 'X', 'i', ' ', 4, 'B', 'i', 'n', ' ', 4, 'H', 'a', 'o', ' ', 3, 'Y', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'J', 'i', 'a', ' ', 3, 'X', 'i', ' ', 3, 'B', 'o', ' ', 4, 'W', 'e', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'B', 'i', 'n', ' ', 3, 'D', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'B', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'i', ' ', 4, 'H', 'a', 'n', ' ', 3, 'P', 'i', ' ', 3, 'N', 'a', ' ', 3, 'P', 'i', ' ', 4, 'G', 'o', 'u', ' ', 3, 'N', 'a', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'M', 'o', ' ', 3, 'S', 'i', ' ', 4, 'X', 'i', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'K', 'u', 'n', ' ', 3, 'H', 'e', ' ', 3, 'H', 'e', ' ', 3, 'M', 'o', ' ', 4, 'H', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 3, 'L', 'i', ' ', 3, 'N', 'i', ' ', 3, 'B', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'J', 'i', 'a', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 3, 'P', 'i', ' ', 3, 'X', 'i', ' ', 2, 'E', ' ', 3, 'J', 'u', ' ', 3, 'M', 'o', ' ', 4, 'C', 'h', 'u', ' ', 4, 'T', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 4, 'B', 'e', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'C', 'a', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 3, 'T', 'e', ' ', 3, 'Y', 'i', ' ', 5, 'H', 'a', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 4, 'P', 'i', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'F', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'Z', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'E', 'r', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'S', 'h', 'i', ' ', 3, 'B', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'E', 'r', ' ', 4, 'G', 'u', 'i', ' ', 5, 'P', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'M', 'a', 'i', ' ', 4, 'D', 'a', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'i', ' ', 4, 'T', 'i', 'e', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'h', 'i', ' ', 4, 'M', 'a', 'o', ' ', 3, 'H', 'e', ' ', 3, 'B', 'i', ' ', 3, 'L', 'u', ' ', 4, 'R', 'e', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'G', 'a', 'i', ' ', 5, 'P', 'i', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 4, 'J', 'i', 'a', ' ', 3, 'X', 'u', ' ', 4, 'Z', 'e', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'G', 'a', 'i', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'S', 'h', 'e', ' ', 4, 'B', 'i', 'n', ' ', 4, 'B', 'i', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'S', 'h', 'e', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'L', 'a', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'S', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'P', 'e', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'M', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'S', 'u', 'i', ' ', 3, 'F', 'u', ' ', 4, 'T', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'J', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 3, 'D', 'u', ' ', 4, 'J', 'i', 'n', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'B', 'a', 'o', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'L', 'a', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'C', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'A', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'G', 'o', 'u', ' ', 4, 'S', 'a', 'i', ' ', 3, 'Z', 'e', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 4, 'B', 'a', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'W', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 4, 'G', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 3, 'B', 'i', ' ', 3, 'D', 'u', ' ', 4, 'S', 'h', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'B', 'e', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'C', 'a', 'i', ' ', 3, 'Z', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'B', 'a', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 4, 'P', 'i', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'G', 'o', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'E', 'r', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'T', 'i', 'e', ' ', 4, 'G', 'u', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 4, 'M', 'a', 'o', ' ', 4, 'F', 'e', 'i', ' ', 3, 'H', 'e', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'e', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'J', 'i', 'a', ' ', 4, 'H', 'u', 'i', ' ', 3, 'Z', 'i', ' ', 4, 'R', 'e', 'n', ' ', 3, 'L', 'u', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 4, 'G', 'a', 'i', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'L', 'a', 'i', ' ', 4, 'S', 'h', 'e', ' ', 3, 'F', 'u', ' ', 3, 'D', 'u', ' ', 3, 'J', 'i', ' ', 4, 'S', 'h', 'u', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'S', 'i', ' ', 3, 'B', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'P', 'e', 'i', ' ', 4, 'T', 'a', 'n', ' ', 4, 'L', 'a', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'F', 'u', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'S', 'a', 'i', ' ', 3, 'Z', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'G', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 3, 'X', 'i', ' ', 4, 'S', 'h', 'e', ' ', 4, 'N', 'a', 'n', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'H', 'e', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'X', 'i', 'a', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'Z', 'o', 'u', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'L', 'i', ' ', 4, 'J', 'i', 'u', ' ', 3, 'F', 'u', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'G', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'C', 'i', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'C', 'h', 'i', ' ', 3, 'C', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'D', 'i', 'e', ' ', 3, 'J', 'u', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'D', 'i', ' ', 3, 'S', 'e', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'Q', 'u', ' ', 4, 'J', 'i', 'e', ' ', 4, 'C', 'h', 'i', ' ', 4, 'C', 'h', 'u', ' ', 4, 'G', 'u', 'a', ' ', 4, 'X', 'u', 'e', ' ', 3, 'C', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'L', 'i', 'e', ' ', 4, 'G', 'a', 'n', ' ', 4, 'S', 'u', 'o', ' ', 3, 'C', 'u', ' ', 3, 'X', 'i', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'S', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'J', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'o', ' ', 4, 'C', 'u', 'i', ' ', 3, 'L', 'u', ' ', 3, 'Q', 'u', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'Z', 'i', ' ', 3, 'T', 'i', ' ', 3, 'Q', 'u', ' ', 4, 'C', 'h', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Z', 'a', 'o', ' ', 3, 'T', 'i', ' ', 4, 'Z', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'Z', 'u', ' ', 3, 'P', 'a', ' ', 4, 'B', 'a', 'o', ' ', 3, 'K', 'u', ' ', 3, 'K', 'e', ' ', 4, 'D', 'u', 'n', ' ', 4, 'J', 'u', 'e', ' ', 3, 'F', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'S', 'a', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'P', 'a', ' ', 3, 'Q', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'T', 'u', 'o', ' ', 4, 'T', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'N', 'i', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'M', 'e', 'i', ' ', 3, 'B', 'a', ' ', 4, 'D', 'i', 'e', ' ', 3, 'K', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'J', 'i', 'a', ' ', 3, 'C', 'i', ' ', 4, 'P', 'a', 'o', ' ', 4, 'Q', 'i', 'a', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'J', 'u', ' ', 4, 'D', 'i', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'F', 'u', ' ', 4, 'P', 'a', 'n', ' ', 3, 'J', 'u', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'B', 'o', ' ', 3, 'N', 'i', ' ', 3, 'J', 'u', ' ', 3, 'L', 'i', ' ', 4, 'G', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'i', ' ', 4, 'D', 'a', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'D', 'u', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'K', 'u', 'a', ' ', 6, 'Z', 'h', 'u', 'a', 'i', ' ', 4, 'G', 'u', 'i', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'C', 'h', 'i', ' ', 3, 'L', 'u', ' ', 5, 'B', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'J', 'i', 'a', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'C', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'T', 'a', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'B', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 3, 'J', 'i', ' ', 3, 'J', 'u', ' ', 3, 'J', 'i', ' ', 4, 'S', 'h', 'u', ' ', 3, 'T', 'u', ' ', 4, 'C', 'h', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'N', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'B', 'o', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Q', 'u', 'n', ' ', 4, 'M', 'o', 'u', ' ', 4, 'S', 'h', 'u', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'T', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'W', 'o', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'J', 'i', 'e', ' ', 3, 'J', 'i', ' ', 4, 'N', 'i', 'e', ' ', 3, 'J', 'u', ' ', 3, 'J', 'u', ' ', 4, 'L', 'u', 'n', ' ', 3, 'L', 'u', ' ', 5, 'L', 'e', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'i', ' ', 3, 'J', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'W', 'a', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'T', 'i', ' ', 3, 'B', 'o', ' ', 3, 'Z', 'u', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'J', 'i', ' ', 3, 'C', 'u', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'C', 'a', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'u', 'n', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'C', 'h', 'e', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'a', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'J', 'u', ' ', 3, 'F', 'u', ' ', 3, 'Z', 'u', ' ', 4, 'D', 'i', 'e', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'R', 'o', 'u', ' ', 4, 'N', 'u', 'o', ' ', 3, 'T', 'i', ' ', 4, 'C', 'h', 'a', ' ', 4, 'T', 'u', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'D', 'a', 'o', ' ', 4, 'C', 'u', 'o', ' ', 3, 'X', 'i', ' ', 3, 'T', 'a', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'T', 'i', ' ', 3, 'J', 'i', ' ', 4, 'N', 'i', 'e', ' ', 4, 'M', 'a', 'n', ' ', 4, 'L', 'i', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'B', 'i', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 3, 'L', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'C', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 4, 'S', 'u', 'o', ' ', 3, 'X', 'i', ' ', 4, 'K', 'u', 'i', ' ', 3, 'J', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'M', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'B', 'e', 'n', 'g', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'B', 'i', 'e', ' ', 4, 'T', 'u', 'i', ' ', 3, 'J', 'u', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'C', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'D', 'u', 'n', ' ', 3, 'B', 'o', ' ', 3, 'C', 'u', ' ', 3, 'Z', 'u', ' ', 4, 'J', 'u', 'e', ' ', 4, 'J', 'u', 'e', ' ', 4, 'L', 'i', 'n', ' ', 3, 'T', 'a', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'P', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'D', 'u', 'n', ' ', 5, 'C', 'u', 'a', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'Z', 'a', 'o', ' ', 3, 'T', 'a', ' ', 3, 'B', 'i', ' ', 3, 'B', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'J', 'u', ' ', 4, 'C', 'h', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'D', 'u', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 3, 'J', 'i', ' ', 3, 'W', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 4, 'L', 'i', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 5, 'R', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'e', ' ', 4, 'N', 'i', 'e', ' ', 3, 'T', 'a', ' ', 3, 'Q', 'u', ' ', 4, 'J', 'i', 'e', ' ', 5, 'C', 'u', 'a', 'n', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'K', 'u', 'i', ' ', 4, 'J', 'u', 'e', ' ', 4, 'L', 'i', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'D', 'a', 'n', ' ', 7, 'S', 'e', 'g', 'a', 'r', 'e', ' ', 3, 'Q', 'u', ' ', 3, 'T', 'i', ' ', 4, 'D', 'u', 'o', ' ', 4, 'D', 'u', 'o', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'L', 'a', 'n', 'g', ' ', 6, 'N', 'e', 'r', 'a', 'u', ' ', 4, 'L', 'u', 'o', ' ', 3, 'A', 'i', ' ', 3, 'J', 'i', ' ', 3, 'J', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 7, 'U', 't', 's', 'u', 'k', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 9, 'S', 'h', 'i', 't', 's', 'u', 'k', 'e', ' ', 5, 'K', 'a', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 4, 'L', 'o', 'u', ' ', 4, 'L', 'a', 'o', ' ', 4, 'T', 'u', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 7, 'Y', 'a', 'g', 'a', 't', 'e', ' ', 3, 'T', 'i', ' ', 4, 'D', 'a', 'o', ' ', 7, 'Y', 'a', 'g', 'a', 't', 'e', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'h', 'e', ' ', 3, 'Y', 'a', ' ', 4, 'G', 'u', 'i', ' ', 4, 'J', 'u', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'X', 'i', 'n', ' ', 3, 'D', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'R', 'e', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 4, 'T', 'u', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'D', 'a', 'i', ' ', 2, 'E', ' ', 3, 'N', 'a', ' ', 3, 'Q', 'i', ' ', 4, 'M', 'a', 'o', ' ', 5, 'R', 'u', 'a', 'n', ' ', 4, 'R', 'e', 'n', ' ', 4, 'F', 'a', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'H', 'u', ' ', 3, 'Q', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 3, 'D', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 3, 'A', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'F', 'a', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'A', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'B', 'e', 'i', ' ', 3, 'G', 'u', ' ', 3, 'K', 'u', ' ', 4, 'P', 'a', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'R', 'o', 'n', 'g', ' ', 2, 'E', ' ', 3, 'B', 'a', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'K', 'e', ' ', 3, 'Y', 'i', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'E', 'r', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 3, 'J', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 3, 'L', 'u', ' ', 4, 'K', 'a', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'S', 'h', 'e', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'W', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'N', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 4, 'H', 'u', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'o', ' ', 4, 'G', 'u', 'o', ' ', 4, 'K', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'n', ' ', 5, 'N', 'i', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 4, 'L', 'u', 'n', ' ', 4, 'P', 'a', 'i', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'R', 'u', 'a', 'n', ' ', 4, 'R', 'o', 'u', ' ', 3, 'J', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'C', 'o', 'u', ' ', 4, 'Q', 'u', 'n', ' ', 3, 'G', 'e', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 3, 'F', 'u', ' ', 3, 'Z', 'i', ' ', 3, 'F', 'u', ' ', 4, 'W', 'e', 'n', ' ', 4, 'B', 'e', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'W', 'e', 'n', ' ', 4, 'T', 'a', 'o', ' ', 3, 'G', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'J', 'i', 'u', ' ', 5, 'C', 'h', 'a', 'o', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'H', 'u', 'n', ' ', 5, 'S', 'o', 'r', 'i', ' ', 4, 'C', 'h', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'P', 'u', ' ', 4, 'L', 'a', 'o', ' ', 4, 'F', 'e', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 3, 'G', 'e', ' ', 3, 'S', 'e', ' ', 4, 'K', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'i', ' ', 4, 'D', 'u', 'i', ' ', 3, 'E', 'r', ' ', 3, 'Y', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 4, 'P', 'e', 'i', ' ', 3, 'L', 'i', ' ', 3, 'L', 'i', ' ', 3, 'L', 'u', ' ', 4, 'L', 'i', 'n', ' ', 4, 'C', 'h', 'e', ' ', 3, 'Y', 'a', ' ', 4, 'G', 'u', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'D', 'i', ' ', 4, 'R', 'e', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 2, 'E', ' ', 4, 'L', 'u', 'n', ' ', 5, 'R', 'u', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'K', 'u', ' ', 3, 'K', 'e', ' ', 3, 'L', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'H', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Z', 'a', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'L', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'F', 'u', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 4, 'H', 'u', 'i', ' ', 4, 'G', 'u', 'n', ' ', 5, 'W', 'a', 'n', 'g', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'Z', 'i', ' ', 4, 'C', 'o', 'u', ' ', 3, 'F', 'u', ' ', 3, 'J', 'i', ' ', 4, 'W', 'e', 'n', ' ', 4, 'S', 'h', 'u', ' ', 4, 'P', 'e', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'C', 'h', 'e', ' ', 4, 'L', 'i', 'n', ' ', 4, 'X', 'i', 'n', ' ', 3, 'G', 'u', ' ', 3, 'C', 'i', ' ', 3, 'C', 'i', ' ', 3, 'P', 'i', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'L', 'a', ' ', 3, 'L', 'a', ' ', 3, 'C', 'i', ' ', 4, 'X', 'u', 'e', ' ', 4, 'B', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 3, 'C', 'i', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'R', 'u', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'u', 'o', ' ', 5, 'C', 'h', 'u', 'o', ' ', 7, 'S', 'u', 'b', 'e', 'r', 'u', ' ', 5, 'R', 'e', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'S', 'i', 'p', ' ', 3, 'I', 'p', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'D', 'a', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'X', 'u', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'G', 'u', 'o', ' ', 4, 'M', 'a', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'Z', 'a', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'T', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'J', 'i', 'n', ' ', 5, 'H', 'a', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 4, 'F', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'D', 'a', ' ', 2, 'E', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 7, 'T', 'o', 't', 'e', 'm', 'o', ' ', 4, 'J', 'i', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'C', 'h', 'e', ' ', 3, 'N', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Y', 'i', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'D', 'a', 'i', ' ', 3, 'E', 'r', ' ', 3, 'D', 'i', ' ', 3, 'P', 'o', ' ', 5, 'W', 'a', 'n', 'g', ' ', 4, 'D', 'i', 'e', ' ', 3, 'Z', 'e', ' ', 4, 'T', 'a', 'o', ' ', 4, 'S', 'h', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'K', 'e', 'p', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'i', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'M', 'i', ' ', 5, 'B', 'e', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'N', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'i', 'e', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 4, 'L', 'i', 'e', ' ', 4, 'X', 'u', 'n', ' ', 4, 'T', 'u', 'i', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'G', 'u', 'a', ' ', 4, 'T', 'a', 'o', ' ', 5, 'P', 'a', 'n', 'g', ' ', 4, 'H', 'o', 'u', ' ', 3, 'N', 'i', ' ', 4, 'D', 'u', 'n', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 3, 'B', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'T', 'o', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'D', 'i', ' ', 3, 'D', 'i', ' ', 3, 'T', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'T', 'i', ' ', 4, 'D', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'T', 'o', 'n', 'g', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 4, 'S', 'h', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 3, 'S', 'u', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'Q', 'u', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'S', 'u', 'o', ' ', 4, 'H', 'u', 'i', ' ', 3, 'L', 'i', ' ', 5, 'S', 'a', 'k', 'o', ' ', 4, 'L', 'a', 'i', ' ', 4, 'B', 'e', 'n', ' ', 4, 'C', 'u', 'o', ' ', 4, 'J', 'u', 'e', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'D', 'a', 'i', ' ', 3, 'L', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'J', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'C', 'h', 'u', 'o', ' ', 4, 'K', 'u', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'T', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'D', 'a', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 3, 'B', 'i', ' ', 4, 'N', 'u', 'o', ' ', 3, 'Y', 'u', ' ', 5, 'D', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 4, 'D', 'u', 'n', ' ', 4, 'S', 'u', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 3, 'T', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'S', 'h', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 2, 'E', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'o', ' ', 2, 'E', ' ', 4, 'X', 'i', 'a', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'D', 'a', 'o', ' ', 3, 'D', 'a', ' ', 4, 'W', 'e', 'i', ' ', 7, 'A', 'p', 'p', 'a', 'r', 'e', ' ', 3, 'Y', 'i', ' ', 4, 'G', 'o', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'C', 'h', 'u', ' ', 4, 'L', 'i', 'u', ' ', 4, 'X', 'u', 'n', ' ', 3, 'T', 'a', ' ', 3, 'D', 'i', ' ', 4, 'C', 'h', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'S', 'u', ' ', 3, 'T', 'a', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'G', 'u', 'a', 'n', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 3, 'A', 'o', ' ', 4, 'S', 'h', 'i', ' ', 3, 'C', 'e', ' ', 4, 'C', 'h', 'i', ' ', 3, 'S', 'u', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'D', 'u', 'n', ' ', 3, 'D', 'i', ' ', 4, 'L', 'o', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'C', 'u', 'o', ' ', 4, 'L', 'i', 'n', ' ', 4, 'Z', 'u', 'n', ' ', 4, 'R', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'W', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'J', 'u', ' ', 4, 'S', 'h', 'i', ' ', 3, 'B', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'M', 'a', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'S', 'u', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'T', 'e', 'n', 'g', ' ', 3, 'E', 'r', ' ', 5, 'M', 'i', 'a', 'o', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'L', 'a', ' ', 3, 'L', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'L', 'u', 'o', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'D', 'e', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'R', 'u', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'B', 'i', 'n', ' ', 5, 'F', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'N', 'a', ' ', 4, 'X', 'i', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 5, 'B', 'a', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'C', 'u', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'X', 'i', 'e', ' ', 5, 'B', 'a', 'n', 'g', ' ', 3, 'W', 'u', ' ', 3, 'J', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'H', 'a', 'n', ' ', 4, 'T', 'a', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'B', 'i', ' ', 4, 'P', 'e', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'B', 'e', 'i', ' ', 3, 'W', 'a', ' ', 3, 'D', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'Y', 'e', ' ', 4, 'L', 'i', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'S', 'h', 'i', ' ', 3, 'K', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'a', 'i', ' ', 3, 'G', 'e', ' ', 3, 'X', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'J', 'i', ' ', 4, 'X', 'u', 'n', ' ', 4, 'H', 'o', 'u', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'X', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'N', 'u', 'o', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 5, 'K', 'u', 'a', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 6, 'O', 't', 'o', 'k', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'D', 'o', 'u', ' ', 4, 'C', 'h', 'i', ' ', 3, 'L', 'u', ' ', 3, 'F', 'u', ' ', 3, 'W', 'u', ' ', 3, 'F', 'u', ' ', 4, 'G', 'a', 'o', ' ', 4, 'H', 'a', 'o', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 5, 'G', 'e', 'n', 'g', ' ', 4, 'J', 'u', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'B', 'o', ' ', 3, 'X', 'i', ' ', 4, 'B', 'e', 'i', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'B', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'P', 'i', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'G', 'u', 'o', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'T', 'a', 'n', ' ', 4, 'Z', 'o', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'L', 'a', 'i', ' ', 3, 'N', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'B', 'u', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'D', 'a', 'n', ' ', 3, 'J', 'u', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'D', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'M', 'e', 'i', ' ', 4, 'R', 'u', 'o', ' ', 4, 'B', 'e', 'i', ' ', 2, 'E', ' ', 3, 'Y', 'u', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'H', 'o', 'u', ' ', 4, 'K', 'u', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'S', 'o', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'M', 'i', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'R', 'u', ' ', 4, 'C', 'h', 'u', ' ', 3, 'Z', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'J', 'u', ' ', 3, 'W', 'u', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'H', 'a', 'o', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'B', 'i', ' ', 3, 'M', 'o', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'F', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 3, 'H', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'F', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'X', 'u', ' ', 5, 'D', 'e', 'n', 'g', ' ', 3, 'B', 'i', ' ', 4, 'X', 'i', 'n', ' ', 3, 'B', 'i', ' ', 5, 'C', 'e', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'M', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 3, 'P', 'o', ' ', 4, 'D', 'a', 'n', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 4, 'C', 'a', 'o', ' ', 5, 'K', 'u', 'a', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'Z', 'o', 'u', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'X', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'P', 'e', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'H', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 4, 'M', 'a', 'o', ' ', 4, 'D', 'a', 'n', ' ', 3, 'X', 'u', ' ', 4, 'T', 'o', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'F', 'e', 'n', ' ', 11, 'S', 'a', 'k', 'e', 'n', 'o', 'm', 'o', 't', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'T', 'a', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'Q', 'i', 'a', ' ', 4, 'T', 'u', 'o', ' ', 4, 'Z', 'u', 'o', ' ', 4, 'H', 'a', 'n', ' ', 3, 'G', 'u', ' ', 3, 'S', 'u', ' ', 3, 'P', 'o', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Z', 'a', 'i', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 5, 'C', 'h', 'u', 'o', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'T', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'T', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'M', 'e', 'i', ' ', 3, 'K', 'u', ' ', 5, 'S', 'u', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 3, 'P', 'u', ' ', 4, 'Z', 'u', 'i', ' ', 4, 'H', 'a', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'X', 'i', ' ', 6, 'N', 'i', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 3, 'L', 'u', ' ', 4, 'L', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'T', 'a', 'o', ' ', 4, 'P', 'e', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'T', 'a', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'C', 'u', ' ', 4, 'K', 'u', 'n', ' ', 3, 'T', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'D', 'u', ' ', 3, 'H', 'u', ' ', 3, 'X', 'u', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 4, 'J', 'i', 'u', ' ', 5, 'C', 'h', 'u', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'P', 'o', ' ', 3, 'K', 'e', ' ', 4, 'S', 'o', 'u', ' ', 3, 'M', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'C', 'u', 'o', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'A', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'H', 'a', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'L', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'P', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'X', 'i', ' ', 4, 'T', 'a', 'n', ' ', 3, 'P', 'o', ' ', 5, 'N', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'i', ' ', 3, 'J', 'u', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 6, 'N', 'i', 'a', 'n', 'g', ' ', 3, 'R', 'u', ' ', 4, 'X', 'u', 'n', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'M', 'i', ' ', 3, 'M', 'i', ' ', 6, 'N', 'i', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'X', 'i', ' ', 3, 'M', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'C', 'a', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'L', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'J', 'i', 'n', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'D', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'P', 'o', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'H', 'e', ' ', 3, 'F', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'B', 'a', ' ', 5, 'L', 'u', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'N', 'a', 'i', ' ', 5, 'D', 'i', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'K', 'o', 'u', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 4, 'F', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'H', 'u', 'a', ' ', 4, 'H', 'a', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'R', 'i', ' ', 3, 'D', 'i', ' ', 3, 'S', 'i', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'C', 'h', 'a', 'i', ' ', 4, 'S', 'h', 'i', ' ', 3, 'T', 'u', ' ', 3, 'X', 'i', ' ', 3, 'N', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 9, 'I', 's', 'h', 'i', 'y', 'u', 'm', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'P', 'i', ' ', 3, 'Y', 'e', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'B', 'a', ' ', 5, 'F', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'T', 'o', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'F', 'u', ' ', 3, 'P', 'i', ' ', 3, 'N', 'a', ' ', 4, 'X', 'i', 'n', ' ', 2, 'E', ' ', 4, 'J', 'u', 'e', ' ', 4, 'D', 'u', 'n', ' ', 4, 'G', 'o', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 3, 'J', 'i', ' ', 4, 'R', 'e', 'n', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'N', 'i', 'u', ' ', 4, 'F', 'e', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'J', 'i', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'P', 'i', ' ', 4, 'G', 'u', 'o', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'J', 'u', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'Y', 'i', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'N', 'i', 'e', ' ', 4, 'G', 'a', 'i', ' ', 3, 'R', 'i', ' ', 4, 'H', 'u', 'o', ' ', 4, 'T', 'a', 'i', ' ', 5, 'K', 'a', 'n', 'g', ' ', 7, 'H', 'a', 'b', 'a', 'k', 'i', ' ', 6, 'I', 'r', 'o', 'r', 'i', ' ', 6, 'N', 'g', 'a', 'a', 'k', ' ', 4, 'D', 'u', 'o', ' ', 3, 'Z', 'i', ' ', 3, 'N', 'i', ' ', 3, 'T', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'M', 'i', 'n', ' ', 3, 'G', 'u', ' ', 2, 'E', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'G', 'u', ' ', 3, 'B', 'a', ' ', 3, 'P', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'S', 'i', ' ', 4, 'Z', 'u', 'o', ' ', 3, 'B', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'T', 'i', 'e', ' ', 3, 'J', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'e', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'B', 'a', 'o', ' ', 3, 'H', 'e', ' ', 3, 'B', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'C', 'h', 'u', ' ', 4, 'S', 'h', 'i', ' ', 3, 'B', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'C', 'h', 'i', ' ', 3, 'Z', 'a', ' ', 3, 'P', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 4, 'L', 'i', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 3, 'L', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'P', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'n', ' ', 3, 'B', 'o', ' ', 4, 'J', 'i', 'e', ' ', 4, 'G', 'o', 'u', ' ', 4, 'S', 'h', 'u', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'M', 'u', ' ', 3, 'N', 'i', ' ', 4, 'N', 'i', 'e', ' ', 3, 'D', 'i', ' ', 4, 'J', 'i', 'a', ' ', 3, 'M', 'u', ' ', 4, 'D', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'S', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'K', 'a', ' ', 4, 'B', 'e', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'T', 'o', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'C', 'h', 'i', ' ', 3, 'E', 'r', ' ', 3, 'G', 'e', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'M', 'o', 'u', ' ', 4, 'J', 'i', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'J', 'u', 'n', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'M', 'o', ' ', 4, 'L', 'e', 'i', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'X', 'u', ' ', 4, 'R', 'e', 'n', ' ', 4, 'Z', 'u', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 6, 'Q', 'i', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'P', 'i', ' ', 4, 'T', 'i', 'e', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'H', 'o', 'u', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'K', 'u', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'u', ' ', 4, 'J', 'u', 'n', ' ', 4, 'C', 'h', 'a', ' ', 4, 'L', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'P', 'i', ' ', 3, 'R', 'u', ' ', 3, 'M', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 3, 'A', 'n', ' ', 5, 'D', 'i', 'o', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'S', 'e', ' ', 4, 'K', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 8, 'K', 'a', 's', 'u', 'g', 'a', 'i', ' ', 3, 'A', 'i', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'H', 'a', 'n', ' ', 4, 'R', 'u', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'K', 'e', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'X', 'i', 'u', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 3, 'T', 'i', ' ', 4, 'C', 'u', 'o', ' ', 4, 'G', 'u', 'a', ' ', 5, 'G', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 4, 'D', 'o', 'u', ' ', 3, 'L', 'u', ' ', 4, 'M', 'e', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 4, 'X', 'i', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'B', 'e', 'i', ' ', 3, 'W', 'u', ' ', 3, 'S', 'u', ' ', 3, 'Y', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'B', 'o', ' ', 4, 'H', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'C', 'u', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'W', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'S', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'W', 'u', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'L', 'u', 'e', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'H', 'a', 'n', ' ', 4, 'L', 'u', 'e', ' ', 4, 'X', 'i', 'e', ' ', 4, 'C', 'h', 'u', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'J', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'T', 'i', 'e', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'P', 'u', ' ', 3, 'L', 'i', ' ', 4, 'P', 'a', 'n', ' ', 4, 'R', 'u', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'G', 'a', 'o', ' ', 3, 'L', 'i', ' ', 3, 'T', 'e', ' ', 6, 'P', 'y', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'T', 'u', ' ', 4, 'L', 'i', 'u', ' ', 4, 'Z', 'u', 'i', ' ', 3, 'J', 'u', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'G', 'a', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'T', 'a', 'o', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'n', ' ', 4, 'K', 'u', 'a', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'B', 'e', 'i', ' ', 3, 'L', 'u', ' ', 3, 'L', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'P', 'o', 'u', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 4, 'Z', 'u', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'A', 'n', ' ', 3, 'P', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 4, 'L', 'e', 'i', ' ', 2, 'A', ' ', 5, 'K', 'o', 'n', 'g', ' ', 3, 'T', 'a', ' ', 4, 'K', 'u', 'n', ' ', 3, 'D', 'u', ' ', 4, 'W', 'e', 'i', ' ', 5, 'C', 'h', 'u', 'i', ' ', 3, 'Z', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'B', 'e', 'n', ' ', 4, 'N', 'i', 'e', ' ', 5, 'C', 'o', 'n', 'g', ' ', 4, 'Q', 'u', 'n', ' ', 4, 'T', 'a', 'n', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'J', 'i', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'X', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'T', 'a', 'o', ' ', 3, 'G', 'u', ' ', 4, 'C', 'u', 'o', ' ', 4, 'S', 'h', 'u', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'L', 'u', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'L', 'u', ' ', 4, 'H', 'u', 'a', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'G', 'a', ' ', 4, 'L', 'a', 'i', ' ', 4, 'K', 'e', 'n', ' ', 7, 'K', 'a', 'z', 'a', 'r', 'i', ' ', 3, 'B', 'u', ' ', 4, 'N', 'a', 'i', ' ', 4, 'W', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'D', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'M', 'e', 'n', ' ', 4, 'K', 'a', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'D', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'D', 'u', ' ', 3, 'T', 'u', ' ', 4, 'W', 'e', 'i', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'R', 'o', 'u', ' ', 3, 'J', 'i', ' ', 2, 'E', ' ', 4, 'R', 'o', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'T', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'a', ' ', 3, 'Y', 'u', ' ', 5, 'K', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 3, 'F', 'u', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 4, 'C', 'h', 'a', ' ', 4, 'Q', 'i', 'e', ' ', 4, 'S', 'h', 'e', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'M', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'H', 'o', 'u', ' ', 4, 'T', 'o', 'u', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 4, 'M', 'i', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'D', 'u', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 3, 'H', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 4, 'J', 'i', 'e', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 4, 'X', 'i', 'u', ' ', 3, 'Y', 'e', ' ', 4, 'M', 'e', 'i', ' ', 4, 'P', 'a', 'i', ' ', 3, 'A', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'M', 'e', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'T', 'a', ' ', 5, 'B', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'S', 'u', 'o', ' ', 3, 'X', 'i', ' ', 4, 'L', 'i', 'u', ' ', 3, 'Z', 'u', ' ', 3, 'Y', 'e', ' ', 4, 'N', 'o', 'u', ' ', 5, 'W', 'e', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'o', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'G', 'e', ' ', 5, 'S', 'h', 'u', 'o', ' ', 5, 'C', 'h', 'u', 'i', ' ', 3, 'B', 'o', ' ', 4, 'P', 'a', 'n', ' ', 3, 'S', 'a', ' ', 3, 'B', 'i', ' ', 5, 'S', 'a', 'n', 'g', ' ', 5, 'G', 'a', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 3, 'W', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'L', 'i', 'u', ' ', 4, 'K', 'a', 'i', ' ', 4, 'S', 'u', 'n', ' ', 4, 'S', 'h', 'a', ' ', 4, 'S', 'o', 'u', ' ', 4, 'W', 'a', 'n', ' ', 4, 'H', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'L', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'N', 'i', 'e', ' ', 3, 'X', 'i', ' ', 4, 'J', 'i', 'a', ' ', 3, 'G', 'e', ' ', 3, 'M', 'a', ' ', 5, 'J', 'u', 'a', 'n', ' ', 8, 'K', 'a', 's', 'u', 'g', 'a', 'i', ' ', 7, 'H', 'a', 'b', 'a', 'k', 'i', ' ', 4, 'S', 'u', 'o', ' ', 3, 'N', 'a', ' ', 3, 'L', 'u', ' ', 4, 'S', 'u', 'o', ' ', 3, 'O', 'u', ' ', 3, 'Z', 'u', ' ', 5, 'T', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'o', 'u', ' ', 3, 'A', 'o', ' ', 4, 'M', 'a', 'n', ' ', 3, 'M', 'o', ' ', 4, 'L', 'u', 'o', ' ', 3, 'B', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'L', 'i', 'u', ' ', 3, 'D', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'u', ' ', 3, 'A', 'o', ' ', 5, 'K', 'e', 'n', 'g', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'C', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'S', 'h', 'u', ' ', 4, 'L', 'o', 'u', ' ', 4, 'X', 'i', 'u', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'Z', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'C', 'a', 'o', ' ', 3, 'L', 'i', ' ', 4, 'X', 'i', 'a', ' ', 3, 'X', 'i', ' ', 5, 'K', 'a', 'n', 'g', ' ', 5, 'B', 'e', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'L', 'u', ' ', 4, 'H', 'u', 'a', ' ', 3, 'J', 'i', ' ', 3, 'P', 'u', ' ', 4, 'H', 'u', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 3, 'P', 'o', ' ', 4, 'L', 'i', 'n', ' ', 4, 'S', 'u', 'o', ' ', 4, 'X', 'i', 'u', ' ', 4, 'S', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 3, 'S', 'i', ' ', 4, 'L', 'i', 'u', ' ', 4, 'N', 'a', 'o', ' ', 5, 'H', 'e', 'n', 'g', ' ', 4, 'P', 'i', 'e', ' ', 4, 'S', 'u', 'i', ' ', 4, 'F', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'J', 'u', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'Z', 'u', 'n', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'e', ' ', 4, 'L', 'a', 'o', ' ', 4, 'D', 'u', 'i', ' ', 4, 'T', 'a', 'n', ' ', 4, 'Z', 'a', 'n', ' ', 3, 'J', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'D', 'e', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'D', 'u', 'i', ' ', 4, 'J', 'u', 'e', ' ', 4, 'N', 'o', 'u', ' ', 3, 'T', 'i', ' ', 3, 'P', 'u', ' ', 4, 'T', 'i', 'e', ' ', 5, 'D', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'K', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'L', 'u', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 4, 'L', 'e', 'i', ' ', 3, 'B', 'i', ' ', 4, 'T', 'i', 'e', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 4, 'D', 'u', 'o', ' ', 4, 'G', 'u', 'o', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'J', 'u', ' ', 4, 'F', 'e', 'n', ' ', 3, 'D', 'a', ' ', 4, 'B', 'e', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'A', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'J', 'i', ' ', 4, 'N', 'i', 'e', ' ', 3, 'T', 'a', ' ', 4, 'H', 'u', 'o', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'B', 'i', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 5, 'N', 'i', 'n', 'g', ' ', 3, 'X', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Y', 'a', 'r', 'i', ' ', 4, 'C', 'h', 'a', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'M', 'i', 'e', ' ', 3, 'L', 'i', ' ', 4, 'L', 'e', 'i', ' ', 3, 'J', 'i', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'L', 'a', ' ', 3, 'D', 'u', ' ', 5, 'S', 'h', 'u', 'o', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'L', 'u', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'B', 'a', 'o', ' ', 3, 'L', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 2, 'E', ' ', 3, 'L', 'u', ' ', 4, 'X', 'i', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'B', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'X', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'C', 'a', 'n', 'g', ' ', 4, 'N', 'i', 'e', ' ', 4, 'L', 'e', 'i', ' ', 5, 'C', 'u', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'P', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'Z', 'a', 'o', ' ', 4, 'N', 'i', 'e', ' ', 4, 'J', 'u', 'e', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 4, 'L', 'a', 'n', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'D', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'P', 'o', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'T', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 6, 'C', 'h', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'J', 'i', ' ', 4, 'F', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'M', 'e', 'n', ' ', 3, 'N', 'u', ' ', 3, 'X', 'i', ' ', 5, 'C', 'h', 'a', 'i', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'G', 'a', 'i', ' ', 3, 'B', 'u', ' ', 4, 'T', 'a', 'i', ' ', 3, 'J', 'u', ' ', 4, 'D', 'u', 'n', ' ', 5, 'C', 'h', 'a', 'o', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'N', 'a', ' ', 4, 'B', 'e', 'i', ' ', 5, 'G', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'J', 'u', 'n', ' ', 3, 'W', 'u', ' ', 4, 'G', 'o', 'u', ' ', 5, 'K', 'a', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 4, 'T', 'o', 'u', ' ', 4, 'N', 'i', 'u', ' ', 3, 'B', 'a', ' ', 3, 'Y', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'G', 'u', ' ', 3, 'B', 'o', ' ', 2, 'E', ' ', 3, 'P', 'o', ' ', 3, 'B', 'u', ' ', 3, 'B', 'a', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 3, 'M', 'u', ' ', 4, 'D', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'T', 'i', 'e', ' ', 3, 'B', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'L', 'i', 'u', ' ', 4, 'B', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'e', ' ', 3, 'B', 'i', ' ', 3, 'N', 'i', ' ', 3, 'P', 'i', ' ', 4, 'D', 'u', 'o', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'K', 'a', 'o', ' ', 4, 'L', 'a', 'o', ' ', 3, 'E', 'r', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 4, 'Y', 'o', 'u', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 3, 'Y', 'e', ' ', 4, 'N', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'L', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'K', 'a', 'i', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'D', 'i', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'a', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'S', 'h', 'a', ' ', 4, 'J', 'i', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'G', 'e', ' ', 5, 'M', 'i', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 3, 'S', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'A', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'R', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'L', 'a', 'o', ' ', 3, 'P', 'u', ' ', 3, 'W', 'u', ' ', 4, 'L', 'a', 'i', ' ', 3, 'T', 'e', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'K', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'S', 'u', 'o', ' ', 3, 'L', 'i', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 4, 'C', 'h', 'u', ' ', 4, 'G', 'u', 'o', ' ', 4, 'G', 'a', 'o', ' ', 4, 'T', 'i', 'e', ' ', 4, 'X', 'i', 'u', ' ', 4, 'C', 'u', 'o', ' ', 4, 'L', 'u', 'e', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'X', 'i', 'n', ' ', 4, 'L', 'i', 'u', ' ', 4, 'K', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'R', 'u', 'i', ' ', 3, 'T', 'i', ' ', 5, 'L', 'a', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 2, 'A', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 4, 'D', 'u', 'o', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'C', 'u', 'o', ' ', 4, 'M', 'a', 'o', ' ', 4, 'B', 'e', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'D', 'e', ' ', 4, 'K', 'u', 'a', ' ', 4, 'K', 'u', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'G', 'u', ' ', 4, 'L', 'u', 'o', ' ', 5, 'C', 'h', 'u', 'i', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 4, 'J', 'i', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'P', 'o', 'u', ' ', 4, 'T', 'a', 'n', ' ', 5, 'D', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 4, 'Q', 'i', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'K', 'a', 'i', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'S', 'o', 'n', 'g', ' ', 2, 'E', ' ', 4, 'C', 'h', 'a', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'D', 'u', 'a', 'n', ' ', 4, 'S', 'o', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'A', 'i', ' ', 3, 'D', 'u', ' ', 4, 'M', 'e', 'i', ' ', 4, 'L', 'o', 'u', ' ', 3, 'Z', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'M', 'e', 'i', ' ', 3, 'M', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'B', 'o', ' ', 3, 'G', 'e', ' ', 4, 'N', 'i', 'e', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 3, 'N', 'a', ' ', 4, 'L', 'i', 'u', ' ', 4, 'H', 'a', 'o', ' ', 5, 'B', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'J', 'i', 'a', ' ', 4, 'B', 'i', 'n', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'D', 'i', ' ', 3, 'Z', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'L', 'i', 'u', ' ', 4, 'T', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'P', 'u', ' ', 3, 'L', 'u', ' ', 4, 'D', 'u', 'i', ' ', 4, 'L', 'a', 'n', ' ', 3, 'P', 'u', ' ', 5, 'C', 'u', 'a', 'n', ' ', 6, 'Q', 'i', 'a', 'n', 'g', ' ', 5, 'D', 'e', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 4, 'L', 'e', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'h', 'a', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'L', 'a', ' ', 5, 'C', 'h', 'a', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'u', ' ', 3, 'A', 'o', ' ', 4, 'D', 'i', 'e', ' ', 3, 'Q', 'u', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'M', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'M', 'e', 'n', ' ', 3, 'M', 'a', ' ', 6, 'S', 'h', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'M', 'e', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'H', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'S', 'a', 'n', ' ', 4, 'K', 'a', 'i', ' ', 5, 'K', 'a', 'n', 'g', ' ', 5, 'B', 'e', 'n', 'g', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'R', 'u', 'n', ' ', 4, 'S', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Y', 'u', 'r', 'u', ' ', 4, 'D', 'o', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'N', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'R', 'u', 'n', ' ', 3, 'H', 'e', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'G', 'e', ' ', 3, 'G', 'e', ' ', 3, 'F', 'a', ' ', 4, 'C', 'h', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'G', 'u', 'i', ' ', 4, 'M', 'i', 'n', ' ', 3, 'S', 'e', ' ', 4, 'K', 'u', 'n', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'L', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'a', ' ', 3, 'J', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'L', 'i', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'i', ' ', 4, 'K', 'u', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 2, 'E', ' ', 4, 'H', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'W', 'e', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'o', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'W', 'e', 'n', ' ', 4, 'B', 'a', 'n', ' ', 3, 'A', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'K', 'u', 'o', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'L', 'a', 'n', ' ', 3, 'D', 'u', ' ', 7, 'P', 'h', 'w', 'u', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 3, 'T', 'a', ' ', 4, 'K', 'a', 'i', ' ', 3, 'H', 'e', ' ', 4, 'Q', 'u', 'e', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'D', 'o', 'u', ' ', 3, 'Q', 'i', ' ', 4, 'K', 'u', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'K', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'H', 'u', 'i', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'P', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'T', 'a', ' ', 4, 'W', 'e', 'n', ' ', 4, 'M', 'e', 'n', ' ', 6, 'S', 'h', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 3, 'B', 'i', ' ', 4, 'W', 'e', 'n', ' ', 7, 'C', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'R', 'u', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'M', 'e', 'n', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'N', 'a', 'o', ' ', 4, 'G', 'u', 'i', ' ', 4, 'W', 'e', 'n', ' ', 3, 'T', 'a', ' ', 4, 'M', 'i', 'n', ' ', 3, 'L', 'u', ' ', 4, 'K', 'a', 'i', ' ', 3, 'F', 'a', ' ', 3, 'G', 'e', ' ', 3, 'H', 'e', ' ', 4, 'K', 'u', 'n', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'L', 'a', 'n', 'g', ' ', 3, 'D', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'X', 'i', ' ', 4, 'W', 'e', 'n', ' ', 4, 'H', 'u', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 2, 'E', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'H', 'u', 'i', ' ', 4, 'K', 'u', 'o', ' ', 4, 'Q', 'u', 'e', ' ', 3, 'G', 'e', ' ', 5, 'T', 'i', 'a', 'n', ' ', 3, 'T', 'a', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'K', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'F', 'u', ' ', 3, 'F', 'u', ' ', 3, 'L', 'e', ' ', 4, 'D', 'u', 'i', ' ', 4, 'X', 'i', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'T', 'u', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'D', 'o', 'u', ' ', 2, 'E', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'B', 'a', 'n', ' ', 4, 'P', 'e', 'i', ' ', 5, 'K', 'e', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'R', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'P', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'J', 'i', 'e', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 2, 'E', ' ', 3, 'Q', 'u', ' ', 3, 'D', 'i', ' ', 3, 'Z', 'u', ' ', 4, 'Z', 'u', 'o', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 2, 'A', ' ', 4, 'T', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 3, 'P', 'o', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'F', 'u', ' ', 3, 'J', 'i', ' ', 3, 'L', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'D', 'u', 'o', ' ', 4, 'L', 'o', 'u', ' ', 3, 'M', 'o', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 4, 'D', 'u', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'E', 'r', ' ', 4, 'G', 'u', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'a', 'i', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'X', 'u', 'n', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'n', 'g', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'F', 'u', ' ', 3, 'B', 'i', ' ', 4, 'X', 'i', 'a', ' ', 5, 'S', 'h', 'a', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'P', 'u', ' ', 4, 'D', 'o', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'C', 'h', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'T', 'o', 'u', ' ', 4, 'N', 'i', 'e', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'P', 'e', 'i', ' ', 4, 'P', 'e', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'Y', 'i', ' ', 4, 'D', 'u', 'i', ' ', 4, 'L', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'J', 'u', ' ', 5, 'C', 'h', 'u', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'P', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'T', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'L', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'R', 'e', 'n', 'g', ' ', 5, 'S', 'h', 'a', 'n', ' ', 6, 'C', 'h', 'o', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'T', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'N', 'i', 'e', ' ', 4, 'D', 'u', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'A', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 4, 'S', 'u', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'G', 'a', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'G', 'e', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'W', 'u', ' ', 4, 'W', 'e', 'i', ' ', 3, 'A', 'i', ' ', 3, 'X', 'i', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'D', 'a', 'o', ' ', 3, 'A', 'o', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'R', 'a', 'o', ' ', 4, 'L', 'i', 'n', ' ', 4, 'T', 'u', 'i', ' ', 5, 'D', 'e', 'n', 'g', ' ', 3, 'P', 'i', ' ', 4, 'S', 'u', 'i', ' ', 4, 'S', 'u', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 3, 'N', 'i', ' ', 3, 'E', 'r', ' ', 3, 'J', 'i', ' ', 4, 'D', 'a', 'o', ' ', 3, 'X', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 2, 'E', ' ', 4, 'H', 'u', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 3, 'L', 'i', ' ', 3, 'L', 'i', ' ', 3, 'L', 'i', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'H', 'e', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 4, 'J', 'u', 'n', ' ', 4, 'N', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'Q', 'u', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 6, 'X', 'i', 'o', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 3, 'J', 'i', ' ', 3, 'G', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'G', 'o', 'u', ' ', 4, 'J', 'u', 'n', ' ', 3, 'C', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'J', 'u', ' ', 4, 'C', 'h', 'u', ' ', 3, 'H', 'u', ' ', 3, 'Z', 'a', ' ', 4, 'L', 'u', 'o', ' ', 3, 'Y', 'u', ' ', 5, 'C', 'h', 'o', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'S', 'u', 'i', ' ', 4, 'H', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 3, 'Z', 'a', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 3, 'X', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'L', 'i', 'u', ' ', 3, 'L', 'i', ' ', 4, 'N', 'a', 'n', ' ', 4, 'X', 'u', 'e', ' ', 3, 'Z', 'a', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'X', 'u', 'e', ' ', 3, 'N', 'a', ' ', 4, 'F', 'o', 'u', ' ', 3, 'S', 'e', ' ', 3, 'M', 'u', ' ', 4, 'W', 'e', 'n', ' ', 4, 'F', 'e', 'n', ' ', 5, 'P', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'L', 'i', ' ', 3, 'L', 'i', ' ', 4, 'A', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 3, 'A', 'n', ' ', 4, 'B', 'a', 'o', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'D', 'a', 'n', 'g', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'W', 'u', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 3, 'X', 'u', ' ', 3, 'J', 'i', ' ', 3, 'M', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'T', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'P', 'e', 'i', ' ', 4, 'M', 'e', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'H', 'u', 'o', ' ', 4, 'S', 'h', 'a', ' ', 4, 'F', 'e', 'i', ' ', 5, 'W', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'N', 'i', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'T', 'u', 'n', ' ', 4, 'L', 'i', 'n', ' ', 5, 'D', 'o', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'W', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'M', 'o', ' ', 4, 'M', 'a', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'L', 'i', 'u', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'B', 'i', 'n', ' ', 3, 'W', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'H', 'u', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'X', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'A', 'i', ' ', 4, 'D', 'a', 'n', ' ', 5, 'D', 'e', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'L', 'u', ' ', 5, 'L', 'o', 'n', 'g', ' ', 4, 'D', 'a', 'i', ' ', 3, 'J', 'i', ' ', 5, 'P', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'B', 'a', ' ', 3, 'P', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'X', 'i', ' ', 3, 'J', 'i', ' ', 4, 'M', 'a', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 3, 'L', 'i', ' ', 4, 'H', 'u', 'o', ' ', 3, 'A', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'D', 'a', 'i', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'A', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 4, 'B', 'a', 'o', ' ', 3, 'H', 'e', ' ', 3, 'H', 'e', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'K', 'a', 'o', ' ', 3, 'M', 'i', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 4, 'P', 'a', 'o', ' ', 3, 'Y', 'e', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 3, 'Y', 'e', ' ', 3, 'G', 'e', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'R', 'e', 'n', ' ', 3, 'D', 'i', ' ', 3, 'D', 'u', ' ', 3, 'W', 'u', ' ', 4, 'R', 'e', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'J', 'i', 'n', ' ', 4, 'X', 'u', 'e', ' ', 4, 'N', 'i', 'u', ' ', 3, 'B', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'S', 'a', ' ', 3, 'N', 'a', ' ', 3, 'M', 'o', ' ', 3, 'Z', 'u', ' ', 3, 'D', 'a', ' ', 4, 'B', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'T', 'a', 'o', ' ', 4, 'T', 'u', 'o', ' ', 4, 'J', 'i', 'a', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'P', 'a', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'T', 'o', 'm', 'o', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'J', 'i', 'a', ' ', 4, 'T', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'X', 'i', 'e', ' ', 3, 'A', 'n', ' ', 3, 'A', 'n', ' ', 4, 'H', 'e', 'n', ' ', 5, 'G', 'o', 'n', 'g', ' ', 7, 'K', 'o', 'h', 'a', 'z', 'e', ' ', 3, 'D', 'a', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'T', 'i', 'n', 'g', ' ', 4, 'W', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'K', 'o', 'n', 'g', ' ', 5, 'B', 'e', 'n', 'g', ' ', 3, 'T', 'a', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'K', 'u', 'o', ' ', 3, 'J', 'u', ' ', 3, 'L', 'a', ' ', 4, 'X', 'i', 'e', ' ', 4, 'R', 'o', 'u', ' ', 5, 'B', 'a', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'H', 'e', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'M', 'u', ' ', 3, 'J', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 3, 'D', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'O', 'n', ' ', 4, 'T', 'a', 'o', ' ', 4, 'G', 'o', 'u', ' ', 3, 'T', 'a', ' ', 4, 'B', 'e', 'i', ' ', 4, 'X', 'i', 'e', ' ', 4, 'P', 'a', 'n', ' ', 3, 'G', 'e', ' ', 3, 'B', 'i', ' ', 4, 'K', 'u', 'o', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'L', 'o', 'u', ' ', 4, 'G', 'u', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'X', 'u', 'e', ' ', 3, 'J', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'D', 'a', ' ', 4, 'H', 'u', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'D', 'u', ' ', 3, 'W', 'a', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'R', 'e', 'n', ' ', 3, 'F', 'u', ' ', 4, 'M', 'e', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'G', 'e', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'H', 'a', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'R', 'o', 'u', ' ', 4, 'X', 'u', 'n', ' ', 4, 'S', 'h', 'e', ' ', 4, 'W', 'e', 'i', ' ', 3, 'G', 'e', ' ', 4, 'B', 'e', 'i', ' ', 4, 'T', 'a', 'o', ' ', 4, 'G', 'o', 'u', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'B', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'H', 'u', 'i', ' ', 3, 'D', 'u', ' ', 3, 'W', 'a', ' ', 3, 'D', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'R', 'e', 'n', ' ', 3, 'F', 'u', ' ', 4, 'H', 'a', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'T', 'a', 'o', ' ', 4, 'J', 'i', 'u', ' ', 4, 'J', 'i', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'J', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'Z', 'a', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'L', 'e', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Y', 'u', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'H', 'u', ' ', 3, 'Y', 'e', ' ', 5, 'D', 'i', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'P', 'a', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'n', ' ', 4, 'H', 'a', 'n', ' ', 3, 'X', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'X', 'u', ' ', 3, 'G', 'u', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'H', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'W', 'a', 'n', ' ', 4, 'B', 'a', 'n', ' ', 4, 'D', 'u', 'n', ' ', 3, 'D', 'i', ' ', 4, 'D', 'a', 'n', ' ', 4, 'P', 'a', 'n', ' ', 3, 'P', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'C', 'e', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 3, 'H', 'e', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 2, 'E', ' ', 2, 'E', ' ', 4, 'W', 'e', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'G', 'u', 'a', ' ', 5, 'S', 'h', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'H', 'a', 'i', ' ', 4, 'D', 'u', 'i', ' ', 5, 'P', 'i', 'a', 'n', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'L', 'e', 'i', ' ', 3, 'F', 'u', ' ', 4, 'J', 'i', 'a', ' ', 4, 'T', 'o', 'u', ' ', 4, 'H', 'u', 'i', ' ', 4, 'K', 'u', 'i', ' ', 4, 'J', 'i', 'a', ' ', 3, 'L', 'e', ' ', 5, 'T', 'i', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'J', 'u', 'n', ' ', 3, 'H', 'u', ' ', 4, 'H', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'T', 'u', 'i', ' ', 4, 'T', 'u', 'i', ' ', 4, 'P', 'i', 'n', ' ', 4, 'L', 'a', 'i', ' ', 4, 'T', 'u', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'Z', 'i', ' ', 5, 'C', 'h', 'u', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 4, 'L', 'a', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'K', 'e', ' ', 4, 'C', 'u', 'i', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'S', 'a', 'i', ' ', 3, 'T', 'i', ' ', 2, 'E', ' ', 2, 'E', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'H', 'u', 'n', ' ', 4, 'K', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'S', 'a', 'n', 'g', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 3, 'K', 'u', ' ', 4, 'L', 'e', 'i', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'P', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'M', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'R', 'a', 'o', ' ', 4, 'H', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 3, 'G', 'u', ' ', 4, 'X', 'u', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'R', 'u', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'B', 'i', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'P', 'i', 'n', ' ', 3, 'L', 'u', ' ', 4, 'L', 'a', 'n', ' ', 4, 'N', 'i', 'e', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 5, 'D', 'i', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'n', ' ', 3, 'X', 'u', ' ', 3, 'X', 'u', ' ', 4, 'W', 'a', 'n', ' ', 3, 'G', 'u', ' ', 4, 'D', 'u', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'B', 'a', 'n', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'H', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'L', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'P', 'o', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'J', 'i', 'e', ' ', 4, 'J', 'i', 'a', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'H', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 4, 'H', 'a', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'P', 'i', 'n', ' ', 4, 'H', 'u', 'i', ' ', 4, 'T', 'u', 'i', ' ', 4, 'H', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'K', 'e', ' ', 3, 'T', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 2, 'E', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 2, 'E', ' ', 4, 'N', 'i', 'e', ' ', 4, 'M', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'n', ' ', 5, 'S', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'o', ' ', 4, 'L', 'e', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'R', 'u', ' ', 4, 'P', 'i', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'o', ' ', 7, 'O', 'r', 'o', 's', 'h', 'i', ' ', 3, 'F', 'u', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'S', 'a', ' ', 3, 'B', 'a', ' ', 4, 'T', 'a', 'i', ' ', 4, 'L', 'i', 'e', ' ', 4, 'G', 'u', 'a', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'o', ' ', 3, 'J', 'u', ' ', 3, 'B', 'i', ' ', 3, 'S', 'i', ' ', 4, 'W', 'e', 'i', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'S', 'o', 'u', ' ', 4, 'K', 'a', 'i', ' ', 4, 'S', 'a', 'o', ' ', 4, 'F', 'a', 'n', ' ', 4, 'L', 'i', 'u', ' ', 3, 'X', 'i', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'P', 'i', 'a', 'o', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'L', 'i', 'u', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 3, 'S', 'e', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'S', 'a', ' ', 3, 'J', 'u', ' ', 3, 'S', 'i', ' ', 4, 'S', 'o', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'L', 'i', 'u', ' ', 5, 'P', 'i', 'a', 'o', ' ', 5, 'B', 'i', 'a', 'o', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'F', 'e', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'F', 'e', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'C', 'a', 'n', ' ', 3, 'J', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'S', 'i', ' ', 4, 'T', 'u', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'S', 'u', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'T', 'u', 'n', ' ', 4, 'R', 'e', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'J', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'S', 'u', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'Y', 'i', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 3, 'B', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'T', 'a', 'o', ' ', 4, 'L', 'i', 'u', ' ', 3, 'C', 'i', ' ', 4, 'T', 'i', 'e', ' ', 3, 'S', 'i', ' ', 4, 'B', 'a', 'o', ' ', 4, 'S', 'h', 'i', ' ', 4, 'D', 'u', 'o', ' ', 4, 'H', 'a', 'i', ' ', 4, 'R', 'e', 'n', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'a', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'C', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'E', 'r', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'L', 'e', ' ', 3, 'Y', 'i', ' ', 4, 'C', 'a', 'n', ' ', 3, 'B', 'o', ' ', 4, 'N', 'e', 'i', ' ', 2, 'E', ' ', 3, 'B', 'u', ' ', 4, 'J', 'u', 'n', ' ', 4, 'D', 'o', 'u', ' ', 3, 'S', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'H', 'u', 'n', ' ', 4, 'G', 'u', 'o', ' ', 4, 'S', 'h', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'B', 'u', ' ', 3, 'Y', 'e', ' ', 4, 'T', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 2, 'E', ' ', 5, 'N', 'u', 'a', 'n', ' ', 4, 'H', 'u', 'n', ' ', 3, 'H', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'T', 'i', 'e', ' ', 4, 'H', 'u', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'H', 'o', 'u', ' ', 3, 'H', 'e', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 4, 'W', 'e', 'i', ' ', 3, 'G', 'u', ' ', 4, 'C', 'h', 'a', ' ', 5, 'S', 'o', 'n', 'g', ' ', 5, 'T', 'a', 'n', 'g', ' ', 3, 'B', 'o', ' ', 4, 'G', 'a', 'o', ' ', 3, 'X', 'i', ' ', 4, 'K', 'u', 'i', ' ', 4, 'L', 'i', 'u', ' ', 4, 'S', 'o', 'u', ' ', 4, 'T', 'a', 'o', ' ', 3, 'Y', 'e', ' ', 4, 'Y', 'u', 'n', ' ', 3, 'M', 'o', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'M', 'a', 'n', ' ', 3, 'B', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'X', 'i', 'u', ' ', 4, 'J', 'i', 'n', ' ', 4, 'S', 'a', 'n', ' ', 4, 'K', 'u', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'D', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'i', ' ', 4, 'R', 'a', 'o', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'T', 'a', 'o', ' ', 4, 'H', 'u', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'F', 'e', 'n', ' ', 4, 'H', 'a', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'M', 'o', ' ', 5, 'C', 'h', 'a', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 5, 'Z', 'u', 'a', 'n', ' ', 5, 'N', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'J', 'i', ' ', 4, 'T', 'u', 'o', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'T', 'u', 'n', ' ', 3, 'X', 'i', ' ', 4, 'R', 'e', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'F', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'B', 'a', 'o', ' ', 3, 'S', 'i', ' ', 4, 'D', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'E', 'r', ' ', 4, 'R', 'a', 'o', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 3, 'L', 'e', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 3, 'B', 'o', ' ', 4, 'D', 'o', 'u', ' ', 2, 'E', ' ', 3, 'Y', 'u', ' ', 4, 'N', 'e', 'i', ' ', 4, 'J', 'u', 'n', ' ', 4, 'G', 'u', 'o', ' ', 4, 'H', 'u', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'C', 'h', 'a', ' ', 4, 'K', 'u', 'i', ' ', 3, 'G', 'u', ' ', 4, 'S', 'o', 'u', ' ', 5, 'C', 'h', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 3, 'M', 'o', ' ', 3, 'B', 'o', ' ', 4, 'L', 'i', 'u', ' ', 4, 'X', 'i', 'u', ' ', 4, 'J', 'i', 'n', ' ', 4, 'M', 'a', 'n', ' ', 4, 'S', 'a', 'n', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'N', 'a', 'n', 'g', ' ', 5, 'S', 'h', 'o', 'u', ' ', 4, 'K', 'u', 'i', ' ', 4, 'G', 'u', 'o', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 3, 'B', 'a', ' ', 3, 'N', 'i', ' ', 3, 'B', 'i', ' ', 3, 'B', 'o', ' ', 3, 'T', 'u', ' ', 4, 'H', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'A', 'n', ' ', 3, 'A', 'i', ' ', 3, 'F', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'W', 'e', 'n', ' ', 4, 'X', 'i', 'n', ' ', 4, 'F', 'e', 'n', ' ', 4, 'B', 'i', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 3, 'M', 'a', ' ', 3, 'Y', 'u', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 3, 'D', 'i', ' ', 4, 'T', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 4, 'C', 'h', 'i', ' ', 4, 'X', 'u', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'P', 'e', 'i', ' ', 4, 'X', 'i', 'n', ' ', 3, 'R', 'i', ' ', 3, 'S', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'W', 'e', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'D', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'B', 'o', ' ', 4, 'B', 'a', 'o', ' ', 5, 'K', 'u', 'a', 'i', ' ', 4, 'T', 'u', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'u', ' ', 3, 'Q', 'u', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 3, 'B', 'o', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'J', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'N', 'u', ' ', 3, 'J', 'u', ' ', 3, 'P', 'i', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'a', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'T', 'a', 'i', ' ', 3, 'F', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 3, 'B', 'i', ' ', 4, 'T', 'u', 'o', ' ', 4, 'T', 'u', 'o', ' ', 3, 'S', 'i', ' ', 4, 'L', 'i', 'u', ' ', 3, 'M', 'a', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'T', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'T', 'e', 'n', 'g', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'S', 'h', 'e', 'n', ' ', 6, 'J', 'i', 'o', 'n', 'g', ' ', 3, 'E', 'r', ' ', 4, 'H', 'a', 'i', ' ', 3, 'B', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'L', 'u', 'o', ' ', 5, 'S', 'h', 'u', 'u', ' ', 4, 'D', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'L', 'i', 'u', ' ', 3, 'J', 'u', ' ', 5, 'S', 'o', 'n', 'g', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'M', 'a', 'n', 'g', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'H', 'a', 'n', ' ', 3, 'T', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 4, 'T', 'u', 'i', ' ', 4, 'J', 'u', 'n', ' ', 2, 'E', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'X', 'i', 'n', ' ', 3, 'A', 'i', ' ', 3, 'L', 'u', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'S', 'h', 'e', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'K', 'u', 'n', ' ', 4, 'T', 'a', 'o', ' ', 4, 'L', 'a', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'K', 'e', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'S', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'J', 'i', 'e', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'W', 'u', ' ', 5, 'P', 'i', 'a', 'n', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'F', 'e', 'i', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'H', 'u', 'o', ' ', 3, 'Y', 'u', ' ', 3, 'T', 'i', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'a', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'K', 'u', 'i', ' ', 4, 'R', 'o', 'u', ' ', 3, 'S', 'i', ' ', 4, 'G', 'u', 'a', ' ', 4, 'T', 'u', 'o', ' ', 4, 'K', 'u', 'i', ' ', 4, 'S', 'o', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'L', 'i', 'u', ' ', 5, 'P', 'a', 'n', 'g', ' ', 5, 'T', 'e', 'n', 'g', ' ', 3, 'X', 'i', ' ', 4, 'C', 'a', 'o', ' ', 3, 'D', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'Z', 'o', 'u', ' ', 4, 'S', 'a', 'o', ' ', 5, 'S', 'h', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'X', 'i', ' ', 4, 'L', 'u', 'o', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 3, 'M', 'o', ' ', 3, 'A', 'o', ' ', 4, 'C', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 3, 'B', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Y', 'u', ' ', 3, 'X', 'u', ' ', 4, 'H', 'u', 'a', ' ', 3, 'B', 'o', ' ', 3, 'S', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'L', 'i', 'n', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'D', 'u', 'n', ' ', 4, 'L', 'i', 'u', ' ', 4, 'T', 'u', 'o', ' ', 5, 'Z', 'e', 'n', 'g', ' ', 4, 'T', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'T', 'i', 'e', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'L', 'u', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'e', ' ', 4, 'T', 'u', 'o', ' ', 4, 'B', 'i', 'n', ' ', 4, 'Z', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'L', 'u', ' ', 5, 'T', 'e', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'J', 'i', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'J', 'u', ' ', 3, 'X', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 3, 'L', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'M', 'a', ' ', 3, 'Y', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'X', 'u', 'n', ' ', 4, 'C', 'h', 'i', ' ', 3, 'Q', 'u', ' ', 3, 'R', 'i', ' ', 3, 'B', 'o', ' ', 3, 'L', 'u', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 3, 'S', 'i', ' ', 3, 'F', 'u', ' ', 3, 'J', 'u', ' ', 4, 'Z', 'o', 'u', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'T', 'u', 'o', ' ', 3, 'N', 'u', ' ', 4, 'J', 'i', 'a', ' ', 3, 'Y', 'i', ' ', 4, 'T', 'a', 'i', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'M', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'H', 'u', 'a', ' ', 4, 'L', 'u', 'o', ' ', 4, 'H', 'a', 'i', ' ', 5, 'P', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'L', 'i', ' ', 6, 'C', 'h', 'e', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'X', 'i', 'n', ' ', 4, 'Q', 'i', 'n', ' ', 4, 'J', 'u', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'K', 'e', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'S', 'u', ' ', 4, 'C', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'K', 'u', 'i', ' ', 4, 'S', 'a', 'o', ' ', 3, 'W', 'u', ' ', 3, 'A', 'o', ' ', 4, 'L', 'i', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'o', ' ', 4, 'L', 'u', 'o', ' ', 5, 'C', 'o', 'n', 'g', ' ', 5, 'C', 'h', 'a', 'n', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'J', 'i', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'G', 'u', ' ', 4, 'W', 'e', 'i', ' ', 4, 'W', 'e', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'A', 'n', 'g', ' ', 4, 'T', 'o', 'u', ' ', 4, 'X', 'i', 'e', ' ', 4, 'B', 'a', 'o', ' ', 3, 'B', 'i', ' ', 4, 'C', 'h', 'i', ' ', 3, 'T', 'i', ' ', 3, 'D', 'i', ' ', 3, 'K', 'u', ' ', 4, 'H', 'a', 'i', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'G', 'o', 'u', ' ', 4, 'K', 'u', 'a', ' ', 3, 'G', 'e', ' ', 4, 'T', 'u', 'i', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'P', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 3, 'K', 'e', ' ', 3, 'K', 'a', ' ', 3, 'Y', 'u', ' ', 4, 'S', 'u', 'i', ' ', 4, 'L', 'o', 'u', ' ', 3, 'B', 'o', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'P', 'a', 'n', 'g', ' ', 3, 'B', 'o', ' ', 3, 'C', 'i', ' ', 5, 'K', 'u', 'a', 'n', ' ', 4, 'B', 'i', 'n', ' ', 3, 'M', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'L', 'o', 'u', ' ', 4, 'N', 'a', 'o', ' ', 3, 'D', 'u', ' ', 5, 'Z', 'a', 'n', 'g', ' ', 4, 'S', 'u', 'i', ' ', 3, 'T', 'i', ' ', 4, 'B', 'i', 'n', ' ', 5, 'K', 'u', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'G', 'a', 'o', ' ', 4, 'G', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'K', 'a', 'o', ' ', 5, 'Q', 'i', 'a', 'o', ' ', 4, 'L', 'a', 'o', ' ', 4, 'Z', 'a', 'o', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'K', 'u', 'n', ' ', 4, 'K', 'u', 'n', ' ', 3, 'T', 'i', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'u', ' ', 4, 'R', 'a', 'n', ' ', 4, 'M', 'a', 'o', ' ', 4, 'D', 'a', 'n', ' ', 4, 'K', 'u', 'n', ' ', 4, 'B', 'i', 'n', ' ', 3, 'F', 'a', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 3, 'F', 'a', ' ', 4, 'R', 'a', 'n', ' ', 3, 'T', 'i', ' ', 4, 'P', 'a', 'o', ' ', 3, 'P', 'i', ' ', 4, 'M', 'a', 'o', ' ', 3, 'F', 'u', ' ', 3, 'E', 'r', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'X', 'i', 'u', ' ', 4, 'G', 'u', 'a', ' ', 3, 'J', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'a', ' ', 5, 'S', 'h', 'a', 'o', ' ', 4, 'S', 'h', 'a', ' ', 3, 'T', 'i', ' ', 3, 'L', 'i', ' ', 4, 'B', 'i', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'T', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'S', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 5, 'S', 'h', 'u', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'D', 'u', 'o', ' ', 3, 'H', 'u', ' ', 3, 'L', 'a', ' ', 4, 'J', 'i', 'u', ' ', 3, 'Q', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'B', 'i', 'n', ' ', 5, 'P', 'e', 'n', 'g', ' ', 3, 'M', 'o', ' ', 4, 'S', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 4, 'M', 'a', 'n', ' ', 5, 'S', 'e', 'n', 'g', ' ', 3, 'X', 'u', ' ', 4, 'L', 'i', 'e', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'K', 'u', 'a', 'i', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'B', 'i', 'n', ' ', 4, 'L', 'i', 'e', ' ', 5, 'R', 'a', 'n', 'g', ' ', 4, 'D', 'o', 'u', ' ', 4, 'D', 'o', 'u', ' ', 4, 'N', 'a', 'o', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'X', 'i', ' ', 4, 'D', 'o', 'u', ' ', 4, 'H', 'a', 'n', ' ', 4, 'D', 'o', 'u', ' ', 4, 'D', 'o', 'u', ' ', 4, 'J', 'i', 'u', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'L', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'L', 'i', 'u', ' ', 4, 'G', 'u', 'i', ' ', 6, 'S', 'h', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'G', 'u', 'i', ' ', 4, 'M', 'e', 'i', ' ', 3, 'J', 'i', ' ', 3, 'Q', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'K', 'u', 'i', ' ', 4, 'H', 'u', 'n', ' ', 3, 'B', 'a', ' ', 3, 'P', 'o', ' ', 4, 'M', 'e', 'i', ' ', 3, 'X', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 4, 'T', 'u', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'W', 'a', 'n', 'g', ' ', 6, 'L', 'i', 'a', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 5, 'P', 'i', 'a', 'o', ' ', 3, 'B', 'i', ' ', 3, 'M', 'o', ' ', 3, 'J', 'i', ' ', 3, 'X', 'u', ' ', 5, 'C', 'h', 'o', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'D', 'a', 'o', ' ', 4, 'R', 'e', 'n', ' ', 3, 'J', 'i', ' ', 4, 'E', 'r', 'i', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'T', 'u', 'o', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'X', 'u', ' ', 2, 'E', ' ', 2, 'E', ' ', 4, 'S', 'h', 'a', ' ', 5, 'H', 'a', 'n', 'g', ' ', 4, 'T', 'u', 'n', ' ', 3, 'M', 'o', ' ', 4, 'J', 'i', 'e', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'F', 'a', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'B', 'i', ' ', 3, 'L', 'u', ' ', 4, 'W', 'e', 'n', ' ', 3, 'H', 'u', ' ', 3, 'L', 'u', ' ', 3, 'Z', 'a', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 3, 'N', 'a', ' ', 4, 'Y', 'o', 'u', ' ', 7, 'N', 'a', 'm', 'a', 'z', 'u', ' ', 5, 'T', 'o', 'd', 'o', ' ', 3, 'H', 'e', ' ', 4, 'X', 'i', 'a', ' ', 3, 'Q', 'u', ' ', 4, 'H', 'a', 'n', ' ', 3, 'P', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'T', 'u', 'o', ' ', 3, 'B', 'o', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 3, 'F', 'u', ' ', 3, 'B', 'i', ' ', 3, 'J', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'J', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'B', 'o', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'G', 'u', 'n', ' ', 3, 'P', 'i', ' ', 5, 'N', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'T', 'a', 'i', ' ', 4, 'B', 'a', 'o', ' ', 3, 'F', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'J', 'u', ' ', 3, 'G', 'u', ' ', 7, 'K', 'a', 'j', 'i', 'k', 'a', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'T', 'a', ' ', 4, 'J', 'i', 'e', ' ', 4, 'S', 'h', 'u', ' ', 4, 'H', 'o', 'u', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'E', 'r', ' ', 3, 'A', 'n', ' ', 4, 'W', 'e', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'L', 'i', 'e', ' ', 4, 'L', 'u', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'B', 'i', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'B', 'u', ' ', 4, 'G', 'u', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'G', 'e', ' ', 4, 'H', 'u', 'i', ' ', 5, 'B', 'o', 'r', 'a', ' ', 5, 'M', 'a', 't', 'e', ' ', 4, 'K', 'a', 'o', ' ', 5, 'G', 'o', 'r', 'i', ' ', 4, 'D', 'u', 'o', ' ', 4, 'J', 'u', 'n', ' ', 3, 'T', 'i', ' ', 4, 'M', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'o', ' ', 3, 'Z', 'a', ' ', 4, 'S', 'h', 'a', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'N', 'e', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 4, 'G', 'u', 'n', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'S', 'u', ' ', 3, 'W', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'W', 'a', 'n', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'L', 'i', ' ', 4, 'S', 'h', 'a', ' ', 4, 'S', 'h', 'a', ' ', 4, 'G', 'a', 'o', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'U', 'g', 'u', 'i', ' ', 6, 'A', 's', 'a', 'r', 'i', ' ', 10, 'S', 'u', 'b', 'a', 's', 'h', 'i', 'r', 'i', ' ', 9, 'K', 'a', 'z', 'u', 'n', 'o', 'k', 'o', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 3, 'N', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'Q', 'i', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'N', 'e', 'i', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'J', 'i', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'Q', 'i', 'e', ' ', 3, 'G', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'L', 'a', 'i', ' ', 4, 'F', 'e', 'i', ' ', 3, 'N', 'i', ' ', 3, 'Y', 'i', ' ', 4, 'K', 'u', 'n', ' ', 3, 'L', 'u', ' ', 4, 'J', 'i', 'u', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'L', 'u', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'L', 'i', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'N', 'i', 'a', 'n', ' ', 7, 'S', 'h', 'a', 'c', 'h', 'i', ' ', 6, 'D', 'o', 'j', 'o', 'u', ' ', 8, 'S', 'u', 'k', 'e', 's', 'o', 'u', ' ', 4, 'S', 'h', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'H', 'u', 'n', ' ', 4, 'S', 'h', 'i', ' ', 4, 'H', 'o', 'u', ' ', 5, 'X', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'L', 'a', ' ', 5, 'Z', 'o', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'B', 'i', 'a', 'n', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'Z', 'e', ' ', 4, 'W', 'e', 'i', ' ', 4, 'W', 'e', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'Q', 'u', 'n', ' ', 4, 'R', 'o', 'u', ' ', 4, 'D', 'i', 'e', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'B', 'i', ' ', 2, 'E', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 4, 'S', 'a', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'X', 'i', 'a', ' ', 4, 'T', 'u', 'o', ' ', 3, 'H', 'u', ' ', 8, 'M', 'u', 'r', 'o', 'a', 'j', 'i', ' ', 4, 'R', 'u', 'o', ' ', 7, 'H', 'a', 'r', 'a', 'k', 'a', ' ', 4, 'W', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'H', 'a', 'o', ' ', 3, 'W', 'u', ' ', 5, 'F', 'a', 'n', 'g', ' ', 4, 'S', 'a', 'o', ' ', 4, 'L', 'i', 'u', ' ', 3, 'M', 'a', ' ', 4, 'S', 'h', 'i', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'i', 'n', ' ', 2, 'Z', ' ', 5, 'T', 'e', 'n', 'g', ' ', 3, 'T', 'a', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'G', 'e', ' ', 5, 'R', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 4, 'W', 'e', 'n', ' ', 4, 'R', 'u', 'o', ' ', 9, 'H', 'a', 't', 'a', 'h', 'a', 't', 'a', ' ', 5, 'L', 'i', 'a', 'n', ' ', 3, 'A', 'o', ' ', 3, 'L', 'e', ' ', 4, 'H', 'u', 'i', ' ', 4, 'M', 'i', 'n', ' ', 3, 'J', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'Q', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'S', 'a', 'o', ' ', 4, 'M', 'a', 'n', ' ', 3, 'X', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 4, 'Q', 'i', 'u', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 5, 'K', 'a', 'n', 'g', ' ', 4, 'X', 'u', 'e', ' ', 4, 'B', 'i', 'e', ' ', 4, 'J', 'u', 'e', ' ', 3, 'Q', 'u', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'B', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'X', 'u', 'n', ' ', 3, 'S', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'Z', 'u', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'F', 'a', 'n', ' ', 4, 'J', 'u', 'e', ' ', 4, 'L', 'i', 'n', ' ', 4, 'X', 'u', 'n', ' ', 5, 'M', 'i', 'a', 'o', ' ', 3, 'X', 'i', ' ', 4, 'E', 's', 'o', ' ', 5, 'K', 'y', 'o', 'u', ' ', 4, 'F', 'e', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 4, 'H', 'o', 'u', ' ', 5, 'K', 'u', 'a', 'i', ' ', 4, 'Z', 'e', 'i', ' ', 4, 'S', 'a', 'o', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 4, 'G', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 9, 'H', 'a', 't', 'a', 'h', 'a', 't', 'a', ' ', 7, 'S', 'h', 'i', 'i', 'r', 'a', ' ', 6, 'M', 'u', 't', 's', 'u', ' ', 3, 'R', 'u', ' ', 3, 'J', 'i', ' ', 3, 'X', 'u', ' ', 4, 'H', 'u', 'o', ' ', 7, 'S', 'h', 'i', 'i', 'r', 'a', ' ', 3, 'L', 'i', ' ', 4, 'L', 'i', 'e', ' ', 3, 'L', 'i', ' ', 4, 'M', 'i', 'e', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 2, 'E', ' ', 3, 'L', 'u', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'L', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'D', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'T', 'u', 'n', ' ', 3, 'L', 'u', ' ', 5, 'F', 'a', 'n', 'g', ' ', 3, 'B', 'a', ' ', 3, 'H', 'e', ' ', 3, 'B', 'o', ' ', 5, 'P', 'i', 'n', 'g', ' ', 5, 'N', 'i', 'a', 'n', ' ', 3, 'L', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'Z', 'h', 'a', ' ', 3, 'F', 'u', ' ', 3, 'B', 'o', ' ', 4, 'B', 'a', 'o', ' ', 4, 'H', 'o', 'u', ' ', 3, 'P', 'i', ' ', 4, 'T', 'a', 'i', ' ', 4, 'G', 'u', 'i', ' ', 4, 'J', 'i', 'e', ' ', 4, 'K', 'a', 'o', ' ', 4, 'W', 'e', 'i', ' ', 3, 'E', 'r', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'Z', 'e', ' ', 4, 'H', 'o', 'u', ' ', 5, 'K', 'u', 'a', 'i', ' ', 3, 'J', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'Z', 'a', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'X', 'u', 'n', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'L', 'i', ' ', 5, 'L', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'L', 'i', ' ', 4, 'S', 'h', 'i', ' ', 5, 'T', 'i', 'a', 'o', ' ', 4, 'G', 'u', 'n', ' ', 4, 'S', 'h', 'a', ' ', 4, 'W', 'a', 'n', ' ', 4, 'J', 'u', 'n', ' ', 3, 'J', 'i', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 4, 'Z', 'o', 'u', ' ', 4, 'F', 'e', 'i', ' ', 4, 'K', 'u', 'n', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 3, 'G', 'u', ' ', 3, 'N', 'i', ' ', 5, 'N', 'i', 'a', 'n', ' ', 5, 'D', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'Z', 'i', ' ', 4, 'F', 'e', 'n', ' ', 4, 'D', 'i', 'e', ' ', 3, 'B', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'W', 'e', 'n', ' ', 4, 'W', 'e', 'i', ' ', 4, 'S', 'a', 'i', ' ', 2, 'E', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'F', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 6, 'J', 'i', 'a', 'n', 'g', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'S', 'a', 'o', ' ', 3, 'A', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'T', 'a', ' ', 4, 'Y', 'i', 'n', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'F', 'a', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'L', 'e', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'X', 'u', 'e', ' ', 4, 'B', 'i', 'e', ' ', 4, 'M', 'a', 'n', ' ', 4, 'M', 'i', 'n', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'W', 'e', 'i', ' ', 3, 'X', 'i', ' ', 4, 'J', 'u', 'e', ' ', 5, 'S', 'h', 'a', 'n', ' ', 4, 'L', 'i', 'n', ' ', 4, 'Z', 'u', 'n', ' ', 4, 'H', 'u', 'o', ' ', 4, 'G', 'a', 'n', ' ', 3, 'L', 'i', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'G', 'u', 'a', 'n', ' ', 5, 'N', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'F', 'u', ' ', 3, 'L', 'i', ' ', 4, 'J', 'i', 'u', ' ', 3, 'B', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'F', 'u', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'N', 'i', 'o', ' ', 4, 'G', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 5, 'F', 'e', 'n', 'g', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'B', 'a', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'H', 'u', ' ', 4, 'Q', 'i', 'n', ' ', 3, 'F', 'u', ' ', 4, 'F', 'e', 'n', ' ', 4, 'W', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'S', 'h', 'i', ' ', 3, 'Y', 'u', ' ', 4, 'F', 'o', 'u', ' ', 5, 'Y', 'i', 'a', 'o', ' ', 4, 'J', 'u', 'e', ' ', 4, 'J', 'u', 'e', ' ', 3, 'P', 'i', ' ', 5, 'H', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'B', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Y', 'a', ' ', 6, 'Z', 'h', 'e', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 5, 'F', 'e', 'n', 'g', ' ', 4, 'W', 'e', 'n', ' ', 3, 'O', 'u', ' ', 3, 'T', 'e', ' ', 4, 'J', 'i', 'a', ' ', 3, 'N', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'M', 'i', 'e', ' ', 3, 'F', 'u', ' ', 4, 'T', 'u', 'o', ' ', 4, 'W', 'e', 'n', ' ', 3, 'L', 'i', ' ', 5, 'B', 'i', 'a', 'n', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'G', 'e', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 3, 'Q', 'u', ' ', 5, 'X', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'D', 'a', 'n', ' ', 3, 'J', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'G', 'u', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'R', 'o', 'n', 'g', ' ', 3, 'Y', 'a', ' ', 4, 'T', 'i', 'e', ' ', 3, 'Y', 'u', ' ', 6, 'S', 'h', 'i', 'g', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 3, 'W', 'u', ' ', 3, 'E', 'r', ' ', 4, 'G', 'u', 'a', ' ', 3, 'A', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'J', 'i', ' ', 4, 'L', 'i', 'e', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'R', 'e', 'n', ' ', 3, 'Y', 'i', ' ', 5, 'H', 'o', 'n', 'g', ' ', 4, 'L', 'u', 'o', ' ', 3, 'R', 'u', ' ', 4, 'M', 'o', 'u', ' ', 3, 'G', 'e', ' ', 4, 'R', 'e', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'X', 'i', 'u', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'L', 'u', 'o', ' ', 8, 'C', 'h', 'i', 'd', 'o', 'r', 'i', ' ', 5, 'T', 'o', 'k', 'i', ' ', 4, 'T', 'e', 'n', ' ', 5, 'L', 'u', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 3, 'J', 'i', ' ', 3, 'Y', 'u', ' ', 5, 'H', 'u', 'a', 'n', ' ', 4, 'T', 'u', 'o', ' ', 3, 'B', 'u', ' ', 3, 'W', 'u', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'B', 'o', ' ', 4, 'X', 'u', 'n', ' ', 4, 'X', 'u', 'n', ' ', 3, 'B', 'i', ' ', 3, 'X', 'i', ' ', 4, 'J', 'u', 'n', ' ', 3, 'J', 'u', ' ', 3, 'T', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'T', 'i', ' ', 2, 'E', ' ', 2, 'E', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 3, 'H', 'u', ' ', 3, 'W', 'u', ' ', 5, 'S', 'h', 'e', 'n', ' ', 4, 'L', 'a', 'i', ' ', 8, 'I', 'k', 'a', 'r', 'u', 'g', 'a', ' ', 7, 'K', 'a', 'k', 'e', 's', 'u', ' ', 3, 'L', 'u', ' ', 5, 'P', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 3, 'F', 'u', ' ', 3, 'A', 'n', ' ', 5, 'Z', 'h', 'a', 'o', ' ', 5, 'P', 'e', 'n', 'g', ' ', 4, 'Q', 'i', 'n', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'B', 'e', 'i', ' ', 5, 'D', 'i', 'a', 'o', ' ', 3, 'L', 'u', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 3, 'T', 'u', ' ', 3, 'Y', 'a', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'Q', 'i', ' ', 3, 'L', 'i', ' ', 3, 'Y', 'e', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 5, 'K', 'o', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'i', ' ', 4, 'K', 'u', 'n', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'Y', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 4, 'L', 'a', 'i', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'G', 'e', 'n', 'g', ' ', 3, 'J', 'u', ' ', 3, 'Q', 'u', ' ', 6, 'I', 's', 'u', 'k', 'a', ' ', 12, 'K', 'i', 'k', 'u', 'i', 't', 'a', 'd', 'a', 'k', 'i', ' ', 3, 'J', 'i', ' ', 4, 'S', 'h', 'u', ' ', 4, 'C', 'h', 'i', ' ', 5, 'M', 'i', 'a', 'o', ' ', 4, 'R', 'o', 'u', ' ', 3, 'A', 'n', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'T', 'i', ' ', 3, 'H', 'u', ' ', 3, 'T', 'i', ' ', 2, 'E', ' ', 4, 'J', 'i', 'e', ' ', 4, 'M', 'a', 'o', ' ', 3, 'F', 'u', ' ', 5, 'C', 'h', 'u', 'n', ' ', 3, 'T', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'H', 'e', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'P', 'i', 'a', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'M', 'e', 'i', ' ', 3, 'H', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'D', 'u', 'n', ' ', 3, 'M', 'u', ' ', 3, 'J', 'u', ' ', 8, 'T', 's', 'u', 'g', 'u', 'm', 'i', ' ', 5, 'C', 'a', 'n', 'g', ' ', 5, 'F', 'a', 'n', 'g', ' ', 3, 'G', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'W', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 3, 'H', 'e', ' ', 4, 'C', 'h', 'u', ' ', 5, 'T', 'a', 'n', 'g', ' ', 4, 'X', 'i', 'a', ' ', 4, 'R', 'u', 'o', ' ', 4, 'L', 'i', 'u', ' ', 3, 'J', 'i', ' ', 3, 'G', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'Z', 'h', 'u', 'n', ' ', 4, 'H', 'a', 'n', ' ', 3, 'Z', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'N', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'J', 'i', ' ', 3, 'L', 'i', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'K', 'o', 'u', ' ', 3, 'T', 'i', ' ', 3, 'T', 'i', ' ', 3, 'N', 'i', ' ', 3, 'T', 'u', ' ', 3, 'M', 'a', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'G', 'a', 'o', ' ', 5, 'T', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'L', 'i', ' ', 6, 'Z', 'h', 'u', 'a', 'n', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'A', 'o', ' ', 4, 'Y', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 3, 'O', 'u', ' ', 4, 'C', 'h', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'R', 'o', 'n', 'g', ' ', 4, 'L', 'o', 'u', ' ', 3, 'B', 'i', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 5, 'Z', 'h', 'u', 'o', ' ', 3, 'Y', 'u', ' ', 3, 'W', 'u', ' ', 4, 'J', 'u', 'e', ' ', 4, 'Y', 'i', 'n', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 3, 'S', 'i', ' ', 5, 'J', 'i', 'a', 'o', ' ', 3, 'Y', 'i', ' ', 4, 'H', 'u', 'a', ' ', 3, 'B', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'S', 'u', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'F', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'K', 'a', 'o', ' ', 4, 'J', 'i', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'T', 'u', ' ', 4, 'M', 'a', 'i', ' ', 4, 'Z', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 3, 'L', 'u', ' ', 5, 'T', 'u', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'X', 'u', 'e', ' ', 3, 'Y', 'i', ' ', 3, 'P', 'i', ' ', 4, 'S', 'h', 'u', ' ', 4, 'L', 'u', 'o', ' ', 3, 'Q', 'i', ' ', 3, 'Y', 'i', ' ', 3, 'J', 'i', ' ', 4, 'Z', 'h', 'e', ' ', 3, 'Y', 'u', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 3, 'Y', 'e', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'P', 'i', ' ', 5, 'N', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 3, 'M', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'M', 'e', 'n', 'g', ' ', 3, 'D', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 3, 'Y', 'u', ' ', 4, 'L', 'e', 'i', ' ', 4, 'B', 'a', 'o', ' ', 3, 'L', 'u', ' ', 3, 'H', 'e', ' ', 5, 'L', 'o', 'n', 'g', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 3, 'L', 'i', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'N', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'u', ' ', 3, 'J', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'M', 'i', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 3, 'O', 'u', ' ', 3, 'Y', 'a', ' ', 5, 'C', 'a', 'n', 'g', ' ', 4, 'B', 'a', 'o', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 3, 'G', 'u', ' ', 5, 'D', 'o', 'n', 'g', ' ', 3, 'L', 'u', ' ', 3, 'Y', 'a', ' ', 5, 'X', 'i', 'a', 'o', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'Q', 'u', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 4, 'X', 'u', 'e', ' ', 4, 'T', 'u', 'o', ' ', 3, 'S', 'i', ' ', 4, 'Z', 'h', 'i', ' ', 3, 'E', 'r', ' ', 4, 'G', 'u', 'a', ' ', 4, 'X', 'i', 'u', ' ', 5, 'H', 'e', 'n', 'g', ' ', 5, 'Z', 'h', 'o', 'u', ' ', 3, 'G', 'e', ' ', 5, 'L', 'u', 'a', 'n', ' ', 5, 'H', 'o', 'n', 'g', ' ', 3, 'W', 'u', ' ', 3, 'B', 'o', ' ', 3, 'L', 'i', ' ', 5, 'J', 'u', 'a', 'n', ' ', 3, 'H', 'u', ' ', 2, 'E', ' ', 3, 'Y', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'T', 'i', ' ', 3, 'W', 'u', ' ', 4, 'Q', 'u', 'e', ' ', 5, 'M', 'i', 'a', 'o', ' ', 3, 'A', 'n', ' ', 4, 'K', 'u', 'n', ' ', 4, 'B', 'e', 'i', ' ', 5, 'P', 'e', 'n', 'g', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 5, 'C', 'h', 'u', 'n', ' ', 5, 'G', 'e', 'n', 'g', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'S', 'u', ' ', 3, 'H', 'u', ' ', 3, 'H', 'e', ' ', 2, 'E', ' ', 3, 'G', 'u', ' ', 4, 'Q', 'i', 'u', ' ', 3, 'Z', 'i', ' ', 4, 'M', 'e', 'i', ' ', 3, 'M', 'u', ' ', 3, 'N', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'W', 'e', 'n', 'g', ' ', 4, 'L', 'i', 'u', ' ', 3, 'J', 'i', ' ', 3, 'N', 'i', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'H', 'e', ' ', 3, 'Y', 'i', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'Z', 'h', 'e', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'a', 'o', ' ', 5, 'J', 'i', 'a', 'o', ' ', 4, 'J', 'i', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'L', 'u', ' ', 5, 'X', 'u', 'a', 'n', ' ', 5, 'Z', 'h', 'a', 'n', ' ', 5, 'Y', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'o', ' ', 5, 'M', 'e', 'n', 'g', ' ', 5, 'G', 'u', 'a', 'n', ' ', 7, 'S', 'h', 'u', 'a', 'n', 'g', ' ', 3, 'L', 'u', ' ', 4, 'J', 'i', 'n', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'C', 'u', 'o', ' ', 5, 'J', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'C', 'u', 'o', ' ', 3, 'L', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 3, 'C', 'u', ' ', 3, 'J', 'i', ' ', 5, 'B', 'i', 'a', 'o', ' ', 3, 'C', 'u', ' ', 5, 'B', 'i', 'a', 'o', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'J', 'u', 'n', ' ', 4, 'Z', 'h', 'u', ' ', 5, 'J', 'i', 'a', 'n', ' ', 3, 'M', 'i', ' ', 3, 'M', 'i', ' ', 3, 'W', 'u', ' ', 4, 'L', 'i', 'u', ' ', 5, 'C', 'h', 'e', 'n', ' ', 4, 'J', 'u', 'n', ' ', 4, 'L', 'i', 'n', ' ', 3, 'N', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'L', 'u', ' ', 4, 'J', 'i', 'u', ' ', 4, 'J', 'u', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'L', 'i', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'J', 'i', 'a', ' ', 3, 'M', 'i', ' ', 3, 'L', 'i', ' ', 4, 'S', 'h', 'e', ' ', 6, 'Z', 'h', 'a', 'n', 'g', ' ', 4, 'L', 'i', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'J', 'i', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'C', 'u', ' ', 4, 'M', 'a', 'i', ' ', 4, 'M', 'a', 'i', ' ', 3, 'G', 'e', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'F', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'F', 'u', ' ', 4, 'P', 'a', 'o', ' ', 3, 'Q', 'u', ' ', 3, 'Q', 'u', ' ', 4, 'M', 'o', 'u', ' ', 3, 'F', 'u', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'L', 'a', 'i', ' ', 3, 'Q', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 5, 'F', 'e', 'n', 'g', ' ', 3, 'F', 'u', ' ', 3, 'Q', 'u', ' ', 5, 'M', 'i', 'a', 'n', ' ', 3, 'M', 'a', ' ', 3, 'M', 'o', ' ', 3, 'M', 'o', ' ', 4, 'H', 'u', 'i', ' ', 3, 'M', 'a', ' ', 4, 'Z', 'o', 'u', ' ', 4, 'N', 'e', 'n', ' ', 4, 'F', 'e', 'n', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 6, 'H', 'u', 'a', 'n', 'g', ' ', 4, 'J', 'i', 'n', ' ', 6, 'G', 'u', 'a', 'n', 'g', ' ', 5, 'T', 'i', 'a', 'n', ' ', 4, 'T', 'o', 'u', ' ', 5, 'H', 'e', 'n', 'g', ' ', 3, 'X', 'i', ' ', 6, 'K', 'u', 'a', 'n', 'g', ' ', 5, 'H', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 3, 'L', 'i', ' ', 5, 'N', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'i', ' ', 4, 'H', 'e', 'i', ' ', 4, 'H', 'e', 'i', ' ', 3, 'Y', 'i', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'D', 'a', 'n', ' ', 3, 'X', 'i', ' ', 5, 'T', 'u', 'a', 'n', ' ', 3, 'M', 'o', ' ', 3, 'M', 'o', ' ', 5, 'Q', 'i', 'a', 'n', ' ', 4, 'D', 'a', 'i', ' ', 4, 'C', 'h', 'u', ' ', 4, 'Y', 'o', 'u', ' ', 5, 'D', 'i', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'X', 'i', 'a', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'Q', 'u', ' ', 4, 'M', 'e', 'i', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 3, 'L', 'i', ' ', 5, 'D', 'a', 'n', 'g', ' ', 3, 'D', 'u', ' ', 4, 'C', 'a', 'n', ' ', 4, 'Y', 'i', 'n', ' ', 3, 'A', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'T', 'a', 'n', ' ', 3, 'A', 'n', ' ', 5, 'Z', 'h', 'e', 'n', ' ', 4, 'D', 'a', 'i', ' ', 4, 'C', 'a', 'n', ' ', 3, 'Y', 'i', ' ', 4, 'M', 'e', 'i', ' ', 4, 'D', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'D', 'u', ' ', 3, 'L', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 4, 'F', 'e', 'n', ' ', 3, 'F', 'u', ' ', 3, 'F', 'u', ' ', 4, 'M', 'i', 'n', ' ', 4, 'M', 'i', 'n', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'C', 'u', ' ', 3, 'Q', 'u', ' ', 5, 'C', 'h', 'a', 'o', ' ', 3, 'W', 'a', ' ', 4, 'Z', 'h', 'u', ' ', 4, 'Z', 'h', 'i', ' ', 5, 'M', 'a', 'n', 'g', ' ', 3, 'A', 'o', ' ', 4, 'B', 'i', 'e', ' ', 4, 'T', 'u', 'o', ' ', 3, 'B', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'C', 'h', 'a', 'o', ' ', 4, 'T', 'u', 'o', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'M', 'i', ' ', 4, 'N', 'a', 'i', ' ', 5, 'D', 'i', 'n', 'g', ' ', 3, 'Z', 'i', ' ', 3, 'G', 'u', ' ', 3, 'G', 'u', ' ', 5, 'D', 'o', 'n', 'g', ' ', 4, 'F', 'e', 'n', ' ', 4, 'T', 'a', 'o', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 3, 'P', 'i', ' ', 6, 'C', 'h', 'a', 'n', 'g', ' ', 4, 'G', 'a', 'o', ' ', 3, 'Q', 'i', ' ', 5, 'Y', 'u', 'a', 'n', ' ', 5, 'T', 'a', 'n', 'g', ' ', 5, 'T', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'u', ' ', 4, 'S', 'h', 'u', ' ', 4, 'F', 'e', 'n', ' ', 4, 'F', 'e', 'i', ' ', 4, 'W', 'e', 'n', ' ', 3, 'B', 'a', ' ', 5, 'D', 'i', 'a', 'o', ' ', 4, 'T', 'u', 'o', ' ', 5, 'T', 'o', 'n', 'g', ' ', 3, 'Q', 'u', ' ', 6, 'S', 'h', 'e', 'n', 'g', ' ', 4, 'S', 'h', 'i', ' ', 4, 'Y', 'o', 'u', ' ', 4, 'S', 'h', 'i', ' ', 5, 'T', 'i', 'n', 'g', ' ', 3, 'W', 'u', ' ', 5, 'N', 'i', 'a', 'n', ' ', 5, 'J', 'i', 'n', 'g', ' ', 4, 'H', 'u', 'n', ' ', 3, 'J', 'u', ' ', 4, 'Y', 'a', 'n', ' ', 3, 'T', 'u', ' ', 3, 'T', 'i', ' ', 3, 'X', 'i', ' ', 5, 'X', 'i', 'a', 'n', ' ', 4, 'Y', 'a', 'n', ' ', 4, 'L', 'e', 'i', ' ', 3, 'B', 'i', ' ', 4, 'Y', 'a', 'o', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'H', 'a', 'n', ' ', 3, 'W', 'u', ' ', 3, 'W', 'u', ' ', 4, 'H', 'o', 'u', ' ', 3, 'X', 'i', ' ', 3, 'G', 'e', ' ', 4, 'Z', 'h', 'a', ' ', 4, 'X', 'i', 'u', ' ', 5, 'W', 'e', 'n', 'g', ' ', 4, 'Z', 'h', 'a', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'N', 'a', 'n', 'g', ' ', 3, 'Q', 'i', ' ', 5, 'Z', 'h', 'a', 'i', ' ', 3, 'J', 'i', ' ', 3, 'Z', 'i', ' ', 3, 'J', 'i', ' ', 3, 'J', 'i', ' ', 3, 'Q', 'i', ' ', 3, 'J', 'i', ' ', 4, 'C', 'h', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'H', 'e', ' ', 3, 'Y', 'a', ' ', 4, 'K', 'e', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'P', 'a', 'o', ' ', 4, 'C', 'u', 'o', ' ', 4, 'S', 'h', 'i', ' ', 3, 'Z', 'i', ' ', 4, 'C', 'h', 'i', ' ', 5, 'N', 'i', 'a', 'n', ' ', 3, 'J', 'u', ' ', 5, 'T', 'i', 'a', 'o', ' ', 5, 'L', 'i', 'n', 'g', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'C', 'h', 'u', ' ', 5, 'Q', 'u', 'a', 'n', ' ', 4, 'X', 'i', 'e', ' ', 4, 'K', 'e', 'n', ' ', 4, 'N', 'i', 'e', ' ', 4, 'J', 'i', 'u', ' ', 4, 'Y', 'a', 'o', ' ', 5, 'C', 'h', 'u', 'o', ' ', 4, 'K', 'u', 'n', ' ', 3, 'Y', 'u', ' ', 4, 'C', 'h', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'N', 'i', ' ', 4, 'C', 'u', 'o', ' ', 4, 'Z', 'o', 'u', ' ', 3, 'Q', 'u', ' ', 4, 'N', 'e', 'n', ' ', 5, 'X', 'i', 'a', 'n', ' ', 3, 'O', 'u', ' ', 2, 'E', ' ', 3, 'W', 'o', ' ', 3, 'Y', 'i', ' ', 5, 'C', 'h', 'u', 'o', ' ', 4, 'Z', 'o', 'u', ' ', 5, 'D', 'i', 'a', 'n', ' ', 4, 'C', 'h', 'u', ' ', 4, 'J', 'i', 'n', ' ', 3, 'Y', 'a', ' ', 4, 'C', 'h', 'i', ' ', 5, 'C', 'h', 'e', 'n', ' ', 3, 'H', 'e', ' ', 4, 'K', 'e', 'n', ' ', 3, 'J', 'u', ' ', 5, 'L', 'i', 'n', 'g', ' ', 4, 'P', 'a', 'o', ' ', 5, 'T', 'i', 'a', 'o', ' ', 3, 'Z', 'i', ' ', 4, 'K', 'e', 'n', ' ', 3, 'Y', 'u', ' ', 5, 'C', 'h', 'u', 'o', ' ', 3, 'Q', 'u', ' ', 3, 'W', 'o', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'P', 'a', 'n', 'g', ' ', 5, 'G', 'o', 'n', 'g', ' ', 5, 'P', 'a', 'n', 'g', ' ', 4, 'Y', 'a', 'n', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'K', 'a', 'n', ' ', 3, 'T', 'a', ' ', 5, 'L', 'i', 'n', 'g', ' ', 3, 'T', 'a', ' ', 5, 'L', 'o', 'n', 'g', ' ', 5, 'G', 'o', 'n', 'g', ' ', 4, 'K', 'a', 'n', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Q', 'i', 'u', ' ', 4, 'B', 'i', 'e', ' ', 4, 'G', 'u', 'i', ' ', 4, 'Y', 'u', 'e', ' ', 5, 'C', 'h', 'u', 'i', ' ', 3, 'H', 'e', ' ', 4, 'J', 'u', 'e', ' ', 4, 'X', 'i', 'e', ' ', 3, 'Y', 'u', ' ', 2, 'i', 't', 2, 'i', 'x', 1, 'i', 2, 'i', 'p', 3, 'i', 'e', 't', 3, 'i', 'e', 'x', 2, 'i', 'e', 3, 'i', 'e', 'p', 2, 'a', 't', 2, 'a', 'x', 1, 'a', 2, 'a', 'p', 3, 'u', 'o', 'x', 2, 'u', 'o', 3, 'u', 'o', 'p', 2, 'o', 't', 2, 'o', 'x', 1, 'o', 2, 'o', 'p', 2, 'e', 'x', 1, 'e', 2, 'w', 'u', 3, 'b', 'i', 't', 3, 'b', 'i', 'x', 2, 'b', 'i', 3, 'b', 'i', 'p', 4, 'b', 'i', 'e', 't', 4, 'b', 'i', 'e', 'x', 3, 'b', 'i', 'e', 4, 'b', 'i', 'e', 'p', 3, 'b', 'a', 't', 3, 'b', 'a', 'x', 2, 'b', 'a', 3, 'b', 'a', 'p', 4, 'b', 'u', 'o', 'x', 3, 'b', 'u', 'o', 4, 'b', 'u', 'o', 'p', 3, 'b', 'o', 't', 3, 'b', 'o', 'x', 2, 'b', 'o', 3, 'b', 'o', 'p', 3, 'b', 'e', 'x', 2, 'b', 'e', 3, 'b', 'e', 'p', 3, 'b', 'u', 't', 3, 'b', 'u', 'x', 2, 'b', 'u', 3, 'b', 'u', 'p', 4, 'b', 'u', 'r', 'x', 3, 'b', 'u', 'r', 3, 'b', 'y', 't', 3, 'b', 'y', 'x', 2, 'b', 'y', 3, 'b', 'y', 'p', 4, 'b', 'y', 'r', 'x', 3, 'b', 'y', 'r', 3, 'p', 'i', 't', 3, 'p', 'i', 'x', 2, 'p', 'i', 3, 'p', 'i', 'p', 4, 'p', 'i', 'e', 'x', 3, 'p', 'i', 'e', 4, 'p', 'i', 'e', 'p', 3, 'p', 'a', 't', 3, 'p', 'a', 'x', 2, 'p', 'a', 3, 'p', 'a', 'p', 4, 'p', 'u', 'o', 'x', 3, 'p', 'u', 'o', 4, 'p', 'u', 'o', 'p', 3, 'p', 'o', 't', 3, 'p', 'o', 'x', 2, 'p', 'o', 3, 'p', 'o', 'p', 3, 'p', 'u', 't', 3, 'p', 'u', 'x', 2, 'p', 'u', 3, 'p', 'u', 'p', 4, 'p', 'u', 'r', 'x', 3, 'p', 'u', 'r', 3, 'p', 'y', 't', 3, 'p', 'y', 'x', 2, 'p', 'y', 3, 'p', 'y', 'p', 4, 'p', 'y', 'r', 'x', 3, 'p', 'y', 'r', 4, 'b', 'b', 'i', 't', 4, 'b', 'b', 'i', 'x', 3, 'b', 'b', 'i', 4, 'b', 'b', 'i', 'p', 5, 'b', 'b', 'i', 'e', 't', 5, 'b', 'b', 'i', 'e', 'x', 4, 'b', 'b', 'i', 'e', 5, 'b', 'b', 'i', 'e', 'p', 4, 'b', 'b', 'a', 't', 4, 'b', 'b', 'a', 'x', 3, 'b', 'b', 'a', 4, 'b', 'b', 'a', 'p', 5, 'b', 'b', 'u', 'o', 'x', 4, 'b', 'b', 'u', 'o', 5, 'b', 'b', 'u', 'o', 'p', 4, 'b', 'b', 'o', 't', 4, 'b', 'b', 'o', 'x', 3, 'b', 'b', 'o', 4, 'b', 'b', 'o', 'p', 4, 'b', 'b', 'e', 'x', 3, 'b', 'b', 'e', 4, 'b', 'b', 'e', 'p', 4, 'b', 'b', 'u', 't', 4, 'b', 'b', 'u', 'x', 3, 'b', 'b', 'u', 4, 'b', 'b', 'u', 'p', 5, 'b', 'b', 'u', 'r', 'x', 4, 'b', 'b', 'u', 'r', 4, 'b', 'b', 'y', 't', 4, 'b', 'b', 'y', 'x', 3, 'b', 'b', 'y', 4, 'b', 'b', 'y', 'p', 4, 'n', 'b', 'i', 't', 4, 'n', 'b', 'i', 'x', 3, 'n', 'b', 'i', 4, 'n', 'b', 'i', 'p', 5, 'n', 'b', 'i', 'e', 'x', 4, 'n', 'b', 'i', 'e', 5, 'n', 'b', 'i', 'e', 'p', 4, 'n', 'b', 'a', 't', 4, 'n', 'b', 'a', 'x', 3, 'n', 'b', 'a', 4, 'n', 'b', 'a', 'p', 4, 'n', 'b', 'o', 't', 4, 'n', 'b', 'o', 'x', 3, 'n', 'b', 'o', 4, 'n', 'b', 'o', 'p', 4, 'n', 'b', 'u', 't', 4, 'n', 'b', 'u', 'x', 3, 'n', 'b', 'u', 4, 'n', 'b', 'u', 'p', 5, 'n', 'b', 'u', 'r', 'x', 4, 'n', 'b', 'u', 'r', 4, 'n', 'b', 'y', 't', 4, 'n', 'b', 'y', 'x', 3, 'n', 'b', 'y', 4, 'n', 'b', 'y', 'p', 5, 'n', 'b', 'y', 'r', 'x', 4, 'n', 'b', 'y', 'r', 4, 'h', 'm', 'i', 't', 4, 'h', 'm', 'i', 'x', 3, 'h', 'm', 'i', 4, 'h', 'm', 'i', 'p', 5, 'h', 'm', 'i', 'e', 'x', 4, 'h', 'm', 'i', 'e', 5, 'h', 'm', 'i', 'e', 'p', 4, 'h', 'm', 'a', 't', 4, 'h', 'm', 'a', 'x', 3, 'h', 'm', 'a', 4, 'h', 'm', 'a', 'p', 5, 'h', 'm', 'u', 'o', 'x', 4, 'h', 'm', 'u', 'o', 5, 'h', 'm', 'u', 'o', 'p', 4, 'h', 'm', 'o', 't', 4, 'h', 'm', 'o', 'x', 3, 'h', 'm', 'o', 4, 'h', 'm', 'o', 'p', 4, 'h', 'm', 'u', 't', 4, 'h', 'm', 'u', 'x', 3, 'h', 'm', 'u', 4, 'h', 'm', 'u', 'p', 5, 'h', 'm', 'u', 'r', 'x', 4, 'h', 'm', 'u', 'r', 4, 'h', 'm', 'y', 'x', 3, 'h', 'm', 'y', 4, 'h', 'm', 'y', 'p', 5, 'h', 'm', 'y', 'r', 'x', 4, 'h', 'm', 'y', 'r', 3, 'm', 'i', 't', 3, 'm', 'i', 'x', 2, 'm', 'i', 3, 'm', 'i', 'p', 4, 'm', 'i', 'e', 'x', 3, 'm', 'i', 'e', 4, 'm', 'i', 'e', 'p', 3, 'm', 'a', 't', 3, 'm', 'a', 'x', 2, 'm', 'a', 3, 'm', 'a', 'p', 4, 'm', 'u', 'o', 't', 4, 'm', 'u', 'o', 'x', 3, 'm', 'u', 'o', 4, 'm', 'u', 'o', 'p', 3, 'm', 'o', 't', 3, 'm', 'o', 'x', 2, 'm', 'o', 3, 'm', 'o', 'p', 3, 'm', 'e', 'x', 2, 'm', 'e', 3, 'm', 'u', 't', 3, 'm', 'u', 'x', 2, 'm', 'u', 3, 'm', 'u', 'p', 4, 'm', 'u', 'r', 'x', 3, 'm', 'u', 'r', 3, 'm', 'y', 't', 3, 'm', 'y', 'x', 2, 'm', 'y', 3, 'm', 'y', 'p', 3, 'f', 'i', 't', 3, 'f', 'i', 'x', 2, 'f', 'i', 3, 'f', 'i', 'p', 3, 'f', 'a', 't', 3, 'f', 'a', 'x', 2, 'f', 'a', 3, 'f', 'a', 'p', 3, 'f', 'o', 'x', 2, 'f', 'o', 3, 'f', 'o', 'p', 3, 'f', 'u', 't', 3, 'f', 'u', 'x', 2, 'f', 'u', 3, 'f', 'u', 'p', 4, 'f', 'u', 'r', 'x', 3, 'f', 'u', 'r', 3, 'f', 'y', 't', 3, 'f', 'y', 'x', 2, 'f', 'y', 3, 'f', 'y', 'p', 3, 'v', 'i', 't', 3, 'v', 'i', 'x', 2, 'v', 'i', 3, 'v', 'i', 'p', 4, 'v', 'i', 'e', 't', 4, 'v', 'i', 'e', 'x', 3, 'v', 'i', 'e', 4, 'v', 'i', 'e', 'p', 3, 'v', 'a', 't', 3, 'v', 'a', 'x', 2, 'v', 'a', 3, 'v', 'a', 'p', 3, 'v', 'o', 't', 3, 'v', 'o', 'x', 2, 'v', 'o', 3, 'v', 'o', 'p', 3, 'v', 'e', 'x', 3, 'v', 'e', 'p', 3, 'v', 'u', 't', 3, 'v', 'u', 'x', 2, 'v', 'u', 3, 'v', 'u', 'p', 4, 'v', 'u', 'r', 'x', 3, 'v', 'u', 'r', 3, 'v', 'y', 't', 3, 'v', 'y', 'x', 2, 'v', 'y', 3, 'v', 'y', 'p', 4, 'v', 'y', 'r', 'x', 3, 'v', 'y', 'r', 3, 'd', 'i', 't', 3, 'd', 'i', 'x', 2, 'd', 'i', 3, 'd', 'i', 'p', 4, 'd', 'i', 'e', 'x', 3, 'd', 'i', 'e', 4, 'd', 'i', 'e', 'p', 3, 'd', 'a', 't', 3, 'd', 'a', 'x', 2, 'd', 'a', 3, 'd', 'a', 'p', 4, 'd', 'u', 'o', 'x', 3, 'd', 'u', 'o', 3, 'd', 'o', 't', 3, 'd', 'o', 'x', 2, 'd', 'o', 3, 'd', 'o', 'p', 3, 'd', 'e', 'x', 2, 'd', 'e', 3, 'd', 'e', 'p', 3, 'd', 'u', 't', 3, 'd', 'u', 'x', 2, 'd', 'u', 3, 'd', 'u', 'p', 4, 'd', 'u', 'r', 'x', 3, 'd', 'u', 'r', 3, 't', 'i', 't', 3, 't', 'i', 'x', 2, 't', 'i', 3, 't', 'i', 'p', 4, 't', 'i', 'e', 'x', 3, 't', 'i', 'e', 4, 't', 'i', 'e', 'p', 3, 't', 'a', 't', 3, 't', 'a', 'x', 2, 't', 'a', 3, 't', 'a', 'p', 4, 't', 'u', 'o', 't', 4, 't', 'u', 'o', 'x', 3, 't', 'u', 'o', 4, 't', 'u', 'o', 'p', 3, 't', 'o', 't', 3, 't', 'o', 'x', 2, 't', 'o', 3, 't', 'o', 'p', 3, 't', 'e', 'x', 2, 't', 'e', 3, 't', 'e', 'p', 3, 't', 'u', 't', 3, 't', 'u', 'x', 2, 't', 'u', 3, 't', 'u', 'p', 4, 't', 'u', 'r', 'x', 3, 't', 'u', 'r', 4, 'd', 'd', 'i', 't', 4, 'd', 'd', 'i', 'x', 3, 'd', 'd', 'i', 4, 'd', 'd', 'i', 'p', 5, 'd', 'd', 'i', 'e', 'x', 4, 'd', 'd', 'i', 'e', 5, 'd', 'd', 'i', 'e', 'p', 4, 'd', 'd', 'a', 't', 4, 'd', 'd', 'a', 'x', 3, 'd', 'd', 'a', 4, 'd', 'd', 'a', 'p', 5, 'd', 'd', 'u', 'o', 'x', 4, 'd', 'd', 'u', 'o', 5, 'd', 'd', 'u', 'o', 'p', 4, 'd', 'd', 'o', 't', 4, 'd', 'd', 'o', 'x', 3, 'd', 'd', 'o', 4, 'd', 'd', 'o', 'p', 4, 'd', 'd', 'e', 'x', 3, 'd', 'd', 'e', 4, 'd', 'd', 'e', 'p', 4, 'd', 'd', 'u', 't', 4, 'd', 'd', 'u', 'x', 3, 'd', 'd', 'u', 4, 'd', 'd', 'u', 'p', 5, 'd', 'd', 'u', 'r', 'x', 4, 'd', 'd', 'u', 'r', 4, 'n', 'd', 'i', 't', 4, 'n', 'd', 'i', 'x', 3, 'n', 'd', 'i', 4, 'n', 'd', 'i', 'p', 5, 'n', 'd', 'i', 'e', 'x', 4, 'n', 'd', 'i', 'e', 4, 'n', 'd', 'a', 't', 4, 'n', 'd', 'a', 'x', 3, 'n', 'd', 'a', 4, 'n', 'd', 'a', 'p', 4, 'n', 'd', 'o', 't', 4, 'n', 'd', 'o', 'x', 3, 'n', 'd', 'o', 4, 'n', 'd', 'o', 'p', 4, 'n', 'd', 'e', 'x', 3, 'n', 'd', 'e', 4, 'n', 'd', 'e', 'p', 4, 'n', 'd', 'u', 't', 4, 'n', 'd', 'u', 'x', 3, 'n', 'd', 'u', 4, 'n', 'd', 'u', 'p', 5, 'n', 'd', 'u', 'r', 'x', 4, 'n', 'd', 'u', 'r', 4, 'h', 'n', 'i', 't', 4, 'h', 'n', 'i', 'x', 3, 'h', 'n', 'i', 4, 'h', 'n', 'i', 'p', 5, 'h', 'n', 'i', 'e', 't', 5, 'h', 'n', 'i', 'e', 'x', 4, 'h', 'n', 'i', 'e', 5, 'h', 'n', 'i', 'e', 'p', 4, 'h', 'n', 'a', 't', 4, 'h', 'n', 'a', 'x', 3, 'h', 'n', 'a', 4, 'h', 'n', 'a', 'p', 5, 'h', 'n', 'u', 'o', 'x', 4, 'h', 'n', 'u', 'o', 4, 'h', 'n', 'o', 't', 4, 'h', 'n', 'o', 'x', 4, 'h', 'n', 'o', 'p', 4, 'h', 'n', 'e', 'x', 3, 'h', 'n', 'e', 4, 'h', 'n', 'e', 'p', 4, 'h', 'n', 'u', 't', 3, 'n', 'i', 't', 3, 'n', 'i', 'x', 2, 'n', 'i', 3, 'n', 'i', 'p', 4, 'n', 'i', 'e', 'x', 3, 'n', 'i', 'e', 4, 'n', 'i', 'e', 'p', 3, 'n', 'a', 'x', 2, 'n', 'a', 3, 'n', 'a', 'p', 4, 'n', 'u', 'o', 'x', 3, 'n', 'u', 'o', 4, 'n', 'u', 'o', 'p', 3, 'n', 'o', 't', 3, 'n', 'o', 'x', 2, 'n', 'o', 3, 'n', 'o', 'p', 3, 'n', 'e', 'x', 2, 'n', 'e', 3, 'n', 'e', 'p', 3, 'n', 'u', 't', 3, 'n', 'u', 'x', 2, 'n', 'u', 3, 'n', 'u', 'p', 4, 'n', 'u', 'r', 'x', 3, 'n', 'u', 'r', 4, 'h', 'l', 'i', 't', 4, 'h', 'l', 'i', 'x', 3, 'h', 'l', 'i', 4, 'h', 'l', 'i', 'p', 5, 'h', 'l', 'i', 'e', 'x', 4, 'h', 'l', 'i', 'e', 5, 'h', 'l', 'i', 'e', 'p', 4, 'h', 'l', 'a', 't', 4, 'h', 'l', 'a', 'x', 3, 'h', 'l', 'a', 4, 'h', 'l', 'a', 'p', 5, 'h', 'l', 'u', 'o', 'x', 4, 'h', 'l', 'u', 'o', 5, 'h', 'l', 'u', 'o', 'p', 4, 'h', 'l', 'o', 'x', 3, 'h', 'l', 'o', 4, 'h', 'l', 'o', 'p', 4, 'h', 'l', 'e', 'x', 3, 'h', 'l', 'e', 4, 'h', 'l', 'e', 'p', 4, 'h', 'l', 'u', 't', 4, 'h', 'l', 'u', 'x', 3, 'h', 'l', 'u', 4, 'h', 'l', 'u', 'p', 5, 'h', 'l', 'u', 'r', 'x', 4, 'h', 'l', 'u', 'r', 4, 'h', 'l', 'y', 't', 4, 'h', 'l', 'y', 'x', 3, 'h', 'l', 'y', 4, 'h', 'l', 'y', 'p', 5, 'h', 'l', 'y', 'r', 'x', 4, 'h', 'l', 'y', 'r', 3, 'l', 'i', 't', 3, 'l', 'i', 'x', 2, 'l', 'i', 3, 'l', 'i', 'p', 4, 'l', 'i', 'e', 't', 4, 'l', 'i', 'e', 'x', 3, 'l', 'i', 'e', 4, 'l', 'i', 'e', 'p', 3, 'l', 'a', 't', 3, 'l', 'a', 'x', 2, 'l', 'a', 3, 'l', 'a', 'p', 4, 'l', 'u', 'o', 't', 4, 'l', 'u', 'o', 'x', 3, 'l', 'u', 'o', 4, 'l', 'u', 'o', 'p', 3, 'l', 'o', 't', 3, 'l', 'o', 'x', 2, 'l', 'o', 3, 'l', 'o', 'p', 3, 'l', 'e', 'x', 2, 'l', 'e', 3, 'l', 'e', 'p', 3, 'l', 'u', 't', 3, 'l', 'u', 'x', 2, 'l', 'u', 3, 'l', 'u', 'p', 4, 'l', 'u', 'r', 'x', 3, 'l', 'u', 'r', 3, 'l', 'y', 't', 3, 'l', 'y', 'x', 2, 'l', 'y', 3, 'l', 'y', 'p', 4, 'l', 'y', 'r', 'x', 3, 'l', 'y', 'r', 3, 'g', 'i', 't', 3, 'g', 'i', 'x', 2, 'g', 'i', 3, 'g', 'i', 'p', 4, 'g', 'i', 'e', 't', 4, 'g', 'i', 'e', 'x', 3, 'g', 'i', 'e', 4, 'g', 'i', 'e', 'p', 3, 'g', 'a', 't', 3, 'g', 'a', 'x', 2, 'g', 'a', 3, 'g', 'a', 'p', 4, 'g', 'u', 'o', 't', 4, 'g', 'u', 'o', 'x', 3, 'g', 'u', 'o', 4, 'g', 'u', 'o', 'p', 3, 'g', 'o', 't', 3, 'g', 'o', 'x', 2, 'g', 'o', 3, 'g', 'o', 'p', 3, 'g', 'e', 't', 3, 'g', 'e', 'x', 2, 'g', 'e', 3, 'g', 'e', 'p', 3, 'g', 'u', 't', 3, 'g', 'u', 'x', 2, 'g', 'u', 3, 'g', 'u', 'p', 4, 'g', 'u', 'r', 'x', 3, 'g', 'u', 'r', 3, 'k', 'i', 't', 3, 'k', 'i', 'x', 2, 'k', 'i', 3, 'k', 'i', 'p', 4, 'k', 'i', 'e', 'x', 3, 'k', 'i', 'e', 4, 'k', 'i', 'e', 'p', 3, 'k', 'a', 't', 3, 'k', 'a', 'x', 2, 'k', 'a', 3, 'k', 'a', 'p', 4, 'k', 'u', 'o', 'x', 3, 'k', 'u', 'o', 4, 'k', 'u', 'o', 'p', 3, 'k', 'o', 't', 3, 'k', 'o', 'x', 2, 'k', 'o', 3, 'k', 'o', 'p', 3, 'k', 'e', 't', 3, 'k', 'e', 'x', 2, 'k', 'e', 3, 'k', 'e', 'p', 3, 'k', 'u', 't', 3, 'k', 'u', 'x', 2, 'k', 'u', 3, 'k', 'u', 'p', 4, 'k', 'u', 'r', 'x', 3, 'k', 'u', 'r', 4, 'g', 'g', 'i', 't', 4, 'g', 'g', 'i', 'x', 3, 'g', 'g', 'i', 5, 'g', 'g', 'i', 'e', 'x', 4, 'g', 'g', 'i', 'e', 5, 'g', 'g', 'i', 'e', 'p', 4, 'g', 'g', 'a', 't', 4, 'g', 'g', 'a', 'x', 3, 'g', 'g', 'a', 4, 'g', 'g', 'a', 'p', 5, 'g', 'g', 'u', 'o', 't', 5, 'g', 'g', 'u', 'o', 'x', 4, 'g', 'g', 'u', 'o', 5, 'g', 'g', 'u', 'o', 'p', 4, 'g', 'g', 'o', 't', 4, 'g', 'g', 'o', 'x', 3, 'g', 'g', 'o', 4, 'g', 'g', 'o', 'p', 4, 'g', 'g', 'e', 't', 4, 'g', 'g', 'e', 'x', 3, 'g', 'g', 'e', 4, 'g', 'g', 'e', 'p', 4, 'g', 'g', 'u', 't', 4, 'g', 'g', 'u', 'x', 3, 'g', 'g', 'u', 4, 'g', 'g', 'u', 'p', 5, 'g', 'g', 'u', 'r', 'x', 4, 'g', 'g', 'u', 'r', 5, 'm', 'g', 'i', 'e', 'x', 4, 'm', 'g', 'i', 'e', 4, 'm', 'g', 'a', 't', 4, 'm', 'g', 'a', 'x', 3, 'm', 'g', 'a', 4, 'm', 'g', 'a', 'p', 5, 'm', 'g', 'u', 'o', 'x', 4, 'm', 'g', 'u', 'o', 5, 'm', 'g', 'u', 'o', 'p', 4, 'm', 'g', 'o', 't', 4, 'm', 'g', 'o', 'x', 3, 'm', 'g', 'o', 4, 'm', 'g', 'o', 'p', 4, 'm', 'g', 'e', 'x', 3, 'm', 'g', 'e', 4, 'm', 'g', 'e', 'p', 4, 'm', 'g', 'u', 't', 4, 'm', 'g', 'u', 'x', 3, 'm', 'g', 'u', 4, 'm', 'g', 'u', 'p', 5, 'm', 'g', 'u', 'r', 'x', 4, 'm', 'g', 'u', 'r', 4, 'h', 'x', 'i', 't', 4, 'h', 'x', 'i', 'x', 3, 'h', 'x', 'i', 4, 'h', 'x', 'i', 'p', 5, 'h', 'x', 'i', 'e', 't', 5, 'h', 'x', 'i', 'e', 'x', 4, 'h', 'x', 'i', 'e', 5, 'h', 'x', 'i', 'e', 'p', 4, 'h', 'x', 'a', 't', 4, 'h', 'x', 'a', 'x', 3, 'h', 'x', 'a', 4, 'h', 'x', 'a', 'p', 5, 'h', 'x', 'u', 'o', 't', 5, 'h', 'x', 'u', 'o', 'x', 4, 'h', 'x', 'u', 'o', 5, 'h', 'x', 'u', 'o', 'p', 4, 'h', 'x', 'o', 't', 4, 'h', 'x', 'o', 'x', 3, 'h', 'x', 'o', 4, 'h', 'x', 'o', 'p', 4, 'h', 'x', 'e', 'x', 3, 'h', 'x', 'e', 4, 'h', 'x', 'e', 'p', 5, 'n', 'g', 'i', 'e', 'x', 4, 'n', 'g', 'i', 'e', 5, 'n', 'g', 'i', 'e', 'p', 4, 'n', 'g', 'a', 't', 4, 'n', 'g', 'a', 'x', 3, 'n', 'g', 'a', 4, 'n', 'g', 'a', 'p', 5, 'n', 'g', 'u', 'o', 't', 5, 'n', 'g', 'u', 'o', 'x', 4, 'n', 'g', 'u', 'o', 4, 'n', 'g', 'o', 't', 4, 'n', 'g', 'o', 'x', 3, 'n', 'g', 'o', 4, 'n', 'g', 'o', 'p', 4, 'n', 'g', 'e', 'x', 3, 'n', 'g', 'e', 4, 'n', 'g', 'e', 'p', 3, 'h', 'i', 't', 4, 'h', 'i', 'e', 'x', 3, 'h', 'i', 'e', 3, 'h', 'a', 't', 3, 'h', 'a', 'x', 2, 'h', 'a', 3, 'h', 'a', 'p', 4, 'h', 'u', 'o', 't', 4, 'h', 'u', 'o', 'x', 3, 'h', 'u', 'o', 4, 'h', 'u', 'o', 'p', 3, 'h', 'o', 't', 3, 'h', 'o', 'x', 2, 'h', 'o', 3, 'h', 'o', 'p', 3, 'h', 'e', 'x', 2, 'h', 'e', 3, 'h', 'e', 'p', 3, 'w', 'a', 't', 3, 'w', 'a', 'x', 2, 'w', 'a', 3, 'w', 'a', 'p', 4, 'w', 'u', 'o', 'x', 3, 'w', 'u', 'o', 4, 'w', 'u', 'o', 'p', 3, 'w', 'o', 'x', 2, 'w', 'o', 3, 'w', 'o', 'p', 3, 'w', 'e', 'x', 2, 'w', 'e', 3, 'w', 'e', 'p', 3, 'z', 'i', 't', 3, 'z', 'i', 'x', 2, 'z', 'i', 3, 'z', 'i', 'p', 4, 'z', 'i', 'e', 'x', 3, 'z', 'i', 'e', 4, 'z', 'i', 'e', 'p', 3, 'z', 'a', 't', 3, 'z', 'a', 'x', 2, 'z', 'a', 3, 'z', 'a', 'p', 4, 'z', 'u', 'o', 'x', 3, 'z', 'u', 'o', 4, 'z', 'u', 'o', 'p', 3, 'z', 'o', 't', 3, 'z', 'o', 'x', 2, 'z', 'o', 3, 'z', 'o', 'p', 3, 'z', 'e', 'x', 2, 'z', 'e', 3, 'z', 'e', 'p', 3, 'z', 'u', 't', 3, 'z', 'u', 'x', 2, 'z', 'u', 3, 'z', 'u', 'p', 4, 'z', 'u', 'r', 'x', 3, 'z', 'u', 'r', 3, 'z', 'y', 't', 3, 'z', 'y', 'x', 2, 'z', 'y', 3, 'z', 'y', 'p', 4, 'z', 'y', 'r', 'x', 3, 'z', 'y', 'r', 3, 'c', 'i', 't', 3, 'c', 'i', 'x', 2, 'c', 'i', 3, 'c', 'i', 'p', 4, 'c', 'i', 'e', 't', 4, 'c', 'i', 'e', 'x', 3, 'c', 'i', 'e', 4, 'c', 'i', 'e', 'p', 3, 'c', 'a', 't', 3, 'c', 'a', 'x', 2, 'c', 'a', 3, 'c', 'a', 'p', 4, 'c', 'u', 'o', 'x', 3, 'c', 'u', 'o', 4, 'c', 'u', 'o', 'p', 3, 'c', 'o', 't', 3, 'c', 'o', 'x', 2, 'c', 'o', 3, 'c', 'o', 'p', 3, 'c', 'e', 'x', 2, 'c', 'e', 3, 'c', 'e', 'p', 3, 'c', 'u', 't', 3, 'c', 'u', 'x', 2, 'c', 'u', 3, 'c', 'u', 'p', 4, 'c', 'u', 'r', 'x', 3, 'c', 'u', 'r', 3, 'c', 'y', 't', 3, 'c', 'y', 'x', 2, 'c', 'y', 3, 'c', 'y', 'p', 4, 'c', 'y', 'r', 'x', 3, 'c', 'y', 'r', 4, 'z', 'z', 'i', 't', 4, 'z', 'z', 'i', 'x', 3, 'z', 'z', 'i', 4, 'z', 'z', 'i', 'p', 5, 'z', 'z', 'i', 'e', 't', 5, 'z', 'z', 'i', 'e', 'x', 4, 'z', 'z', 'i', 'e', 5, 'z', 'z', 'i', 'e', 'p', 4, 'z', 'z', 'a', 't', 4, 'z', 'z', 'a', 'x', 3, 'z', 'z', 'a', 4, 'z', 'z', 'a', 'p', 4, 'z', 'z', 'o', 'x', 3, 'z', 'z', 'o', 4, 'z', 'z', 'o', 'p', 4, 'z', 'z', 'e', 'x', 3, 'z', 'z', 'e', 4, 'z', 'z', 'e', 'p', 4, 'z', 'z', 'u', 'x', 3, 'z', 'z', 'u', 4, 'z', 'z', 'u', 'p', 5, 'z', 'z', 'u', 'r', 'x', 4, 'z', 'z', 'u', 'r', 4, 'z', 'z', 'y', 't', 4, 'z', 'z', 'y', 'x', 3, 'z', 'z', 'y', 4, 'z', 'z', 'y', 'p', 5, 'z', 'z', 'y', 'r', 'x', 4, 'z', 'z', 'y', 'r', 4, 'n', 'z', 'i', 't', 4, 'n', 'z', 'i', 'x', 3, 'n', 'z', 'i', 4, 'n', 'z', 'i', 'p', 5, 'n', 'z', 'i', 'e', 'x', 4, 'n', 'z', 'i', 'e', 5, 'n', 'z', 'i', 'e', 'p', 4, 'n', 'z', 'a', 't', 4, 'n', 'z', 'a', 'x', 3, 'n', 'z', 'a', 4, 'n', 'z', 'a', 'p', 5, 'n', 'z', 'u', 'o', 'x', 4, 'n', 'z', 'u', 'o', 4, 'n', 'z', 'o', 'x', 4, 'n', 'z', 'o', 'p', 4, 'n', 'z', 'e', 'x', 3, 'n', 'z', 'e', 4, 'n', 'z', 'u', 'x', 3, 'n', 'z', 'u', 4, 'n', 'z', 'u', 'p', 5, 'n', 'z', 'u', 'r', 'x', 4, 'n', 'z', 'u', 'r', 4, 'n', 'z', 'y', 't', 4, 'n', 'z', 'y', 'x', 3, 'n', 'z', 'y', 4, 'n', 'z', 'y', 'p', 5, 'n', 'z', 'y', 'r', 'x', 4, 'n', 'z', 'y', 'r', 3, 's', 'i', 't', 3, 's', 'i', 'x', 2, 's', 'i', 3, 's', 'i', 'p', 4, 's', 'i', 'e', 'x', 3, 's', 'i', 'e', 4, 's', 'i', 'e', 'p', 3, 's', 'a', 't', 3, 's', 'a', 'x', 2, 's', 'a', 3, 's', 'a', 'p', 4, 's', 'u', 'o', 'x', 3, 's', 'u', 'o', 4, 's', 'u', 'o', 'p', 3, 's', 'o', 't', 3, 's', 'o', 'x', 2, 's', 'o', 3, 's', 'o', 'p', 3, 's', 'e', 'x', 2, 's', 'e', 3, 's', 'e', 'p', 3, 's', 'u', 't', 3, 's', 'u', 'x', 2, 's', 'u', 3, 's', 'u', 'p', 4, 's', 'u', 'r', 'x', 3, 's', 'u', 'r', 3, 's', 'y', 't', 3, 's', 'y', 'x', 2, 's', 'y', 3, 's', 'y', 'p', 4, 's', 'y', 'r', 'x', 3, 's', 'y', 'r', 4, 's', 's', 'i', 't', 4, 's', 's', 'i', 'x', 3, 's', 's', 'i', 4, 's', 's', 'i', 'p', 5, 's', 's', 'i', 'e', 'x', 4, 's', 's', 'i', 'e', 5, 's', 's', 'i', 'e', 'p', 4, 's', 's', 'a', 't', 4, 's', 's', 'a', 'x', 3, 's', 's', 'a', 4, 's', 's', 'a', 'p', 4, 's', 's', 'o', 't', 4, 's', 's', 'o', 'x', 3, 's', 's', 'o', 4, 's', 's', 'o', 'p', 4, 's', 's', 'e', 'x', 3, 's', 's', 'e', 4, 's', 's', 'e', 'p', 4, 's', 's', 'u', 't', 4, 's', 's', 'u', 'x', 3, 's', 's', 'u', 4, 's', 's', 'u', 'p', 4, 's', 's', 'y', 't', 4, 's', 's', 'y', 'x', 3, 's', 's', 'y', 4, 's', 's', 'y', 'p', 5, 's', 's', 'y', 'r', 'x', 4, 's', 's', 'y', 'r', 4, 'z', 'h', 'a', 't', 4, 'z', 'h', 'a', 'x', 3, 'z', 'h', 'a', 4, 'z', 'h', 'a', 'p', 5, 'z', 'h', 'u', 'o', 'x', 4, 'z', 'h', 'u', 'o', 5, 'z', 'h', 'u', 'o', 'p', 4, 'z', 'h', 'o', 't', 4, 'z', 'h', 'o', 'x', 3, 'z', 'h', 'o', 4, 'z', 'h', 'o', 'p', 4, 'z', 'h', 'e', 't', 4, 'z', 'h', 'e', 'x', 3, 'z', 'h', 'e', 4, 'z', 'h', 'e', 'p', 4, 'z', 'h', 'u', 't', 4, 'z', 'h', 'u', 'x', 3, 'z', 'h', 'u', 4, 'z', 'h', 'u', 'p', 5, 'z', 'h', 'u', 'r', 'x', 4, 'z', 'h', 'u', 'r', 4, 'z', 'h', 'y', 't', 4, 'z', 'h', 'y', 'x', 3, 'z', 'h', 'y', 4, 'z', 'h', 'y', 'p', 5, 'z', 'h', 'y', 'r', 'x', 4, 'z', 'h', 'y', 'r', 4, 'c', 'h', 'a', 't', 4, 'c', 'h', 'a', 'x', 3, 'c', 'h', 'a', 4, 'c', 'h', 'a', 'p', 5, 'c', 'h', 'u', 'o', 't', 5, 'c', 'h', 'u', 'o', 'x', 4, 'c', 'h', 'u', 'o', 5, 'c', 'h', 'u', 'o', 'p', 4, 'c', 'h', 'o', 't', 4, 'c', 'h', 'o', 'x', 3, 'c', 'h', 'o', 4, 'c', 'h', 'o', 'p', 4, 'c', 'h', 'e', 't', 4, 'c', 'h', 'e', 'x', 3, 'c', 'h', 'e', 4, 'c', 'h', 'e', 'p', 4, 'c', 'h', 'u', 'x', 3, 'c', 'h', 'u', 4, 'c', 'h', 'u', 'p', 5, 'c', 'h', 'u', 'r', 'x', 4, 'c', 'h', 'u', 'r', 4, 'c', 'h', 'y', 't', 4, 'c', 'h', 'y', 'x', 3, 'c', 'h', 'y', 4, 'c', 'h', 'y', 'p', 5, 'c', 'h', 'y', 'r', 'x', 4, 'c', 'h', 'y', 'r', 4, 'r', 'r', 'a', 'x', 3, 'r', 'r', 'a', 5, 'r', 'r', 'u', 'o', 'x', 4, 'r', 'r', 'u', 'o', 4, 'r', 'r', 'o', 't', 4, 'r', 'r', 'o', 'x', 3, 'r', 'r', 'o', 4, 'r', 'r', 'o', 'p', 4, 'r', 'r', 'e', 't', 4, 'r', 'r', 'e', 'x', 3, 'r', 'r', 'e', 4, 'r', 'r', 'e', 'p', 4, 'r', 'r', 'u', 't', 4, 'r', 'r', 'u', 'x', 3, 'r', 'r', 'u', 4, 'r', 'r', 'u', 'p', 5, 'r', 'r', 'u', 'r', 'x', 4, 'r', 'r', 'u', 'r', 4, 'r', 'r', 'y', 't', 4, 'r', 'r', 'y', 'x', 3, 'r', 'r', 'y', 4, 'r', 'r', 'y', 'p', 5, 'r', 'r', 'y', 'r', 'x', 4, 'r', 'r', 'y', 'r', 4, 'n', 'r', 'a', 't', 4, 'n', 'r', 'a', 'x', 3, 'n', 'r', 'a', 4, 'n', 'r', 'a', 'p', 4, 'n', 'r', 'o', 'x', 3, 'n', 'r', 'o', 4, 'n', 'r', 'o', 'p', 4, 'n', 'r', 'e', 't', 4, 'n', 'r', 'e', 'x', 3, 'n', 'r', 'e', 4, 'n', 'r', 'e', 'p', 4, 'n', 'r', 'u', 't', 4, 'n', 'r', 'u', 'x', 3, 'n', 'r', 'u', 4, 'n', 'r', 'u', 'p', 5, 'n', 'r', 'u', 'r', 'x', 4, 'n', 'r', 'u', 'r', 4, 'n', 'r', 'y', 't', 4, 'n', 'r', 'y', 'x', 3, 'n', 'r', 'y', 4, 'n', 'r', 'y', 'p', 5, 'n', 'r', 'y', 'r', 'x', 4, 'n', 'r', 'y', 'r', 4, 's', 'h', 'a', 't', 4, 's', 'h', 'a', 'x', 3, 's', 'h', 'a', 4, 's', 'h', 'a', 'p', 5, 's', 'h', 'u', 'o', 'x', 4, 's', 'h', 'u', 'o', 5, 's', 'h', 'u', 'o', 'p', 4, 's', 'h', 'o', 't', 4, 's', 'h', 'o', 'x', 3, 's', 'h', 'o', 4, 's', 'h', 'o', 'p', 4, 's', 'h', 'e', 't', 4, 's', 'h', 'e', 'x', 3, 's', 'h', 'e', 4, 's', 'h', 'e', 'p', 4, 's', 'h', 'u', 't', 4, 's', 'h', 'u', 'x', 3, 's', 'h', 'u', 4, 's', 'h', 'u', 'p', 5, 's', 'h', 'u', 'r', 'x', 4, 's', 'h', 'u', 'r', 4, 's', 'h', 'y', 't', 4, 's', 'h', 'y', 'x', 3, 's', 'h', 'y', 4, 's', 'h', 'y', 'p', 5, 's', 'h', 'y', 'r', 'x', 4, 's', 'h', 'y', 'r', 3, 'r', 'a', 't', 3, 'r', 'a', 'x', 2, 'r', 'a', 3, 'r', 'a', 'p', 4, 'r', 'u', 'o', 'x', 3, 'r', 'u', 'o', 4, 'r', 'u', 'o', 'p', 3, 'r', 'o', 't', 3, 'r', 'o', 'x', 2, 'r', 'o', 3, 'r', 'o', 'p', 3, 'r', 'e', 'x', 2, 'r', 'e', 3, 'r', 'e', 'p', 3, 'r', 'u', 't', 3, 'r', 'u', 'x', 2, 'r', 'u', 3, 'r', 'u', 'p', 4, 'r', 'u', 'r', 'x', 3, 'r', 'u', 'r', 3, 'r', 'y', 't', 3, 'r', 'y', 'x', 2, 'r', 'y', 3, 'r', 'y', 'p', 4, 'r', 'y', 'r', 'x', 3, 'r', 'y', 'r', 3, 'j', 'i', 't', 3, 'j', 'i', 'x', 2, 'j', 'i', 3, 'j', 'i', 'p', 4, 'j', 'i', 'e', 't', 4, 'j', 'i', 'e', 'x', 3, 'j', 'i', 'e', 4, 'j', 'i', 'e', 'p', 4, 'j', 'u', 'o', 't', 4, 'j', 'u', 'o', 'x', 3, 'j', 'u', 'o', 4, 'j', 'u', 'o', 'p', 3, 'j', 'o', 't', 3, 'j', 'o', 'x', 2, 'j', 'o', 3, 'j', 'o', 'p', 3, 'j', 'u', 't', 3, 'j', 'u', 'x', 2, 'j', 'u', 3, 'j', 'u', 'p', 4, 'j', 'u', 'r', 'x', 3, 'j', 'u', 'r', 3, 'j', 'y', 't', 3, 'j', 'y', 'x', 2, 'j', 'y', 3, 'j', 'y', 'p', 4, 'j', 'y', 'r', 'x', 3, 'j', 'y', 'r', 3, 'q', 'i', 't', 3, 'q', 'i', 'x', 2, 'q', 'i', 3, 'q', 'i', 'p', 4, 'q', 'i', 'e', 't', 4, 'q', 'i', 'e', 'x', 3, 'q', 'i', 'e', 4, 'q', 'i', 'e', 'p', 4, 'q', 'u', 'o', 't', 4, 'q', 'u', 'o', 'x', 3, 'q', 'u', 'o', 4, 'q', 'u', 'o', 'p', 3, 'q', 'o', 't', 3, 'q', 'o', 'x', 2, 'q', 'o', 3, 'q', 'o', 'p', 3, 'q', 'u', 't', 3, 'q', 'u', 'x', 2, 'q', 'u', 3, 'q', 'u', 'p', 4, 'q', 'u', 'r', 'x', 3, 'q', 'u', 'r', 3, 'q', 'y', 't', 3, 'q', 'y', 'x', 2, 'q', 'y', 3, 'q', 'y', 'p', 4, 'q', 'y', 'r', 'x', 3, 'q', 'y', 'r', 4, 'j', 'j', 'i', 't', 4, 'j', 'j', 'i', 'x', 3, 'j', 'j', 'i', 4, 'j', 'j', 'i', 'p', 5, 'j', 'j', 'i', 'e', 't', 5, 'j', 'j', 'i', 'e', 'x', 4, 'j', 'j', 'i', 'e', 5, 'j', 'j', 'i', 'e', 'p', 5, 'j', 'j', 'u', 'o', 'x', 4, 'j', 'j', 'u', 'o', 5, 'j', 'j', 'u', 'o', 'p', 4, 'j', 'j', 'o', 't', 4, 'j', 'j', 'o', 'x', 3, 'j', 'j', 'o', 4, 'j', 'j', 'o', 'p', 4, 'j', 'j', 'u', 't', 4, 'j', 'j', 'u', 'x', 3, 'j', 'j', 'u', 4, 'j', 'j', 'u', 'p', 5, 'j', 'j', 'u', 'r', 'x', 4, 'j', 'j', 'u', 'r', 4, 'j', 'j', 'y', 't', 4, 'j', 'j', 'y', 'x', 3, 'j', 'j', 'y', 4, 'j', 'j', 'y', 'p', 4, 'n', 'j', 'i', 't', 4, 'n', 'j', 'i', 'x', 3, 'n', 'j', 'i', 4, 'n', 'j', 'i', 'p', 5, 'n', 'j', 'i', 'e', 't', 5, 'n', 'j', 'i', 'e', 'x', 4, 'n', 'j', 'i', 'e', 5, 'n', 'j', 'i', 'e', 'p', 5, 'n', 'j', 'u', 'o', 'x', 4, 'n', 'j', 'u', 'o', 4, 'n', 'j', 'o', 't', 4, 'n', 'j', 'o', 'x', 3, 'n', 'j', 'o', 4, 'n', 'j', 'o', 'p', 4, 'n', 'j', 'u', 'x', 3, 'n', 'j', 'u', 4, 'n', 'j', 'u', 'p', 5, 'n', 'j', 'u', 'r', 'x', 4, 'n', 'j', 'u', 'r', 4, 'n', 'j', 'y', 't', 4, 'n', 'j', 'y', 'x', 3, 'n', 'j', 'y', 4, 'n', 'j', 'y', 'p', 5, 'n', 'j', 'y', 'r', 'x', 4, 'n', 'j', 'y', 'r', 4, 'n', 'y', 'i', 't', 4, 'n', 'y', 'i', 'x', 3, 'n', 'y', 'i', 4, 'n', 'y', 'i', 'p', 5, 'n', 'y', 'i', 'e', 't', 5, 'n', 'y', 'i', 'e', 'x', 4, 'n', 'y', 'i', 'e', 5, 'n', 'y', 'i', 'e', 'p', 5, 'n', 'y', 'u', 'o', 'x', 4, 'n', 'y', 'u', 'o', 5, 'n', 'y', 'u', 'o', 'p', 4, 'n', 'y', 'o', 't', 4, 'n', 'y', 'o', 'x', 3, 'n', 'y', 'o', 4, 'n', 'y', 'o', 'p', 4, 'n', 'y', 'u', 't', 4, 'n', 'y', 'u', 'x', 3, 'n', 'y', 'u', 4, 'n', 'y', 'u', 'p', 3, 'x', 'i', 't', 3, 'x', 'i', 'x', 2, 'x', 'i', 3, 'x', 'i', 'p', 4, 'x', 'i', 'e', 't', 4, 'x', 'i', 'e', 'x', 3, 'x', 'i', 'e', 4, 'x', 'i', 'e', 'p', 4, 'x', 'u', 'o', 'x', 3, 'x', 'u', 'o', 3, 'x', 'o', 't', 3, 'x', 'o', 'x', 2, 'x', 'o', 3, 'x', 'o', 'p', 3, 'x', 'y', 't', 3, 'x', 'y', 'x', 2, 'x', 'y', 3, 'x', 'y', 'p', 4, 'x', 'y', 'r', 'x', 3, 'x', 'y', 'r', 3, 'y', 'i', 't', 3, 'y', 'i', 'x', 2, 'y', 'i', 3, 'y', 'i', 'p', 4, 'y', 'i', 'e', 't', 4, 'y', 'i', 'e', 'x', 3, 'y', 'i', 'e', 4, 'y', 'i', 'e', 'p', 4, 'y', 'u', 'o', 't', 4, 'y', 'u', 'o', 'x', 3, 'y', 'u', 'o', 4, 'y', 'u', 'o', 'p', 3, 'y', 'o', 't', 3, 'y', 'o', 'x', 2, 'y', 'o', 3, 'y', 'o', 'p', 3, 'y', 'u', 't', 3, 'y', 'u', 'x', 2, 'y', 'u', 3, 'y', 'u', 'p', 4, 'y', 'u', 'r', 'x', 3, 'y', 'u', 'r', 3, 'y', 'y', 't', 3, 'y', 'y', 'x', 2, 'y', 'y', 3, 'y', 'y', 'p', 4, 'y', 'y', 'r', 'x', 3, 'y', 'y', 'r', 3, 'Q', 'o', 't', 2, 'L', 'i', 3, 'K', 'i', 't', 4, 'N', 'y', 'i', 'p', 3, 'C', 'y', 'p', 3, 'S', 's', 'i', 4, 'G', 'g', 'o', 'p', 3, 'G', 'e', 'p', 2, 'M', 'i', 4, 'H', 'x', 'i', 't', 3, 'L', 'y', 'r', 4, 'B', 'b', 'u', 't', 3, 'M', 'o', 'p', 2, 'Y', 'o', 3, 'P', 'u', 't', 4, 'H', 'x', 'u', 'o', 3, 'T', 'a', 't', 2, 'G', 'a', 4, 'D', 'd', 'u', 'r', 3, 'B', 'u', 'r', 4, 'G', 'g', 'u', 'o', 4, 'N', 'y', 'o', 'p', 2, 'T', 'u', 2, 'O', 'p', 4, 'J', 'j', 'u', 't', 3, 'Z', 'o', 't', 3, 'P', 'y', 't', 3, 'H', 'm', 'o', 3, 'Y', 'i', 't', 3, 'V', 'u', 'r', 3, 'S', 'h', 'y', 3, 'V', 'e', 'p', 2, 'Z', 'a', 2, 'J', 'o', 3, 'J', 'j', 'y', 3, 'G', 'o', 't', 4, 'J', 'j', 'i', 'e', 2, 'W', 'o', 2, 'D', 'u', 4, 'S', 'h', 'u', 'r', 3, 'L', 'i', 'e', 2, 'C', 'y', 4, 'C', 'u', 'o', 'p', 3, 'C', 'i', 'p', 4, 'H', 'x', 'o', 'p', 4, 'S', 'h', 'a', 't', 4, 'S', 'h', 'o', 'p', 3, 'C', 'h', 'e', 5, 'Z', 'z', 'i', 'e', 't', 2, 'K', 'e', 2, 'g', 'a', 3, 'g', 'a', 'g', 4, 'g', 'a', 'g', 'g', 4, 'g', 'a', 'g', 's', 3, 'g', 'a', 'n', 4, 'g', 'a', 'n', 'j', 4, 'g', 'a', 'n', 'h', 3, 'g', 'a', 'd', 3, 'g', 'a', 'l', 4, 'g', 'a', 'l', 'g', 4, 'g', 'a', 'l', 'm', 4, 'g', 'a', 'l', 'b', 4, 'g', 'a', 'l', 's', 4, 'g', 'a', 'l', 't', 4, 'g', 'a', 'l', 'p', 4, 'g', 'a', 'l', 'h', 3, 'g', 'a', 'm', 3, 'g', 'a', 'b', 4, 'g', 'a', 'b', 's', 3, 'g', 'a', 's', 4, 'g', 'a', 's', 's', 4, 'g', 'a', 'n', 'g', 3, 'g', 'a', 'j', 3, 'g', 'a', 'c', 3, 'g', 'a', 'k', 3, 'g', 'a', 't', 3, 'g', 'a', 'p', 3, 'g', 'a', 'h', 3, 'g', 'a', 'e', 4, 'g', 'a', 'e', 'g', 5, 'g', 'a', 'e', 'g', 'g', 5, 'g', 'a', 'e', 'g', 's', 4, 'g', 'a', 'e', 'n', 5, 'g', 'a', 'e', 'n', 'j', 5, 'g', 'a', 'e', 'n', 'h', 4, 'g', 'a', 'e', 'd', 4, 'g', 'a', 'e', 'l', 5, 'g', 'a', 'e', 'l', 'g', 5, 'g', 'a', 'e', 'l', 'm', 5, 'g', 'a', 'e', 'l', 'b', 5, 'g', 'a', 'e', 'l', 's', 5, 'g', 'a', 'e', 'l', 't', 5, 'g', 'a', 'e', 'l', 'p', 5, 'g', 'a', 'e', 'l', 'h', 4, 'g', 'a', 'e', 'm', 4, 'g', 'a', 'e', 'b', 5, 'g', 'a', 'e', 'b', 's', 4, 'g', 'a', 'e', 's', 5, 'g', 'a', 'e', 's', 's', 5, 'g', 'a', 'e', 'n', 'g', 4, 'g', 'a', 'e', 'j', 4, 'g', 'a', 'e', 'c', 4, 'g', 'a', 'e', 'k', 4, 'g', 'a', 'e', 't', 4, 'g', 'a', 'e', 'p', 4, 'g', 'a', 'e', 'h', 3, 'g', 'y', 'a', 4, 'g', 'y', 'a', 'g', 5, 'g', 'y', 'a', 'g', 'g', 5, 'g', 'y', 'a', 'g', 's', 4, 'g', 'y', 'a', 'n', 5, 'g', 'y', 'a', 'n', 'j', 5, 'g', 'y', 'a', 'n', 'h', 4, 'g', 'y', 'a', 'd', 4, 'g', 'y', 'a', 'l', 5, 'g', 'y', 'a', 'l', 'g', 5, 'g', 'y', 'a', 'l', 'm', 5, 'g', 'y', 'a', 'l', 'b', 5, 'g', 'y', 'a', 'l', 's', 5, 'g', 'y', 'a', 'l', 't', 5, 'g', 'y', 'a', 'l', 'p', 5, 'g', 'y', 'a', 'l', 'h', 4, 'g', 'y', 'a', 'm', 4, 'g', 'y', 'a', 'b', 5, 'g', 'y', 'a', 'b', 's', 4, 'g', 'y', 'a', 's', 5, 'g', 'y', 'a', 's', 's', 5, 'g', 'y', 'a', 'n', 'g', 4, 'g', 'y', 'a', 'j', 4, 'g', 'y', 'a', 'c', 4, 'g', 'y', 'a', 'k', 4, 'g', 'y', 'a', 't', 4, 'g', 'y', 'a', 'p', 4, 'g', 'y', 'a', 'h', 4, 'g', 'y', 'a', 'e', 5, 'g', 'y', 'a', 'e', 'g', 6, 'g', 'y', 'a', 'e', 'g', 'g', 6, 'g', 'y', 'a', 'e', 'g', 's', 5, 'g', 'y', 'a', 'e', 'n', 6, 'g', 'y', 'a', 'e', 'n', 'j', 6, 'g', 'y', 'a', 'e', 'n', 'h', 5, 'g', 'y', 'a', 'e', 'd', 5, 'g', 'y', 'a', 'e', 'l', 6, 'g', 'y', 'a', 'e', 'l', 'g', 6, 'g', 'y', 'a', 'e', 'l', 'm', 6, 'g', 'y', 'a', 'e', 'l', 'b', 6, 'g', 'y', 'a', 'e', 'l', 's', 6, 'g', 'y', 'a', 'e', 'l', 't', 6, 'g', 'y', 'a', 'e', 'l', 'p', 6, 'g', 'y', 'a', 'e', 'l', 'h', 5, 'g', 'y', 'a', 'e', 'm', 5, 'g', 'y', 'a', 'e', 'b', 6, 'g', 'y', 'a', 'e', 'b', 's', 5, 'g', 'y', 'a', 'e', 's', 6, 'g', 'y', 'a', 'e', 's', 's', 6, 'g', 'y', 'a', 'e', 'n', 'g', 5, 'g', 'y', 'a', 'e', 'j', 5, 'g', 'y', 'a', 'e', 'c', 5, 'g', 'y', 'a', 'e', 'k', 5, 'g', 'y', 'a', 'e', 't', 5, 'g', 'y', 'a', 'e', 'p', 5, 'g', 'y', 'a', 'e', 'h', 3, 'g', 'e', 'o', 4, 'g', 'e', 'o', 'g', 5, 'g', 'e', 'o', 'g', 'g', 5, 'g', 'e', 'o', 'g', 's', 4, 'g', 'e', 'o', 'n', 5, 'g', 'e', 'o', 'n', 'j', 5, 'g', 'e', 'o', 'n', 'h', 4, 'g', 'e', 'o', 'd', 4, 'g', 'e', 'o', 'l', 5, 'g', 'e', 'o', 'l', 'g', 5, 'g', 'e', 'o', 'l', 'm', 5, 'g', 'e', 'o', 'l', 'b', 5, 'g', 'e', 'o', 'l', 's', 5, 'g', 'e', 'o', 'l', 't', 5, 'g', 'e', 'o', 'l', 'p', 5, 'g', 'e', 'o', 'l', 'h', 4, 'g', 'e', 'o', 'm', 4, 'g', 'e', 'o', 'b', 5, 'g', 'e', 'o', 'b', 's', 4, 'g', 'e', 'o', 's', 5, 'g', 'e', 'o', 's', 's', 5, 'g', 'e', 'o', 'n', 'g', 4, 'g', 'e', 'o', 'j', 4, 'g', 'e', 'o', 'c', 4, 'g', 'e', 'o', 'k', 4, 'g', 'e', 'o', 't', 4, 'g', 'e', 'o', 'p', 4, 'g', 'e', 'o', 'h', 2, 'g', 'e', 3, 'g', 'e', 'g', 4, 'g', 'e', 'g', 'g', 4, 'g', 'e', 'g', 's', 3, 'g', 'e', 'n', 4, 'g', 'e', 'n', 'j', 4, 'g', 'e', 'n', 'h', 3, 'g', 'e', 'd', 3, 'g', 'e', 'l', 4, 'g', 'e', 'l', 'g', 4, 'g', 'e', 'l', 'm', 4, 'g', 'e', 'l', 'b', 4, 'g', 'e', 'l', 's', 4, 'g', 'e', 'l', 't', 4, 'g', 'e', 'l', 'p', 4, 'g', 'e', 'l', 'h', 3, 'g', 'e', 'm', 3, 'g', 'e', 'b', 4, 'g', 'e', 'b', 's', 3, 'g', 'e', 's', 4, 'g', 'e', 's', 's', 4, 'g', 'e', 'n', 'g', 3, 'g', 'e', 'j', 3, 'g', 'e', 'c', 3, 'g', 'e', 'k', 3, 'g', 'e', 't', 3, 'g', 'e', 'p', 3, 'g', 'e', 'h', 4, 'g', 'y', 'e', 'o', 5, 'g', 'y', 'e', 'o', 'g', 6, 'g', 'y', 'e', 'o', 'g', 'g', 6, 'g', 'y', 'e', 'o', 'g', 's', 5, 'g', 'y', 'e', 'o', 'n', 6, 'g', 'y', 'e', 'o', 'n', 'j', 6, 'g', 'y', 'e', 'o', 'n', 'h', 5, 'g', 'y', 'e', 'o', 'd', 5, 'g', 'y', 'e', 'o', 'l', 6, 'g', 'y', 'e', 'o', 'l', 'g', 6, 'g', 'y', 'e', 'o', 'l', 'm', 6, 'g', 'y', 'e', 'o', 'l', 'b', 6, 'g', 'y', 'e', 'o', 'l', 's', 6, 'g', 'y', 'e', 'o', 'l', 't', 6, 'g', 'y', 'e', 'o', 'l', 'p', 6, 'g', 'y', 'e', 'o', 'l', 'h', 5, 'g', 'y', 'e', 'o', 'm', 5, 'g', 'y', 'e', 'o', 'b', 6, 'g', 'y', 'e', 'o', 'b', 's', 5, 'g', 'y', 'e', 'o', 's', 6, 'g', 'y', 'e', 'o', 's', 's', 6, 'g', 'y', 'e', 'o', 'n', 'g', 5, 'g', 'y', 'e', 'o', 'j', 5, 'g', 'y', 'e', 'o', 'c', 5, 'g', 'y', 'e', 'o', 'k', 5, 'g', 'y', 'e', 'o', 't', 5, 'g', 'y', 'e', 'o', 'p', 5, 'g', 'y', 'e', 'o', 'h', 3, 'g', 'y', 'e', 4, 'g', 'y', 'e', 'g', 5, 'g', 'y', 'e', 'g', 'g', 5, 'g', 'y', 'e', 'g', 's', 4, 'g', 'y', 'e', 'n', 5, 'g', 'y', 'e', 'n', 'j', 5, 'g', 'y', 'e', 'n', 'h', 4, 'g', 'y', 'e', 'd', 4, 'g', 'y', 'e', 'l', 5, 'g', 'y', 'e', 'l', 'g', 5, 'g', 'y', 'e', 'l', 'm', 5, 'g', 'y', 'e', 'l', 'b', 5, 'g', 'y', 'e', 'l', 's', 5, 'g', 'y', 'e', 'l', 't', 5, 'g', 'y', 'e', 'l', 'p', 5, 'g', 'y', 'e', 'l', 'h', 4, 'g', 'y', 'e', 'm', 4, 'g', 'y', 'e', 'b', 5, 'g', 'y', 'e', 'b', 's', 4, 'g', 'y', 'e', 's', 5, 'g', 'y', 'e', 's', 's', 5, 'g', 'y', 'e', 'n', 'g', 4, 'g', 'y', 'e', 'j', 4, 'g', 'y', 'e', 'c', 4, 'g', 'y', 'e', 'k', 4, 'g', 'y', 'e', 't', 4, 'g', 'y', 'e', 'p', 4, 'g', 'y', 'e', 'h', 2, 'g', 'o', 3, 'g', 'o', 'g', 4, 'g', 'o', 'g', 'g', 4, 'g', 'o', 'g', 's', 3, 'g', 'o', 'n', 4, 'g', 'o', 'n', 'j', 4, 'g', 'o', 'n', 'h', 3, 'g', 'o', 'd', 3, 'g', 'o', 'l', 4, 'g', 'o', 'l', 'g', 4, 'g', 'o', 'l', 'm', 4, 'g', 'o', 'l', 'b', 4, 'g', 'o', 'l', 's', 4, 'g', 'o', 'l', 't', 4, 'g', 'o', 'l', 'p', 4, 'g', 'o', 'l', 'h', 3, 'g', 'o', 'm', 3, 'g', 'o', 'b', 4, 'g', 'o', 'b', 's', 3, 'g', 'o', 's', 4, 'g', 'o', 's', 's', 4, 'g', 'o', 'n', 'g', 3, 'g', 'o', 'j', 3, 'g', 'o', 'c', 3, 'g', 'o', 'k', 3, 'g', 'o', 't', 3, 'g', 'o', 'p', 3, 'g', 'o', 'h', 3, 'g', 'w', 'a', 4, 'g', 'w', 'a', 'g', 5, 'g', 'w', 'a', 'g', 'g', 5, 'g', 'w', 'a', 'g', 's', 4, 'g', 'w', 'a', 'n', 5, 'g', 'w', 'a', 'n', 'j', 5, 'g', 'w', 'a', 'n', 'h', 4, 'g', 'w', 'a', 'd', 4, 'g', 'w', 'a', 'l', 5, 'g', 'w', 'a', 'l', 'g', 5, 'g', 'w', 'a', 'l', 'm', 5, 'g', 'w', 'a', 'l', 'b', 5, 'g', 'w', 'a', 'l', 's', 5, 'g', 'w', 'a', 'l', 't', 5, 'g', 'w', 'a', 'l', 'p', 5, 'g', 'w', 'a', 'l', 'h', 4, 'g', 'w', 'a', 'm', 4, 'g', 'w', 'a', 'b', 5, 'g', 'w', 'a', 'b', 's', 4, 'g', 'w', 'a', 's', 5, 'g', 'w', 'a', 's', 's', 5, 'g', 'w', 'a', 'n', 'g', 4, 'g', 'w', 'a', 'j', 4, 'g', 'w', 'a', 'c', 4, 'g', 'w', 'a', 'k', 4, 'g', 'w', 'a', 't', 4, 'g', 'w', 'a', 'p', 4, 'g', 'w', 'a', 'h', 4, 'g', 'w', 'a', 'e', 5, 'g', 'w', 'a', 'e', 'g', 6, 'g', 'w', 'a', 'e', 'g', 'g', 6, 'g', 'w', 'a', 'e', 'g', 's', 5, 'g', 'w', 'a', 'e', 'n', 6, 'g', 'w', 'a', 'e', 'n', 'j', 6, 'g', 'w', 'a', 'e', 'n', 'h', 5, 'g', 'w', 'a', 'e', 'd', 5, 'g', 'w', 'a', 'e', 'l', 6, 'g', 'w', 'a', 'e', 'l', 'g', 6, 'g', 'w', 'a', 'e', 'l', 'm', 6, 'g', 'w', 'a', 'e', 'l', 'b', 6, 'g', 'w', 'a', 'e', 'l', 's', 6, 'g', 'w', 'a', 'e', 'l', 't', 6, 'g', 'w', 'a', 'e', 'l', 'p', 6, 'g', 'w', 'a', 'e', 'l', 'h', 5, 'g', 'w', 'a', 'e', 'm', 5, 'g', 'w', 'a', 'e', 'b', 6, 'g', 'w', 'a', 'e', 'b', 's', 5, 'g', 'w', 'a', 'e', 's', 6, 'g', 'w', 'a', 'e', 's', 's', 6, 'g', 'w', 'a', 'e', 'n', 'g', 5, 'g', 'w', 'a', 'e', 'j', 5, 'g', 'w', 'a', 'e', 'c', 5, 'g', 'w', 'a', 'e', 'k', 5, 'g', 'w', 'a', 'e', 't', 5, 'g', 'w', 'a', 'e', 'p', 5, 'g', 'w', 'a', 'e', 'h', 3, 'g', 'o', 'e', 4, 'g', 'o', 'e', 'g', 5, 'g', 'o', 'e', 'g', 'g', 5, 'g', 'o', 'e', 'g', 's', 4, 'g', 'o', 'e', 'n', 5, 'g', 'o', 'e', 'n', 'j', 5, 'g', 'o', 'e', 'n', 'h', 4, 'g', 'o', 'e', 'd', 4, 'g', 'o', 'e', 'l', 5, 'g', 'o', 'e', 'l', 'g', 5, 'g', 'o', 'e', 'l', 'm', 5, 'g', 'o', 'e', 'l', 'b', 5, 'g', 'o', 'e', 'l', 's', 5, 'g', 'o', 'e', 'l', 't', 5, 'g', 'o', 'e', 'l', 'p', 5, 'g', 'o', 'e', 'l', 'h', 4, 'g', 'o', 'e', 'm', 4, 'g', 'o', 'e', 'b', 5, 'g', 'o', 'e', 'b', 's', 4, 'g', 'o', 'e', 's', 5, 'g', 'o', 'e', 's', 's', 5, 'g', 'o', 'e', 'n', 'g', 4, 'g', 'o', 'e', 'j', 4, 'g', 'o', 'e', 'c', 4, 'g', 'o', 'e', 'k', 4, 'g', 'o', 'e', 't', 4, 'g', 'o', 'e', 'p', 4, 'g', 'o', 'e', 'h', 3, 'g', 'y', 'o', 4, 'g', 'y', 'o', 'g', 5, 'g', 'y', 'o', 'g', 'g', 5, 'g', 'y', 'o', 'g', 's', 4, 'g', 'y', 'o', 'n', 5, 'g', 'y', 'o', 'n', 'j', 5, 'g', 'y', 'o', 'n', 'h', 4, 'g', 'y', 'o', 'd', 4, 'g', 'y', 'o', 'l', 5, 'g', 'y', 'o', 'l', 'g', 5, 'g', 'y', 'o', 'l', 'm', 5, 'g', 'y', 'o', 'l', 'b', 5, 'g', 'y', 'o', 'l', 's', 5, 'g', 'y', 'o', 'l', 't', 5, 'g', 'y', 'o', 'l', 'p', 5, 'g', 'y', 'o', 'l', 'h', 4, 'g', 'y', 'o', 'm', 4, 'g', 'y', 'o', 'b', 5, 'g', 'y', 'o', 'b', 's', 4, 'g', 'y', 'o', 's', 5, 'g', 'y', 'o', 's', 's', 5, 'g', 'y', 'o', 'n', 'g', 4, 'g', 'y', 'o', 'j', 4, 'g', 'y', 'o', 'c', 4, 'g', 'y', 'o', 'k', 4, 'g', 'y', 'o', 't', 4, 'g', 'y', 'o', 'p', 4, 'g', 'y', 'o', 'h', 2, 'g', 'u', 3, 'g', 'u', 'g', 4, 'g', 'u', 'g', 'g', 4, 'g', 'u', 'g', 's', 3, 'g', 'u', 'n', 4, 'g', 'u', 'n', 'j', 4, 'g', 'u', 'n', 'h', 3, 'g', 'u', 'd', 3, 'g', 'u', 'l', 4, 'g', 'u', 'l', 'g', 4, 'g', 'u', 'l', 'm', 4, 'g', 'u', 'l', 'b', 4, 'g', 'u', 'l', 's', 4, 'g', 'u', 'l', 't', 4, 'g', 'u', 'l', 'p', 4, 'g', 'u', 'l', 'h', 3, 'g', 'u', 'm', 3, 'g', 'u', 'b', 4, 'g', 'u', 'b', 's', 3, 'g', 'u', 's', 4, 'g', 'u', 's', 's', 4, 'g', 'u', 'n', 'g', 3, 'g', 'u', 'j', 3, 'g', 'u', 'c', 3, 'g', 'u', 'k', 3, 'g', 'u', 't', 3, 'g', 'u', 'p', 3, 'g', 'u', 'h', 4, 'g', 'w', 'e', 'o', 5, 'g', 'w', 'e', 'o', 'g', 6, 'g', 'w', 'e', 'o', 'g', 'g', 6, 'g', 'w', 'e', 'o', 'g', 's', 5, 'g', 'w', 'e', 'o', 'n', 6, 'g', 'w', 'e', 'o', 'n', 'j', 6, 'g', 'w', 'e', 'o', 'n', 'h', 5, 'g', 'w', 'e', 'o', 'd', 5, 'g', 'w', 'e', 'o', 'l', 6, 'g', 'w', 'e', 'o', 'l', 'g', 6, 'g', 'w', 'e', 'o', 'l', 'm', 6, 'g', 'w', 'e', 'o', 'l', 'b', 6, 'g', 'w', 'e', 'o', 'l', 's', 6, 'g', 'w', 'e', 'o', 'l', 't', 6, 'g', 'w', 'e', 'o', 'l', 'p', 6, 'g', 'w', 'e', 'o', 'l', 'h', 5, 'g', 'w', 'e', 'o', 'm', 5, 'g', 'w', 'e', 'o', 'b', 6, 'g', 'w', 'e', 'o', 'b', 's', 5, 'g', 'w', 'e', 'o', 's', 6, 'g', 'w', 'e', 'o', 's', 's', 6, 'g', 'w', 'e', 'o', 'n', 'g', 5, 'g', 'w', 'e', 'o', 'j', 5, 'g', 'w', 'e', 'o', 'c', 5, 'g', 'w', 'e', 'o', 'k', 5, 'g', 'w', 'e', 'o', 't', 5, 'g', 'w', 'e', 'o', 'p', 5, 'g', 'w', 'e', 'o', 'h', 3, 'g', 'w', 'e', 4, 'g', 'w', 'e', 'g', 5, 'g', 'w', 'e', 'g', 'g', 5, 'g', 'w', 'e', 'g', 's', 4, 'g', 'w', 'e', 'n', 5, 'g', 'w', 'e', 'n', 'j', 5, 'g', 'w', 'e', 'n', 'h', 4, 'g', 'w', 'e', 'd', 4, 'g', 'w', 'e', 'l', 5, 'g', 'w', 'e', 'l', 'g', 5, 'g', 'w', 'e', 'l', 'm', 5, 'g', 'w', 'e', 'l', 'b', 5, 'g', 'w', 'e', 'l', 's', 5, 'g', 'w', 'e', 'l', 't', 5, 'g', 'w', 'e', 'l', 'p', 5, 'g', 'w', 'e', 'l', 'h', 4, 'g', 'w', 'e', 'm', 4, 'g', 'w', 'e', 'b', 5, 'g', 'w', 'e', 'b', 's', 4, 'g', 'w', 'e', 's', 5, 'g', 'w', 'e', 's', 's', 5, 'g', 'w', 'e', 'n', 'g', 4, 'g', 'w', 'e', 'j', 4, 'g', 'w', 'e', 'c', 4, 'g', 'w', 'e', 'k', 4, 'g', 'w', 'e', 't', 4, 'g', 'w', 'e', 'p', 4, 'g', 'w', 'e', 'h', 3, 'g', 'w', 'i', 4, 'g', 'w', 'i', 'g', 5, 'g', 'w', 'i', 'g', 'g', 5, 'g', 'w', 'i', 'g', 's', 4, 'g', 'w', 'i', 'n', 5, 'g', 'w', 'i', 'n', 'j', 5, 'g', 'w', 'i', 'n', 'h', 4, 'g', 'w', 'i', 'd', 4, 'g', 'w', 'i', 'l', 5, 'g', 'w', 'i', 'l', 'g', 5, 'g', 'w', 'i', 'l', 'm', 5, 'g', 'w', 'i', 'l', 'b', 5, 'g', 'w', 'i', 'l', 's', 5, 'g', 'w', 'i', 'l', 't', 5, 'g', 'w', 'i', 'l', 'p', 5, 'g', 'w', 'i', 'l', 'h', 4, 'g', 'w', 'i', 'm', 4, 'g', 'w', 'i', 'b', 5, 'g', 'w', 'i', 'b', 's', 4, 'g', 'w', 'i', 's', 5, 'g', 'w', 'i', 's', 's', 5, 'g', 'w', 'i', 'n', 'g', 4, 'g', 'w', 'i', 'j', 4, 'g', 'w', 'i', 'c', 4, 'g', 'w', 'i', 'k', 4, 'g', 'w', 'i', 't', 4, 'g', 'w', 'i', 'p', 4, 'g', 'w', 'i', 'h', 3, 'g', 'y', 'u', 4, 'g', 'y', 'u', 'g', 5, 'g', 'y', 'u', 'g', 'g', 5, 'g', 'y', 'u', 'g', 's', 4, 'g', 'y', 'u', 'n', 5, 'g', 'y', 'u', 'n', 'j', 5, 'g', 'y', 'u', 'n', 'h', 4, 'g', 'y', 'u', 'd', 4, 'g', 'y', 'u', 'l', 5, 'g', 'y', 'u', 'l', 'g', 5, 'g', 'y', 'u', 'l', 'm', 5, 'g', 'y', 'u', 'l', 'b', 5, 'g', 'y', 'u', 'l', 's', 5, 'g', 'y', 'u', 'l', 't', 5, 'g', 'y', 'u', 'l', 'p', 5, 'g', 'y', 'u', 'l', 'h', 4, 'g', 'y', 'u', 'm', 4, 'g', 'y', 'u', 'b', 5, 'g', 'y', 'u', 'b', 's', 4, 'g', 'y', 'u', 's', 5, 'g', 'y', 'u', 's', 's', 5, 'g', 'y', 'u', 'n', 'g', 4, 'g', 'y', 'u', 'j', 4, 'g', 'y', 'u', 'c', 4, 'g', 'y', 'u', 'k', 4, 'g', 'y', 'u', 't', 4, 'g', 'y', 'u', 'p', 4, 'g', 'y', 'u', 'h', 3, 'g', 'e', 'u', 4, 'g', 'e', 'u', 'g', 5, 'g', 'e', 'u', 'g', 'g', 5, 'g', 'e', 'u', 'g', 's', 4, 'g', 'e', 'u', 'n', 5, 'g', 'e', 'u', 'n', 'j', 5, 'g', 'e', 'u', 'n', 'h', 4, 'g', 'e', 'u', 'd', 4, 'g', 'e', 'u', 'l', 5, 'g', 'e', 'u', 'l', 'g', 5, 'g', 'e', 'u', 'l', 'm', 5, 'g', 'e', 'u', 'l', 'b', 5, 'g', 'e', 'u', 'l', 's', 5, 'g', 'e', 'u', 'l', 't', 5, 'g', 'e', 'u', 'l', 'p', 5, 'g', 'e', 'u', 'l', 'h', 4, 'g', 'e', 'u', 'm', 4, 'g', 'e', 'u', 'b', 5, 'g', 'e', 'u', 'b', 's', 4, 'g', 'e', 'u', 's', 5, 'g', 'e', 'u', 's', 's', 5, 'g', 'e', 'u', 'n', 'g', 4, 'g', 'e', 'u', 'j', 4, 'g', 'e', 'u', 'c', 4, 'g', 'e', 'u', 'k', 4, 'g', 'e', 'u', 't', 4, 'g', 'e', 'u', 'p', 4, 'g', 'e', 'u', 'h', 3, 'g', 'y', 'i', 4, 'g', 'y', 'i', 'g', 5, 'g', 'y', 'i', 'g', 'g', 5, 'g', 'y', 'i', 'g', 's', 4, 'g', 'y', 'i', 'n', 5, 'g', 'y', 'i', 'n', 'j', 5, 'g', 'y', 'i', 'n', 'h', 4, 'g', 'y', 'i', 'd', 4, 'g', 'y', 'i', 'l', 5, 'g', 'y', 'i', 'l', 'g', 5, 'g', 'y', 'i', 'l', 'm', 5, 'g', 'y', 'i', 'l', 'b', 5, 'g', 'y', 'i', 'l', 's', 5, 'g', 'y', 'i', 'l', 't', 5, 'g', 'y', 'i', 'l', 'p', 5, 'g', 'y', 'i', 'l', 'h', 4, 'g', 'y', 'i', 'm', 4, 'g', 'y', 'i', 'b', 5, 'g', 'y', 'i', 'b', 's', 4, 'g', 'y', 'i', 's', 5, 'g', 'y', 'i', 's', 's', 5, 'g', 'y', 'i', 'n', 'g', 4, 'g', 'y', 'i', 'j', 4, 'g', 'y', 'i', 'c', 4, 'g', 'y', 'i', 'k', 4, 'g', 'y', 'i', 't', 4, 'g', 'y', 'i', 'p', 4, 'g', 'y', 'i', 'h', 2, 'g', 'i', 3, 'g', 'i', 'g', 4, 'g', 'i', 'g', 'g', 4, 'g', 'i', 'g', 's', 3, 'g', 'i', 'n', 4, 'g', 'i', 'n', 'j', 4, 'g', 'i', 'n', 'h', 3, 'g', 'i', 'd', 3, 'g', 'i', 'l', 4, 'g', 'i', 'l', 'g', 4, 'g', 'i', 'l', 'm', 4, 'g', 'i', 'l', 'b', 4, 'g', 'i', 'l', 's', 4, 'g', 'i', 'l', 't', 4, 'g', 'i', 'l', 'p', 4, 'g', 'i', 'l', 'h', 3, 'g', 'i', 'm', 3, 'g', 'i', 'b', 4, 'g', 'i', 'b', 's', 3, 'g', 'i', 's', 4, 'g', 'i', 's', 's', 4, 'g', 'i', 'n', 'g', 3, 'g', 'i', 'j', 3, 'g', 'i', 'c', 3, 'g', 'i', 'k', 3, 'g', 'i', 't', 3, 'g', 'i', 'p', 3, 'g', 'i', 'h', 3, 'g', 'g', 'a', 4, 'g', 'g', 'a', 'g', 5, 'g', 'g', 'a', 'g', 'g', 5, 'g', 'g', 'a', 'g', 's', 4, 'g', 'g', 'a', 'n', 5, 'g', 'g', 'a', 'n', 'j', 5, 'g', 'g', 'a', 'n', 'h', 4, 'g', 'g', 'a', 'd', 4, 'g', 'g', 'a', 'l', 5, 'g', 'g', 'a', 'l', 'g', 5, 'g', 'g', 'a', 'l', 'm', 5, 'g', 'g', 'a', 'l', 'b', 5, 'g', 'g', 'a', 'l', 's', 5, 'g', 'g', 'a', 'l', 't', 5, 'g', 'g', 'a', 'l', 'p', 5, 'g', 'g', 'a', 'l', 'h', 4, 'g', 'g', 'a', 'm', 4, 'g', 'g', 'a', 'b', 5, 'g', 'g', 'a', 'b', 's', 4, 'g', 'g', 'a', 's', 5, 'g', 'g', 'a', 's', 's', 5, 'g', 'g', 'a', 'n', 'g', 4, 'g', 'g', 'a', 'j', 4, 'g', 'g', 'a', 'c', 4, 'g', 'g', 'a', 'k', 4, 'g', 'g', 'a', 't', 4, 'g', 'g', 'a', 'p', 4, 'g', 'g', 'a', 'h', 4, 'g', 'g', 'a', 'e', 5, 'g', 'g', 'a', 'e', 'g', 6, 'g', 'g', 'a', 'e', 'g', 'g', 6, 'g', 'g', 'a', 'e', 'g', 's', 5, 'g', 'g', 'a', 'e', 'n', 6, 'g', 'g', 'a', 'e', 'n', 'j', 6, 'g', 'g', 'a', 'e', 'n', 'h', 5, 'g', 'g', 'a', 'e', 'd', 5, 'g', 'g', 'a', 'e', 'l', 6, 'g', 'g', 'a', 'e', 'l', 'g', 6, 'g', 'g', 'a', 'e', 'l', 'm', 6, 'g', 'g', 'a', 'e', 'l', 'b', 6, 'g', 'g', 'a', 'e', 'l', 's', 6, 'g', 'g', 'a', 'e', 'l', 't', 6, 'g', 'g', 'a', 'e', 'l', 'p', 6, 'g', 'g', 'a', 'e', 'l', 'h', 5, 'g', 'g', 'a', 'e', 'm', 5, 'g', 'g', 'a', 'e', 'b', 6, 'g', 'g', 'a', 'e', 'b', 's', 5, 'g', 'g', 'a', 'e', 's', 6, 'g', 'g', 'a', 'e', 's', 's', 6, 'g', 'g', 'a', 'e', 'n', 'g', 5, 'g', 'g', 'a', 'e', 'j', 5, 'g', 'g', 'a', 'e', 'c', 5, 'g', 'g', 'a', 'e', 'k', 5, 'g', 'g', 'a', 'e', 't', 5, 'g', 'g', 'a', 'e', 'p', 5, 'g', 'g', 'a', 'e', 'h', 4, 'g', 'g', 'y', 'a', 5, 'g', 'g', 'y', 'a', 'g', 6, 'g', 'g', 'y', 'a', 'g', 'g', 6, 'g', 'g', 'y', 'a', 'g', 's', 5, 'g', 'g', 'y', 'a', 'n', 6, 'g', 'g', 'y', 'a', 'n', 'j', 6, 'g', 'g', 'y', 'a', 'n', 'h', 5, 'g', 'g', 'y', 'a', 'd', 5, 'g', 'g', 'y', 'a', 'l', 6, 'g', 'g', 'y', 'a', 'l', 'g', 6, 'g', 'g', 'y', 'a', 'l', 'm', 6, 'g', 'g', 'y', 'a', 'l', 'b', 6, 'g', 'g', 'y', 'a', 'l', 's', 6, 'g', 'g', 'y', 'a', 'l', 't', 6, 'g', 'g', 'y', 'a', 'l', 'p', 6, 'g', 'g', 'y', 'a', 'l', 'h', 5, 'g', 'g', 'y', 'a', 'm', 5, 'g', 'g', 'y', 'a', 'b', 6, 'g', 'g', 'y', 'a', 'b', 's', 5, 'g', 'g', 'y', 'a', 's', 6, 'g', 'g', 'y', 'a', 's', 's', 6, 'g', 'g', 'y', 'a', 'n', 'g', 5, 'g', 'g', 'y', 'a', 'j', 5, 'g', 'g', 'y', 'a', 'c', 5, 'g', 'g', 'y', 'a', 'k', 5, 'g', 'g', 'y', 'a', 't', 5, 'g', 'g', 'y', 'a', 'p', 5, 'g', 'g', 'y', 'a', 'h', 5, 'g', 'g', 'y', 'a', 'e', 6, 'g', 'g', 'y', 'a', 'e', 'g', 7, 'g', 'g', 'y', 'a', 'e', 'g', 'g', 7, 'g', 'g', 'y', 'a', 'e', 'g', 's', 6, 'g', 'g', 'y', 'a', 'e', 'n', 7, 'g', 'g', 'y', 'a', 'e', 'n', 'j', 7, 'g', 'g', 'y', 'a', 'e', 'n', 'h', 6, 'g', 'g', 'y', 'a', 'e', 'd', 6, 'g', 'g', 'y', 'a', 'e', 'l', 7, 'g', 'g', 'y', 'a', 'e', 'l', 'g', 7, 'g', 'g', 'y', 'a', 'e', 'l', 'm', 7, 'g', 'g', 'y', 'a', 'e', 'l', 'b', 7, 'g', 'g', 'y', 'a', 'e', 'l', 's', 7, 'g', 'g', 'y', 'a', 'e', 'l', 't', 7, 'g', 'g', 'y', 'a', 'e', 'l', 'p', 7, 'g', 'g', 'y', 'a', 'e', 'l', 'h', 6, 'g', 'g', 'y', 'a', 'e', 'm', 6, 'g', 'g', 'y', 'a', 'e', 'b', 7, 'g', 'g', 'y', 'a', 'e', 'b', 's', 6, 'g', 'g', 'y', 'a', 'e', 's', 7, 'g', 'g', 'y', 'a', 'e', 's', 's', 7, 'g', 'g', 'y', 'a', 'e', 'n', 'g', 6, 'g', 'g', 'y', 'a', 'e', 'j', 6, 'g', 'g', 'y', 'a', 'e', 'c', 6, 'g', 'g', 'y', 'a', 'e', 'k', 6, 'g', 'g', 'y', 'a', 'e', 't', 6, 'g', 'g', 'y', 'a', 'e', 'p', 6, 'g', 'g', 'y', 'a', 'e', 'h', 4, 'g', 'g', 'e', 'o', 5, 'g', 'g', 'e', 'o', 'g', 6, 'g', 'g', 'e', 'o', 'g', 'g', 6, 'g', 'g', 'e', 'o', 'g', 's', 5, 'g', 'g', 'e', 'o', 'n', 6, 'g', 'g', 'e', 'o', 'n', 'j', 6, 'g', 'g', 'e', 'o', 'n', 'h', 5, 'g', 'g', 'e', 'o', 'd', 5, 'g', 'g', 'e', 'o', 'l', 6, 'g', 'g', 'e', 'o', 'l', 'g', 6, 'g', 'g', 'e', 'o', 'l', 'm', 6, 'g', 'g', 'e', 'o', 'l', 'b', 6, 'g', 'g', 'e', 'o', 'l', 's', 6, 'g', 'g', 'e', 'o', 'l', 't', 6, 'g', 'g', 'e', 'o', 'l', 'p', 6, 'g', 'g', 'e', 'o', 'l', 'h', 5, 'g', 'g', 'e', 'o', 'm', 5, 'g', 'g', 'e', 'o', 'b', 6, 'g', 'g', 'e', 'o', 'b', 's', 5, 'g', 'g', 'e', 'o', 's', 6, 'g', 'g', 'e', 'o', 's', 's', 6, 'g', 'g', 'e', 'o', 'n', 'g', 5, 'g', 'g', 'e', 'o', 'j', 5, 'g', 'g', 'e', 'o', 'c', 5, 'g', 'g', 'e', 'o', 'k', 5, 'g', 'g', 'e', 'o', 't', 5, 'g', 'g', 'e', 'o', 'p', 5, 'g', 'g', 'e', 'o', 'h', 3, 'g', 'g', 'e', 4, 'g', 'g', 'e', 'g', 5, 'g', 'g', 'e', 'g', 'g', 5, 'g', 'g', 'e', 'g', 's', 4, 'g', 'g', 'e', 'n', 5, 'g', 'g', 'e', 'n', 'j', 5, 'g', 'g', 'e', 'n', 'h', 4, 'g', 'g', 'e', 'd', 4, 'g', 'g', 'e', 'l', 5, 'g', 'g', 'e', 'l', 'g', 5, 'g', 'g', 'e', 'l', 'm', 5, 'g', 'g', 'e', 'l', 'b', 5, 'g', 'g', 'e', 'l', 's', 5, 'g', 'g', 'e', 'l', 't', 5, 'g', 'g', 'e', 'l', 'p', 5, 'g', 'g', 'e', 'l', 'h', 4, 'g', 'g', 'e', 'm', 4, 'g', 'g', 'e', 'b', 5, 'g', 'g', 'e', 'b', 's', 4, 'g', 'g', 'e', 's', 5, 'g', 'g', 'e', 's', 's', 5, 'g', 'g', 'e', 'n', 'g', 4, 'g', 'g', 'e', 'j', 4, 'g', 'g', 'e', 'c', 4, 'g', 'g', 'e', 'k', 4, 'g', 'g', 'e', 't', 4, 'g', 'g', 'e', 'p', 4, 'g', 'g', 'e', 'h', 5, 'g', 'g', 'y', 'e', 'o', 6, 'g', 'g', 'y', 'e', 'o', 'g', 7, 'g', 'g', 'y', 'e', 'o', 'g', 'g', 7, 'g', 'g', 'y', 'e', 'o', 'g', 's', 6, 'g', 'g', 'y', 'e', 'o', 'n', 7, 'g', 'g', 'y', 'e', 'o', 'n', 'j', 7, 'g', 'g', 'y', 'e', 'o', 'n', 'h', 6, 'g', 'g', 'y', 'e', 'o', 'd', 6, 'g', 'g', 'y', 'e', 'o', 'l', 7, 'g', 'g', 'y', 'e', 'o', 'l', 'g', 7, 'g', 'g', 'y', 'e', 'o', 'l', 'm', 7, 'g', 'g', 'y', 'e', 'o', 'l', 'b', 7, 'g', 'g', 'y', 'e', 'o', 'l', 's', 7, 'g', 'g', 'y', 'e', 'o', 'l', 't', 7, 'g', 'g', 'y', 'e', 'o', 'l', 'p', 7, 'g', 'g', 'y', 'e', 'o', 'l', 'h', 6, 'g', 'g', 'y', 'e', 'o', 'm', 6, 'g', 'g', 'y', 'e', 'o', 'b', 7, 'g', 'g', 'y', 'e', 'o', 'b', 's', 6, 'g', 'g', 'y', 'e', 'o', 's', 7, 'g', 'g', 'y', 'e', 'o', 's', 's', 7, 'g', 'g', 'y', 'e', 'o', 'n', 'g', 6, 'g', 'g', 'y', 'e', 'o', 'j', 6, 'g', 'g', 'y', 'e', 'o', 'c', 6, 'g', 'g', 'y', 'e', 'o', 'k', 6, 'g', 'g', 'y', 'e', 'o', 't', 6, 'g', 'g', 'y', 'e', 'o', 'p', 6, 'g', 'g', 'y', 'e', 'o', 'h', 4, 'g', 'g', 'y', 'e', 5, 'g', 'g', 'y', 'e', 'g', 6, 'g', 'g', 'y', 'e', 'g', 'g', 6, 'g', 'g', 'y', 'e', 'g', 's', 5, 'g', 'g', 'y', 'e', 'n', 6, 'g', 'g', 'y', 'e', 'n', 'j', 6, 'g', 'g', 'y', 'e', 'n', 'h', 5, 'g', 'g', 'y', 'e', 'd', 5, 'g', 'g', 'y', 'e', 'l', 6, 'g', 'g', 'y', 'e', 'l', 'g', 6, 'g', 'g', 'y', 'e', 'l', 'm', 6, 'g', 'g', 'y', 'e', 'l', 'b', 6, 'g', 'g', 'y', 'e', 'l', 's', 6, 'g', 'g', 'y', 'e', 'l', 't', 6, 'g', 'g', 'y', 'e', 'l', 'p', 6, 'g', 'g', 'y', 'e', 'l', 'h', 5, 'g', 'g', 'y', 'e', 'm', 5, 'g', 'g', 'y', 'e', 'b', 6, 'g', 'g', 'y', 'e', 'b', 's', 5, 'g', 'g', 'y', 'e', 's', 6, 'g', 'g', 'y', 'e', 's', 's', 6, 'g', 'g', 'y', 'e', 'n', 'g', 5, 'g', 'g', 'y', 'e', 'j', 5, 'g', 'g', 'y', 'e', 'c', 5, 'g', 'g', 'y', 'e', 'k', 5, 'g', 'g', 'y', 'e', 't', 5, 'g', 'g', 'y', 'e', 'p', 5, 'g', 'g', 'y', 'e', 'h', 3, 'g', 'g', 'o', 4, 'g', 'g', 'o', 'g', 5, 'g', 'g', 'o', 'g', 'g', 5, 'g', 'g', 'o', 'g', 's', 4, 'g', 'g', 'o', 'n', 5, 'g', 'g', 'o', 'n', 'j', 5, 'g', 'g', 'o', 'n', 'h', 4, 'g', 'g', 'o', 'd', 4, 'g', 'g', 'o', 'l', 5, 'g', 'g', 'o', 'l', 'g', 5, 'g', 'g', 'o', 'l', 'm', 5, 'g', 'g', 'o', 'l', 'b', 5, 'g', 'g', 'o', 'l', 's', 5, 'g', 'g', 'o', 'l', 't', 5, 'g', 'g', 'o', 'l', 'p', 5, 'g', 'g', 'o', 'l', 'h', 4, 'g', 'g', 'o', 'm', 4, 'g', 'g', 'o', 'b', 5, 'g', 'g', 'o', 'b', 's', 4, 'g', 'g', 'o', 's', 5, 'g', 'g', 'o', 's', 's', 5, 'g', 'g', 'o', 'n', 'g', 4, 'g', 'g', 'o', 'j', 4, 'g', 'g', 'o', 'c', 4, 'g', 'g', 'o', 'k', 4, 'g', 'g', 'o', 't', 4, 'g', 'g', 'o', 'p', 4, 'g', 'g', 'o', 'h', 4, 'g', 'g', 'w', 'a', 5, 'g', 'g', 'w', 'a', 'g', 6, 'g', 'g', 'w', 'a', 'g', 'g', 6, 'g', 'g', 'w', 'a', 'g', 's', 5, 'g', 'g', 'w', 'a', 'n', 6, 'g', 'g', 'w', 'a', 'n', 'j', 6, 'g', 'g', 'w', 'a', 'n', 'h', 5, 'g', 'g', 'w', 'a', 'd', 5, 'g', 'g', 'w', 'a', 'l', 6, 'g', 'g', 'w', 'a', 'l', 'g', 6, 'g', 'g', 'w', 'a', 'l', 'm', 6, 'g', 'g', 'w', 'a', 'l', 'b', 6, 'g', 'g', 'w', 'a', 'l', 's', 6, 'g', 'g', 'w', 'a', 'l', 't', 6, 'g', 'g', 'w', 'a', 'l', 'p', 6, 'g', 'g', 'w', 'a', 'l', 'h', 5, 'g', 'g', 'w', 'a', 'm', 5, 'g', 'g', 'w', 'a', 'b', 6, 'g', 'g', 'w', 'a', 'b', 's', 5, 'g', 'g', 'w', 'a', 's', 6, 'g', 'g', 'w', 'a', 's', 's', 6, 'g', 'g', 'w', 'a', 'n', 'g', 5, 'g', 'g', 'w', 'a', 'j', 5, 'g', 'g', 'w', 'a', 'c', 5, 'g', 'g', 'w', 'a', 'k', 5, 'g', 'g', 'w', 'a', 't', 5, 'g', 'g', 'w', 'a', 'p', 5, 'g', 'g', 'w', 'a', 'h', 5, 'g', 'g', 'w', 'a', 'e', 6, 'g', 'g', 'w', 'a', 'e', 'g', 7, 'g', 'g', 'w', 'a', 'e', 'g', 'g', 7, 'g', 'g', 'w', 'a', 'e', 'g', 's', 6, 'g', 'g', 'w', 'a', 'e', 'n', 7, 'g', 'g', 'w', 'a', 'e', 'n', 'j', 7, 'g', 'g', 'w', 'a', 'e', 'n', 'h', 6, 'g', 'g', 'w', 'a', 'e', 'd', 6, 'g', 'g', 'w', 'a', 'e', 'l', 7, 'g', 'g', 'w', 'a', 'e', 'l', 'g', 7, 'g', 'g', 'w', 'a', 'e', 'l', 'm', 7, 'g', 'g', 'w', 'a', 'e', 'l', 'b', 7, 'g', 'g', 'w', 'a', 'e', 'l', 's', 7, 'g', 'g', 'w', 'a', 'e', 'l', 't', 7, 'g', 'g', 'w', 'a', 'e', 'l', 'p', 7, 'g', 'g', 'w', 'a', 'e', 'l', 'h', 6, 'g', 'g', 'w', 'a', 'e', 'm', 6, 'g', 'g', 'w', 'a', 'e', 'b', 7, 'g', 'g', 'w', 'a', 'e', 'b', 's', 6, 'g', 'g', 'w', 'a', 'e', 's', 7, 'g', 'g', 'w', 'a', 'e', 's', 's', 7, 'g', 'g', 'w', 'a', 'e', 'n', 'g', 6, 'g', 'g', 'w', 'a', 'e', 'j', 6, 'g', 'g', 'w', 'a', 'e', 'c', 6, 'g', 'g', 'w', 'a', 'e', 'k', 6, 'g', 'g', 'w', 'a', 'e', 't', 6, 'g', 'g', 'w', 'a', 'e', 'p', 6, 'g', 'g', 'w', 'a', 'e', 'h', 4, 'g', 'g', 'o', 'e', 5, 'g', 'g', 'o', 'e', 'g', 6, 'g', 'g', 'o', 'e', 'g', 'g', 6, 'g', 'g', 'o', 'e', 'g', 's', 5, 'g', 'g', 'o', 'e', 'n', 6, 'g', 'g', 'o', 'e', 'n', 'j', 6, 'g', 'g', 'o', 'e', 'n', 'h', 5, 'g', 'g', 'o', 'e', 'd', 5, 'g', 'g', 'o', 'e', 'l', 6, 'g', 'g', 'o', 'e', 'l', 'g', 6, 'g', 'g', 'o', 'e', 'l', 'm', 6, 'g', 'g', 'o', 'e', 'l', 'b', 6, 'g', 'g', 'o', 'e', 'l', 's', 6, 'g', 'g', 'o', 'e', 'l', 't', 6, 'g', 'g', 'o', 'e', 'l', 'p', 6, 'g', 'g', 'o', 'e', 'l', 'h', 5, 'g', 'g', 'o', 'e', 'm', 5, 'g', 'g', 'o', 'e', 'b', 6, 'g', 'g', 'o', 'e', 'b', 's', 5, 'g', 'g', 'o', 'e', 's', 6, 'g', 'g', 'o', 'e', 's', 's', 6, 'g', 'g', 'o', 'e', 'n', 'g', 5, 'g', 'g', 'o', 'e', 'j', 5, 'g', 'g', 'o', 'e', 'c', 5, 'g', 'g', 'o', 'e', 'k', 5, 'g', 'g', 'o', 'e', 't', 5, 'g', 'g', 'o', 'e', 'p', 5, 'g', 'g', 'o', 'e', 'h', 4, 'g', 'g', 'y', 'o', 5, 'g', 'g', 'y', 'o', 'g', 6, 'g', 'g', 'y', 'o', 'g', 'g', 6, 'g', 'g', 'y', 'o', 'g', 's', 5, 'g', 'g', 'y', 'o', 'n', 6, 'g', 'g', 'y', 'o', 'n', 'j', 6, 'g', 'g', 'y', 'o', 'n', 'h', 5, 'g', 'g', 'y', 'o', 'd', 5, 'g', 'g', 'y', 'o', 'l', 6, 'g', 'g', 'y', 'o', 'l', 'g', 6, 'g', 'g', 'y', 'o', 'l', 'm', 6, 'g', 'g', 'y', 'o', 'l', 'b', 6, 'g', 'g', 'y', 'o', 'l', 's', 6, 'g', 'g', 'y', 'o', 'l', 't', 6, 'g', 'g', 'y', 'o', 'l', 'p', 6, 'g', 'g', 'y', 'o', 'l', 'h', 5, 'g', 'g', 'y', 'o', 'm', 5, 'g', 'g', 'y', 'o', 'b', 6, 'g', 'g', 'y', 'o', 'b', 's', 5, 'g', 'g', 'y', 'o', 's', 6, 'g', 'g', 'y', 'o', 's', 's', 6, 'g', 'g', 'y', 'o', 'n', 'g', 5, 'g', 'g', 'y', 'o', 'j', 5, 'g', 'g', 'y', 'o', 'c', 5, 'g', 'g', 'y', 'o', 'k', 5, 'g', 'g', 'y', 'o', 't', 5, 'g', 'g', 'y', 'o', 'p', 5, 'g', 'g', 'y', 'o', 'h', 3, 'g', 'g', 'u', 4, 'g', 'g', 'u', 'g', 5, 'g', 'g', 'u', 'g', 'g', 5, 'g', 'g', 'u', 'g', 's', 4, 'g', 'g', 'u', 'n', 5, 'g', 'g', 'u', 'n', 'j', 5, 'g', 'g', 'u', 'n', 'h', 4, 'g', 'g', 'u', 'd', 4, 'g', 'g', 'u', 'l', 5, 'g', 'g', 'u', 'l', 'g', 5, 'g', 'g', 'u', 'l', 'm', 5, 'g', 'g', 'u', 'l', 'b', 5, 'g', 'g', 'u', 'l', 's', 5, 'g', 'g', 'u', 'l', 't', 5, 'g', 'g', 'u', 'l', 'p', 5, 'g', 'g', 'u', 'l', 'h', 4, 'g', 'g', 'u', 'm', 4, 'g', 'g', 'u', 'b', 5, 'g', 'g', 'u', 'b', 's', 4, 'g', 'g', 'u', 's', 5, 'g', 'g', 'u', 's', 's', 5, 'g', 'g', 'u', 'n', 'g', 4, 'g', 'g', 'u', 'j', 4, 'g', 'g', 'u', 'c', 4, 'g', 'g', 'u', 'k', 4, 'g', 'g', 'u', 't', 4, 'g', 'g', 'u', 'p', 4, 'g', 'g', 'u', 'h', 5, 'g', 'g', 'w', 'e', 'o', 6, 'g', 'g', 'w', 'e', 'o', 'g', 7, 'g', 'g', 'w', 'e', 'o', 'g', 'g', 7, 'g', 'g', 'w', 'e', 'o', 'g', 's', 6, 'g', 'g', 'w', 'e', 'o', 'n', 7, 'g', 'g', 'w', 'e', 'o', 'n', 'j', 7, 'g', 'g', 'w', 'e', 'o', 'n', 'h', 6, 'g', 'g', 'w', 'e', 'o', 'd', 6, 'g', 'g', 'w', 'e', 'o', 'l', 7, 'g', 'g', 'w', 'e', 'o', 'l', 'g', 7, 'g', 'g', 'w', 'e', 'o', 'l', 'm', 7, 'g', 'g', 'w', 'e', 'o', 'l', 'b', 7, 'g', 'g', 'w', 'e', 'o', 'l', 's', 7, 'g', 'g', 'w', 'e', 'o', 'l', 't', 7, 'g', 'g', 'w', 'e', 'o', 'l', 'p', 7, 'g', 'g', 'w', 'e', 'o', 'l', 'h', 6, 'g', 'g', 'w', 'e', 'o', 'm', 6, 'g', 'g', 'w', 'e', 'o', 'b', 7, 'g', 'g', 'w', 'e', 'o', 'b', 's', 6, 'g', 'g', 'w', 'e', 'o', 's', 7, 'g', 'g', 'w', 'e', 'o', 's', 's', 7, 'g', 'g', 'w', 'e', 'o', 'n', 'g', 6, 'g', 'g', 'w', 'e', 'o', 'j', 6, 'g', 'g', 'w', 'e', 'o', 'c', 6, 'g', 'g', 'w', 'e', 'o', 'k', 6, 'g', 'g', 'w', 'e', 'o', 't', 6, 'g', 'g', 'w', 'e', 'o', 'p', 6, 'g', 'g', 'w', 'e', 'o', 'h', 4, 'g', 'g', 'w', 'e', 5, 'g', 'g', 'w', 'e', 'g', 6, 'g', 'g', 'w', 'e', 'g', 'g', 6, 'g', 'g', 'w', 'e', 'g', 's', 5, 'g', 'g', 'w', 'e', 'n', 6, 'g', 'g', 'w', 'e', 'n', 'j', 6, 'g', 'g', 'w', 'e', 'n', 'h', 5, 'g', 'g', 'w', 'e', 'd', 5, 'g', 'g', 'w', 'e', 'l', 6, 'g', 'g', 'w', 'e', 'l', 'g', 6, 'g', 'g', 'w', 'e', 'l', 'm', 6, 'g', 'g', 'w', 'e', 'l', 'b', 6, 'g', 'g', 'w', 'e', 'l', 's', 6, 'g', 'g', 'w', 'e', 'l', 't', 6, 'g', 'g', 'w', 'e', 'l', 'p', 6, 'g', 'g', 'w', 'e', 'l', 'h', 5, 'g', 'g', 'w', 'e', 'm', 5, 'g', 'g', 'w', 'e', 'b', 6, 'g', 'g', 'w', 'e', 'b', 's', 5, 'g', 'g', 'w', 'e', 's', 6, 'g', 'g', 'w', 'e', 's', 's', 6, 'g', 'g', 'w', 'e', 'n', 'g', 5, 'g', 'g', 'w', 'e', 'j', 5, 'g', 'g', 'w', 'e', 'c', 5, 'g', 'g', 'w', 'e', 'k', 5, 'g', 'g', 'w', 'e', 't', 5, 'g', 'g', 'w', 'e', 'p', 5, 'g', 'g', 'w', 'e', 'h', 4, 'g', 'g', 'w', 'i', 5, 'g', 'g', 'w', 'i', 'g', 6, 'g', 'g', 'w', 'i', 'g', 'g', 6, 'g', 'g', 'w', 'i', 'g', 's', 5, 'g', 'g', 'w', 'i', 'n', 6, 'g', 'g', 'w', 'i', 'n', 'j', 6, 'g', 'g', 'w', 'i', 'n', 'h', 5, 'g', 'g', 'w', 'i', 'd', 5, 'g', 'g', 'w', 'i', 'l', 6, 'g', 'g', 'w', 'i', 'l', 'g', 6, 'g', 'g', 'w', 'i', 'l', 'm', 6, 'g', 'g', 'w', 'i', 'l', 'b', 6, 'g', 'g', 'w', 'i', 'l', 's', 6, 'g', 'g', 'w', 'i', 'l', 't', 6, 'g', 'g', 'w', 'i', 'l', 'p', 6, 'g', 'g', 'w', 'i', 'l', 'h', 5, 'g', 'g', 'w', 'i', 'm', 5, 'g', 'g', 'w', 'i', 'b', 6, 'g', 'g', 'w', 'i', 'b', 's', 5, 'g', 'g', 'w', 'i', 's', 6, 'g', 'g', 'w', 'i', 's', 's', 6, 'g', 'g', 'w', 'i', 'n', 'g', 5, 'g', 'g', 'w', 'i', 'j', 5, 'g', 'g', 'w', 'i', 'c', 5, 'g', 'g', 'w', 'i', 'k', 5, 'g', 'g', 'w', 'i', 't', 5, 'g', 'g', 'w', 'i', 'p', 5, 'g', 'g', 'w', 'i', 'h', 4, 'g', 'g', 'y', 'u', 5, 'g', 'g', 'y', 'u', 'g', 6, 'g', 'g', 'y', 'u', 'g', 'g', 6, 'g', 'g', 'y', 'u', 'g', 's', 5, 'g', 'g', 'y', 'u', 'n', 6, 'g', 'g', 'y', 'u', 'n', 'j', 6, 'g', 'g', 'y', 'u', 'n', 'h', 5, 'g', 'g', 'y', 'u', 'd', 5, 'g', 'g', 'y', 'u', 'l', 6, 'g', 'g', 'y', 'u', 'l', 'g', 6, 'g', 'g', 'y', 'u', 'l', 'm', 6, 'g', 'g', 'y', 'u', 'l', 'b', 6, 'g', 'g', 'y', 'u', 'l', 's', 6, 'g', 'g', 'y', 'u', 'l', 't', 6, 'g', 'g', 'y', 'u', 'l', 'p', 6, 'g', 'g', 'y', 'u', 'l', 'h', 5, 'g', 'g', 'y', 'u', 'm', 5, 'g', 'g', 'y', 'u', 'b', 6, 'g', 'g', 'y', 'u', 'b', 's', 5, 'g', 'g', 'y', 'u', 's', 6, 'g', 'g', 'y', 'u', 's', 's', 6, 'g', 'g', 'y', 'u', 'n', 'g', 5, 'g', 'g', 'y', 'u', 'j', 5, 'g', 'g', 'y', 'u', 'c', 5, 'g', 'g', 'y', 'u', 'k', 5, 'g', 'g', 'y', 'u', 't', 5, 'g', 'g', 'y', 'u', 'p', 5, 'g', 'g', 'y', 'u', 'h', 4, 'g', 'g', 'e', 'u', 5, 'g', 'g', 'e', 'u', 'g', 6, 'g', 'g', 'e', 'u', 'g', 'g', 6, 'g', 'g', 'e', 'u', 'g', 's', 5, 'g', 'g', 'e', 'u', 'n', 6, 'g', 'g', 'e', 'u', 'n', 'j', 6, 'g', 'g', 'e', 'u', 'n', 'h', 5, 'g', 'g', 'e', 'u', 'd', 5, 'g', 'g', 'e', 'u', 'l', 6, 'g', 'g', 'e', 'u', 'l', 'g', 6, 'g', 'g', 'e', 'u', 'l', 'm', 6, 'g', 'g', 'e', 'u', 'l', 'b', 6, 'g', 'g', 'e', 'u', 'l', 's', 6, 'g', 'g', 'e', 'u', 'l', 't', 6, 'g', 'g', 'e', 'u', 'l', 'p', 6, 'g', 'g', 'e', 'u', 'l', 'h', 5, 'g', 'g', 'e', 'u', 'm', 5, 'g', 'g', 'e', 'u', 'b', 6, 'g', 'g', 'e', 'u', 'b', 's', 5, 'g', 'g', 'e', 'u', 's', 6, 'g', 'g', 'e', 'u', 's', 's', 6, 'g', 'g', 'e', 'u', 'n', 'g', 5, 'g', 'g', 'e', 'u', 'j', 5, 'g', 'g', 'e', 'u', 'c', 5, 'g', 'g', 'e', 'u', 'k', 5, 'g', 'g', 'e', 'u', 't', 5, 'g', 'g', 'e', 'u', 'p', 5, 'g', 'g', 'e', 'u', 'h', 4, 'g', 'g', 'y', 'i', 5, 'g', 'g', 'y', 'i', 'g', 6, 'g', 'g', 'y', 'i', 'g', 'g', 6, 'g', 'g', 'y', 'i', 'g', 's', 5, 'g', 'g', 'y', 'i', 'n', 6, 'g', 'g', 'y', 'i', 'n', 'j', 6, 'g', 'g', 'y', 'i', 'n', 'h', 5, 'g', 'g', 'y', 'i', 'd', 5, 'g', 'g', 'y', 'i', 'l', 6, 'g', 'g', 'y', 'i', 'l', 'g', 6, 'g', 'g', 'y', 'i', 'l', 'm', 6, 'g', 'g', 'y', 'i', 'l', 'b', 6, 'g', 'g', 'y', 'i', 'l', 's', 6, 'g', 'g', 'y', 'i', 'l', 't', 6, 'g', 'g', 'y', 'i', 'l', 'p', 6, 'g', 'g', 'y', 'i', 'l', 'h', 5, 'g', 'g', 'y', 'i', 'm', 5, 'g', 'g', 'y', 'i', 'b', 6, 'g', 'g', 'y', 'i', 'b', 's', 5, 'g', 'g', 'y', 'i', 's', 6, 'g', 'g', 'y', 'i', 's', 's', 6, 'g', 'g', 'y', 'i', 'n', 'g', 5, 'g', 'g', 'y', 'i', 'j', 5, 'g', 'g', 'y', 'i', 'c', 5, 'g', 'g', 'y', 'i', 'k', 5, 'g', 'g', 'y', 'i', 't', 5, 'g', 'g', 'y', 'i', 'p', 5, 'g', 'g', 'y', 'i', 'h', 3, 'g', 'g', 'i', 4, 'g', 'g', 'i', 'g', 5, 'g', 'g', 'i', 'g', 'g', 5, 'g', 'g', 'i', 'g', 's', 4, 'g', 'g', 'i', 'n', 5, 'g', 'g', 'i', 'n', 'j', 5, 'g', 'g', 'i', 'n', 'h', 4, 'g', 'g', 'i', 'd', 4, 'g', 'g', 'i', 'l', 5, 'g', 'g', 'i', 'l', 'g', 5, 'g', 'g', 'i', 'l', 'm', 5, 'g', 'g', 'i', 'l', 'b', 5, 'g', 'g', 'i', 'l', 's', 5, 'g', 'g', 'i', 'l', 't', 5, 'g', 'g', 'i', 'l', 'p', 5, 'g', 'g', 'i', 'l', 'h', 4, 'g', 'g', 'i', 'm', 4, 'g', 'g', 'i', 'b', 5, 'g', 'g', 'i', 'b', 's', 4, 'g', 'g', 'i', 's', 5, 'g', 'g', 'i', 's', 's', 5, 'g', 'g', 'i', 'n', 'g', 4, 'g', 'g', 'i', 'j', 4, 'g', 'g', 'i', 'c', 4, 'g', 'g', 'i', 'k', 4, 'g', 'g', 'i', 't', 4, 'g', 'g', 'i', 'p', 4, 'g', 'g', 'i', 'h', 2, 'n', 'a', 3, 'n', 'a', 'g', 4, 'n', 'a', 'g', 'g', 4, 'n', 'a', 'g', 's', 3, 'n', 'a', 'n', 4, 'n', 'a', 'n', 'j', 4, 'n', 'a', 'n', 'h', 3, 'n', 'a', 'd', 3, 'n', 'a', 'l', 4, 'n', 'a', 'l', 'g', 4, 'n', 'a', 'l', 'm', 4, 'n', 'a', 'l', 'b', 4, 'n', 'a', 'l', 's', 4, 'n', 'a', 'l', 't', 4, 'n', 'a', 'l', 'p', 4, 'n', 'a', 'l', 'h', 3, 'n', 'a', 'm', 3, 'n', 'a', 'b', 4, 'n', 'a', 'b', 's', 3, 'n', 'a', 's', 4, 'n', 'a', 's', 's', 4, 'n', 'a', 'n', 'g', 3, 'n', 'a', 'j', 3, 'n', 'a', 'c', 3, 'n', 'a', 'k', 3, 'n', 'a', 't', 3, 'n', 'a', 'p', 3, 'n', 'a', 'h', 3, 'n', 'a', 'e', 4, 'n', 'a', 'e', 'g', 5, 'n', 'a', 'e', 'g', 'g', 5, 'n', 'a', 'e', 'g', 's', 4, 'n', 'a', 'e', 'n', 5, 'n', 'a', 'e', 'n', 'j', 5, 'n', 'a', 'e', 'n', 'h', 4, 'n', 'a', 'e', 'd', 4, 'n', 'a', 'e', 'l', 5, 'n', 'a', 'e', 'l', 'g', 5, 'n', 'a', 'e', 'l', 'm', 5, 'n', 'a', 'e', 'l', 'b', 5, 'n', 'a', 'e', 'l', 's', 5, 'n', 'a', 'e', 'l', 't', 5, 'n', 'a', 'e', 'l', 'p', 5, 'n', 'a', 'e', 'l', 'h', 4, 'n', 'a', 'e', 'm', 4, 'n', 'a', 'e', 'b', 5, 'n', 'a', 'e', 'b', 's', 4, 'n', 'a', 'e', 's', 5, 'n', 'a', 'e', 's', 's', 5, 'n', 'a', 'e', 'n', 'g', 4, 'n', 'a', 'e', 'j', 4, 'n', 'a', 'e', 'c', 4, 'n', 'a', 'e', 'k', 4, 'n', 'a', 'e', 't', 4, 'n', 'a', 'e', 'p', 4, 'n', 'a', 'e', 'h', 3, 'n', 'y', 'a', 4, 'n', 'y', 'a', 'g', 5, 'n', 'y', 'a', 'g', 'g', 5, 'n', 'y', 'a', 'g', 's', 4, 'n', 'y', 'a', 'n', 5, 'n', 'y', 'a', 'n', 'j', 5, 'n', 'y', 'a', 'n', 'h', 4, 'n', 'y', 'a', 'd', 4, 'n', 'y', 'a', 'l', 5, 'n', 'y', 'a', 'l', 'g', 5, 'n', 'y', 'a', 'l', 'm', 5, 'n', 'y', 'a', 'l', 'b', 5, 'n', 'y', 'a', 'l', 's', 5, 'n', 'y', 'a', 'l', 't', 5, 'n', 'y', 'a', 'l', 'p', 5, 'n', 'y', 'a', 'l', 'h', 4, 'n', 'y', 'a', 'm', 4, 'n', 'y', 'a', 'b', 5, 'n', 'y', 'a', 'b', 's', 4, 'n', 'y', 'a', 's', 5, 'n', 'y', 'a', 's', 's', 5, 'n', 'y', 'a', 'n', 'g', 4, 'n', 'y', 'a', 'j', 4, 'n', 'y', 'a', 'c', 4, 'n', 'y', 'a', 'k', 4, 'n', 'y', 'a', 't', 4, 'n', 'y', 'a', 'p', 4, 'n', 'y', 'a', 'h', 4, 'n', 'y', 'a', 'e', 5, 'n', 'y', 'a', 'e', 'g', 6, 'n', 'y', 'a', 'e', 'g', 'g', 6, 'n', 'y', 'a', 'e', 'g', 's', 5, 'n', 'y', 'a', 'e', 'n', 6, 'n', 'y', 'a', 'e', 'n', 'j', 6, 'n', 'y', 'a', 'e', 'n', 'h', 5, 'n', 'y', 'a', 'e', 'd', 5, 'n', 'y', 'a', 'e', 'l', 6, 'n', 'y', 'a', 'e', 'l', 'g', 6, 'n', 'y', 'a', 'e', 'l', 'm', 6, 'n', 'y', 'a', 'e', 'l', 'b', 6, 'n', 'y', 'a', 'e', 'l', 's', 6, 'n', 'y', 'a', 'e', 'l', 't', 6, 'n', 'y', 'a', 'e', 'l', 'p', 6, 'n', 'y', 'a', 'e', 'l', 'h', 5, 'n', 'y', 'a', 'e', 'm', 5, 'n', 'y', 'a', 'e', 'b', 6, 'n', 'y', 'a', 'e', 'b', 's', 5, 'n', 'y', 'a', 'e', 's', 6, 'n', 'y', 'a', 'e', 's', 's', 6, 'n', 'y', 'a', 'e', 'n', 'g', 5, 'n', 'y', 'a', 'e', 'j', 5, 'n', 'y', 'a', 'e', 'c', 5, 'n', 'y', 'a', 'e', 'k', 5, 'n', 'y', 'a', 'e', 't', 5, 'n', 'y', 'a', 'e', 'p', 5, 'n', 'y', 'a', 'e', 'h', 3, 'n', 'e', 'o', 4, 'n', 'e', 'o', 'g', 5, 'n', 'e', 'o', 'g', 'g', 5, 'n', 'e', 'o', 'g', 's', 4, 'n', 'e', 'o', 'n', 5, 'n', 'e', 'o', 'n', 'j', 5, 'n', 'e', 'o', 'n', 'h', 4, 'n', 'e', 'o', 'd', 4, 'n', 'e', 'o', 'l', 5, 'n', 'e', 'o', 'l', 'g', 5, 'n', 'e', 'o', 'l', 'm', 5, 'n', 'e', 'o', 'l', 'b', 5, 'n', 'e', 'o', 'l', 's', 5, 'n', 'e', 'o', 'l', 't', 5, 'n', 'e', 'o', 'l', 'p', 5, 'n', 'e', 'o', 'l', 'h', 4, 'n', 'e', 'o', 'm', 4, 'n', 'e', 'o', 'b', 5, 'n', 'e', 'o', 'b', 's', 4, 'n', 'e', 'o', 's', 5, 'n', 'e', 'o', 's', 's', 5, 'n', 'e', 'o', 'n', 'g', 4, 'n', 'e', 'o', 'j', 4, 'n', 'e', 'o', 'c', 4, 'n', 'e', 'o', 'k', 4, 'n', 'e', 'o', 't', 4, 'n', 'e', 'o', 'p', 4, 'n', 'e', 'o', 'h', 2, 'n', 'e', 3, 'n', 'e', 'g', 4, 'n', 'e', 'g', 'g', 4, 'n', 'e', 'g', 's', 3, 'n', 'e', 'n', 4, 'n', 'e', 'n', 'j', 4, 'n', 'e', 'n', 'h', 3, 'n', 'e', 'd', 3, 'n', 'e', 'l', 4, 'n', 'e', 'l', 'g', 4, 'n', 'e', 'l', 'm', 4, 'n', 'e', 'l', 'b', 4, 'n', 'e', 'l', 's', 4, 'n', 'e', 'l', 't', 4, 'n', 'e', 'l', 'p', 4, 'n', 'e', 'l', 'h', 3, 'n', 'e', 'm', 3, 'n', 'e', 'b', 4, 'n', 'e', 'b', 's', 3, 'n', 'e', 's', 4, 'n', 'e', 's', 's', 4, 'n', 'e', 'n', 'g', 3, 'n', 'e', 'j', 3, 'n', 'e', 'c', 3, 'n', 'e', 'k', 3, 'n', 'e', 't', 3, 'n', 'e', 'p', 3, 'n', 'e', 'h', 4, 'n', 'y', 'e', 'o', 5, 'n', 'y', 'e', 'o', 'g', 6, 'n', 'y', 'e', 'o', 'g', 'g', 6, 'n', 'y', 'e', 'o', 'g', 's', 5, 'n', 'y', 'e', 'o', 'n', 6, 'n', 'y', 'e', 'o', 'n', 'j', 6, 'n', 'y', 'e', 'o', 'n', 'h', 5, 'n', 'y', 'e', 'o', 'd', 5, 'n', 'y', 'e', 'o', 'l', 6, 'n', 'y', 'e', 'o', 'l', 'g', 6, 'n', 'y', 'e', 'o', 'l', 'm', 6, 'n', 'y', 'e', 'o', 'l', 'b', 6, 'n', 'y', 'e', 'o', 'l', 's', 6, 'n', 'y', 'e', 'o', 'l', 't', 6, 'n', 'y', 'e', 'o', 'l', 'p', 6, 'n', 'y', 'e', 'o', 'l', 'h', 5, 'n', 'y', 'e', 'o', 'm', 5, 'n', 'y', 'e', 'o', 'b', 6, 'n', 'y', 'e', 'o', 'b', 's', 5, 'n', 'y', 'e', 'o', 's', 6, 'n', 'y', 'e', 'o', 's', 's', 6, 'n', 'y', 'e', 'o', 'n', 'g', 5, 'n', 'y', 'e', 'o', 'j', 5, 'n', 'y', 'e', 'o', 'c', 5, 'n', 'y', 'e', 'o', 'k', 5, 'n', 'y', 'e', 'o', 't', 5, 'n', 'y', 'e', 'o', 'p', 5, 'n', 'y', 'e', 'o', 'h', 3, 'n', 'y', 'e', 4, 'n', 'y', 'e', 'g', 5, 'n', 'y', 'e', 'g', 'g', 5, 'n', 'y', 'e', 'g', 's', 4, 'n', 'y', 'e', 'n', 5, 'n', 'y', 'e', 'n', 'j', 5, 'n', 'y', 'e', 'n', 'h', 4, 'n', 'y', 'e', 'd', 4, 'n', 'y', 'e', 'l', 5, 'n', 'y', 'e', 'l', 'g', 5, 'n', 'y', 'e', 'l', 'm', 5, 'n', 'y', 'e', 'l', 'b', 5, 'n', 'y', 'e', 'l', 's', 5, 'n', 'y', 'e', 'l', 't', 5, 'n', 'y', 'e', 'l', 'p', 5, 'n', 'y', 'e', 'l', 'h', 4, 'n', 'y', 'e', 'm', 4, 'n', 'y', 'e', 'b', 5, 'n', 'y', 'e', 'b', 's', 4, 'n', 'y', 'e', 's', 5, 'n', 'y', 'e', 's', 's', 5, 'n', 'y', 'e', 'n', 'g', 4, 'n', 'y', 'e', 'j', 4, 'n', 'y', 'e', 'c', 4, 'n', 'y', 'e', 'k', 4, 'n', 'y', 'e', 't', 4, 'n', 'y', 'e', 'p', 4, 'n', 'y', 'e', 'h', 2, 'n', 'o', 3, 'n', 'o', 'g', 4, 'n', 'o', 'g', 'g', 4, 'n', 'o', 'g', 's', 3, 'n', 'o', 'n', 4, 'n', 'o', 'n', 'j', 4, 'n', 'o', 'n', 'h', 3, 'n', 'o', 'd', 3, 'n', 'o', 'l', 4, 'n', 'o', 'l', 'g', 4, 'n', 'o', 'l', 'm', 4, 'n', 'o', 'l', 'b', 4, 'n', 'o', 'l', 's', 4, 'n', 'o', 'l', 't', 4, 'n', 'o', 'l', 'p', 4, 'n', 'o', 'l', 'h', 3, 'n', 'o', 'm', 3, 'n', 'o', 'b', 4, 'n', 'o', 'b', 's', 3, 'n', 'o', 's', 4, 'n', 'o', 's', 's', 4, 'n', 'o', 'n', 'g', 3, 'n', 'o', 'j', 3, 'n', 'o', 'c', 3, 'n', 'o', 'k', 3, 'n', 'o', 't', 3, 'n', 'o', 'p', 3, 'n', 'o', 'h', 3, 'n', 'w', 'a', 4, 'n', 'w', 'a', 'g', 5, 'n', 'w', 'a', 'g', 'g', 5, 'n', 'w', 'a', 'g', 's', 4, 'n', 'w', 'a', 'n', 5, 'n', 'w', 'a', 'n', 'j', 5, 'n', 'w', 'a', 'n', 'h', 4, 'n', 'w', 'a', 'd', 4, 'n', 'w', 'a', 'l', 5, 'n', 'w', 'a', 'l', 'g', 5, 'n', 'w', 'a', 'l', 'm', 5, 'n', 'w', 'a', 'l', 'b', 5, 'n', 'w', 'a', 'l', 's', 5, 'n', 'w', 'a', 'l', 't', 5, 'n', 'w', 'a', 'l', 'p', 5, 'n', 'w', 'a', 'l', 'h', 4, 'n', 'w', 'a', 'm', 4, 'n', 'w', 'a', 'b', 5, 'n', 'w', 'a', 'b', 's', 4, 'n', 'w', 'a', 's', 5, 'n', 'w', 'a', 's', 's', 5, 'n', 'w', 'a', 'n', 'g', 4, 'n', 'w', 'a', 'j', 4, 'n', 'w', 'a', 'c', 4, 'n', 'w', 'a', 'k', 4, 'n', 'w', 'a', 't', 4, 'n', 'w', 'a', 'p', 4, 'n', 'w', 'a', 'h', 4, 'n', 'w', 'a', 'e', 5, 'n', 'w', 'a', 'e', 'g', 6, 'n', 'w', 'a', 'e', 'g', 'g', 6, 'n', 'w', 'a', 'e', 'g', 's', 5, 'n', 'w', 'a', 'e', 'n', 6, 'n', 'w', 'a', 'e', 'n', 'j', 6, 'n', 'w', 'a', 'e', 'n', 'h', 5, 'n', 'w', 'a', 'e', 'd', 5, 'n', 'w', 'a', 'e', 'l', 6, 'n', 'w', 'a', 'e', 'l', 'g', 6, 'n', 'w', 'a', 'e', 'l', 'm', 6, 'n', 'w', 'a', 'e', 'l', 'b', 6, 'n', 'w', 'a', 'e', 'l', 's', 6, 'n', 'w', 'a', 'e', 'l', 't', 6, 'n', 'w', 'a', 'e', 'l', 'p', 6, 'n', 'w', 'a', 'e', 'l', 'h', 5, 'n', 'w', 'a', 'e', 'm', 5, 'n', 'w', 'a', 'e', 'b', 6, 'n', 'w', 'a', 'e', 'b', 's', 5, 'n', 'w', 'a', 'e', 's', 6, 'n', 'w', 'a', 'e', 's', 's', 6, 'n', 'w', 'a', 'e', 'n', 'g', 5, 'n', 'w', 'a', 'e', 'j', 5, 'n', 'w', 'a', 'e', 'c', 5, 'n', 'w', 'a', 'e', 'k', 5, 'n', 'w', 'a', 'e', 't', 5, 'n', 'w', 'a', 'e', 'p', 5, 'n', 'w', 'a', 'e', 'h', 3, 'n', 'o', 'e', 4, 'n', 'o', 'e', 'g', 5, 'n', 'o', 'e', 'g', 'g', 5, 'n', 'o', 'e', 'g', 's', 4, 'n', 'o', 'e', 'n', 5, 'n', 'o', 'e', 'n', 'j', 5, 'n', 'o', 'e', 'n', 'h', 4, 'n', 'o', 'e', 'd', 4, 'n', 'o', 'e', 'l', 5, 'n', 'o', 'e', 'l', 'g', 5, 'n', 'o', 'e', 'l', 'm', 5, 'n', 'o', 'e', 'l', 'b', 5, 'n', 'o', 'e', 'l', 's', 5, 'n', 'o', 'e', 'l', 't', 5, 'n', 'o', 'e', 'l', 'p', 5, 'n', 'o', 'e', 'l', 'h', 4, 'n', 'o', 'e', 'm', 4, 'n', 'o', 'e', 'b', 5, 'n', 'o', 'e', 'b', 's', 4, 'n', 'o', 'e', 's', 5, 'n', 'o', 'e', 's', 's', 5, 'n', 'o', 'e', 'n', 'g', 4, 'n', 'o', 'e', 'j', 4, 'n', 'o', 'e', 'c', 4, 'n', 'o', 'e', 'k', 4, 'n', 'o', 'e', 't', 4, 'n', 'o', 'e', 'p', 4, 'n', 'o', 'e', 'h', 3, 'n', 'y', 'o', 4, 'n', 'y', 'o', 'g', 5, 'n', 'y', 'o', 'g', 'g', 5, 'n', 'y', 'o', 'g', 's', 4, 'n', 'y', 'o', 'n', 5, 'n', 'y', 'o', 'n', 'j', 5, 'n', 'y', 'o', 'n', 'h', 4, 'n', 'y', 'o', 'd', 4, 'n', 'y', 'o', 'l', 5, 'n', 'y', 'o', 'l', 'g', 5, 'n', 'y', 'o', 'l', 'm', 5, 'n', 'y', 'o', 'l', 'b', 5, 'n', 'y', 'o', 'l', 's', 5, 'n', 'y', 'o', 'l', 't', 5, 'n', 'y', 'o', 'l', 'p', 5, 'n', 'y', 'o', 'l', 'h', 4, 'n', 'y', 'o', 'm', 4, 'n', 'y', 'o', 'b', 5, 'n', 'y', 'o', 'b', 's', 4, 'n', 'y', 'o', 's', 5, 'n', 'y', 'o', 's', 's', 5, 'n', 'y', 'o', 'n', 'g', 4, 'n', 'y', 'o', 'j', 4, 'n', 'y', 'o', 'c', 4, 'n', 'y', 'o', 'k', 4, 'n', 'y', 'o', 't', 4, 'n', 'y', 'o', 'p', 4, 'n', 'y', 'o', 'h', 2, 'n', 'u', 3, 'n', 'u', 'g', 4, 'n', 'u', 'g', 'g', 4, 'n', 'u', 'g', 's', 3, 'n', 'u', 'n', 4, 'n', 'u', 'n', 'j', 4, 'n', 'u', 'n', 'h', 3, 'n', 'u', 'd', 3, 'n', 'u', 'l', 4, 'n', 'u', 'l', 'g', 4, 'n', 'u', 'l', 'm', 4, 'n', 'u', 'l', 'b', 4, 'n', 'u', 'l', 's', 4, 'n', 'u', 'l', 't', 4, 'n', 'u', 'l', 'p', 4, 'n', 'u', 'l', 'h', 3, 'n', 'u', 'm', 3, 'n', 'u', 'b', 4, 'n', 'u', 'b', 's', 3, 'n', 'u', 's', 4, 'n', 'u', 's', 's', 4, 'n', 'u', 'n', 'g', 3, 'n', 'u', 'j', 3, 'n', 'u', 'c', 3, 'n', 'u', 'k', 3, 'n', 'u', 't', 3, 'n', 'u', 'p', 3, 'n', 'u', 'h', 4, 'n', 'w', 'e', 'o', 5, 'n', 'w', 'e', 'o', 'g', 6, 'n', 'w', 'e', 'o', 'g', 'g', 6, 'n', 'w', 'e', 'o', 'g', 's', 5, 'n', 'w', 'e', 'o', 'n', 6, 'n', 'w', 'e', 'o', 'n', 'j', 6, 'n', 'w', 'e', 'o', 'n', 'h', 5, 'n', 'w', 'e', 'o', 'd', 5, 'n', 'w', 'e', 'o', 'l', 6, 'n', 'w', 'e', 'o', 'l', 'g', 6, 'n', 'w', 'e', 'o', 'l', 'm', 6, 'n', 'w', 'e', 'o', 'l', 'b', 6, 'n', 'w', 'e', 'o', 'l', 's', 6, 'n', 'w', 'e', 'o', 'l', 't', 6, 'n', 'w', 'e', 'o', 'l', 'p', 6, 'n', 'w', 'e', 'o', 'l', 'h', 5, 'n', 'w', 'e', 'o', 'm', 5, 'n', 'w', 'e', 'o', 'b', 6, 'n', 'w', 'e', 'o', 'b', 's', 5, 'n', 'w', 'e', 'o', 's', 6, 'n', 'w', 'e', 'o', 's', 's', 6, 'n', 'w', 'e', 'o', 'n', 'g', 5, 'n', 'w', 'e', 'o', 'j', 5, 'n', 'w', 'e', 'o', 'c', 5, 'n', 'w', 'e', 'o', 'k', 5, 'n', 'w', 'e', 'o', 't', 5, 'n', 'w', 'e', 'o', 'p', 5, 'n', 'w', 'e', 'o', 'h', 3, 'n', 'w', 'e', 4, 'n', 'w', 'e', 'g', 5, 'n', 'w', 'e', 'g', 'g', 5, 'n', 'w', 'e', 'g', 's', 4, 'n', 'w', 'e', 'n', 5, 'n', 'w', 'e', 'n', 'j', 5, 'n', 'w', 'e', 'n', 'h', 4, 'n', 'w', 'e', 'd', 4, 'n', 'w', 'e', 'l', 5, 'n', 'w', 'e', 'l', 'g', 5, 'n', 'w', 'e', 'l', 'm', 5, 'n', 'w', 'e', 'l', 'b', 5, 'n', 'w', 'e', 'l', 's', 5, 'n', 'w', 'e', 'l', 't', 5, 'n', 'w', 'e', 'l', 'p', 5, 'n', 'w', 'e', 'l', 'h', 4, 'n', 'w', 'e', 'm', 4, 'n', 'w', 'e', 'b', 5, 'n', 'w', 'e', 'b', 's', 4, 'n', 'w', 'e', 's', 5, 'n', 'w', 'e', 's', 's', 5, 'n', 'w', 'e', 'n', 'g', 4, 'n', 'w', 'e', 'j', 4, 'n', 'w', 'e', 'c', 4, 'n', 'w', 'e', 'k', 4, 'n', 'w', 'e', 't', 4, 'n', 'w', 'e', 'p', 4, 'n', 'w', 'e', 'h', 3, 'n', 'w', 'i', 4, 'n', 'w', 'i', 'g', 5, 'n', 'w', 'i', 'g', 'g', 5, 'n', 'w', 'i', 'g', 's', 4, 'n', 'w', 'i', 'n', 5, 'n', 'w', 'i', 'n', 'j', 5, 'n', 'w', 'i', 'n', 'h', 4, 'n', 'w', 'i', 'd', 4, 'n', 'w', 'i', 'l', 5, 'n', 'w', 'i', 'l', 'g', 5, 'n', 'w', 'i', 'l', 'm', 5, 'n', 'w', 'i', 'l', 'b', 5, 'n', 'w', 'i', 'l', 's', 5, 'n', 'w', 'i', 'l', 't', 5, 'n', 'w', 'i', 'l', 'p', 5, 'n', 'w', 'i', 'l', 'h', 4, 'n', 'w', 'i', 'm', 4, 'n', 'w', 'i', 'b', 5, 'n', 'w', 'i', 'b', 's', 4, 'n', 'w', 'i', 's', 5, 'n', 'w', 'i', 's', 's', 5, 'n', 'w', 'i', 'n', 'g', 4, 'n', 'w', 'i', 'j', 4, 'n', 'w', 'i', 'c', 4, 'n', 'w', 'i', 'k', 4, 'n', 'w', 'i', 't', 4, 'n', 'w', 'i', 'p', 4, 'n', 'w', 'i', 'h', 3, 'n', 'y', 'u', 4, 'n', 'y', 'u', 'g', 5, 'n', 'y', 'u', 'g', 'g', 5, 'n', 'y', 'u', 'g', 's', 4, 'n', 'y', 'u', 'n', 5, 'n', 'y', 'u', 'n', 'j', 5, 'n', 'y', 'u', 'n', 'h', 4, 'n', 'y', 'u', 'd', 4, 'n', 'y', 'u', 'l', 5, 'n', 'y', 'u', 'l', 'g', 5, 'n', 'y', 'u', 'l', 'm', 5, 'n', 'y', 'u', 'l', 'b', 5, 'n', 'y', 'u', 'l', 's', 5, 'n', 'y', 'u', 'l', 't', 5, 'n', 'y', 'u', 'l', 'p', 5, 'n', 'y', 'u', 'l', 'h', 4, 'n', 'y', 'u', 'm', 4, 'n', 'y', 'u', 'b', 5, 'n', 'y', 'u', 'b', 's', 4, 'n', 'y', 'u', 's', 5, 'n', 'y', 'u', 's', 's', 5, 'n', 'y', 'u', 'n', 'g', 4, 'n', 'y', 'u', 'j', 4, 'n', 'y', 'u', 'c', 4, 'n', 'y', 'u', 'k', 4, 'n', 'y', 'u', 't', 4, 'n', 'y', 'u', 'p', 4, 'n', 'y', 'u', 'h', 3, 'n', 'e', 'u', 4, 'n', 'e', 'u', 'g', 5, 'n', 'e', 'u', 'g', 'g', 5, 'n', 'e', 'u', 'g', 's', 4, 'n', 'e', 'u', 'n', 5, 'n', 'e', 'u', 'n', 'j', 5, 'n', 'e', 'u', 'n', 'h', 4, 'n', 'e', 'u', 'd', 4, 'n', 'e', 'u', 'l', 5, 'n', 'e', 'u', 'l', 'g', 5, 'n', 'e', 'u', 'l', 'm', 5, 'n', 'e', 'u', 'l', 'b', 5, 'n', 'e', 'u', 'l', 's', 5, 'n', 'e', 'u', 'l', 't', 5, 'n', 'e', 'u', 'l', 'p', 5, 'n', 'e', 'u', 'l', 'h', 4, 'n', 'e', 'u', 'm', 4, 'n', 'e', 'u', 'b', 5, 'n', 'e', 'u', 'b', 's', 4, 'n', 'e', 'u', 's', 5, 'n', 'e', 'u', 's', 's', 5, 'n', 'e', 'u', 'n', 'g', 4, 'n', 'e', 'u', 'j', 4, 'n', 'e', 'u', 'c', 4, 'n', 'e', 'u', 'k', 4, 'n', 'e', 'u', 't', 4, 'n', 'e', 'u', 'p', 4, 'n', 'e', 'u', 'h', 3, 'n', 'y', 'i', 4, 'n', 'y', 'i', 'g', 5, 'n', 'y', 'i', 'g', 'g', 5, 'n', 'y', 'i', 'g', 's', 4, 'n', 'y', 'i', 'n', 5, 'n', 'y', 'i', 'n', 'j', 5, 'n', 'y', 'i', 'n', 'h', 4, 'n', 'y', 'i', 'd', 4, 'n', 'y', 'i', 'l', 5, 'n', 'y', 'i', 'l', 'g', 5, 'n', 'y', 'i', 'l', 'm', 5, 'n', 'y', 'i', 'l', 'b', 5, 'n', 'y', 'i', 'l', 's', 5, 'n', 'y', 'i', 'l', 't', 5, 'n', 'y', 'i', 'l', 'p', 5, 'n', 'y', 'i', 'l', 'h', 4, 'n', 'y', 'i', 'm', 4, 'n', 'y', 'i', 'b', 5, 'n', 'y', 'i', 'b', 's', 4, 'n', 'y', 'i', 's', 5, 'n', 'y', 'i', 's', 's', 5, 'n', 'y', 'i', 'n', 'g', 4, 'n', 'y', 'i', 'j', 4, 'n', 'y', 'i', 'c', 4, 'n', 'y', 'i', 'k', 4, 'n', 'y', 'i', 't', 4, 'n', 'y', 'i', 'p', 4, 'n', 'y', 'i', 'h', 2, 'n', 'i', 3, 'n', 'i', 'g', 4, 'n', 'i', 'g', 'g', 4, 'n', 'i', 'g', 's', 3, 'n', 'i', 'n', 4, 'n', 'i', 'n', 'j', 4, 'n', 'i', 'n', 'h', 3, 'n', 'i', 'd', 3, 'n', 'i', 'l', 4, 'n', 'i', 'l', 'g', 4, 'n', 'i', 'l', 'm', 4, 'n', 'i', 'l', 'b', 4, 'n', 'i', 'l', 's', 4, 'n', 'i', 'l', 't', 4, 'n', 'i', 'l', 'p', 4, 'n', 'i', 'l', 'h', 3, 'n', 'i', 'm', 3, 'n', 'i', 'b', 4, 'n', 'i', 'b', 's', 3, 'n', 'i', 's', 4, 'n', 'i', 's', 's', 4, 'n', 'i', 'n', 'g', 3, 'n', 'i', 'j', 3, 'n', 'i', 'c', 3, 'n', 'i', 'k', 3, 'n', 'i', 't', 3, 'n', 'i', 'p', 3, 'n', 'i', 'h', 2, 'd', 'a', 3, 'd', 'a', 'g', 4, 'd', 'a', 'g', 'g', 4, 'd', 'a', 'g', 's', 3, 'd', 'a', 'n', 4, 'd', 'a', 'n', 'j', 4, 'd', 'a', 'n', 'h', 3, 'd', 'a', 'd', 3, 'd', 'a', 'l', 4, 'd', 'a', 'l', 'g', 4, 'd', 'a', 'l', 'm', 4, 'd', 'a', 'l', 'b', 4, 'd', 'a', 'l', 's', 4, 'd', 'a', 'l', 't', 4, 'd', 'a', 'l', 'p', 4, 'd', 'a', 'l', 'h', 3, 'd', 'a', 'm', 3, 'd', 'a', 'b', 4, 'd', 'a', 'b', 's', 3, 'd', 'a', 's', 4, 'd', 'a', 's', 's', 4, 'd', 'a', 'n', 'g', 3, 'd', 'a', 'j', 3, 'd', 'a', 'c', 3, 'd', 'a', 'k', 3, 'd', 'a', 't', 3, 'd', 'a', 'p', 3, 'd', 'a', 'h', 3, 'd', 'a', 'e', 4, 'd', 'a', 'e', 'g', 5, 'd', 'a', 'e', 'g', 'g', 5, 'd', 'a', 'e', 'g', 's', 4, 'd', 'a', 'e', 'n', 5, 'd', 'a', 'e', 'n', 'j', 5, 'd', 'a', 'e', 'n', 'h', 4, 'd', 'a', 'e', 'd', 4, 'd', 'a', 'e', 'l', 5, 'd', 'a', 'e', 'l', 'g', 5, 'd', 'a', 'e', 'l', 'm', 5, 'd', 'a', 'e', 'l', 'b', 5, 'd', 'a', 'e', 'l', 's', 5, 'd', 'a', 'e', 'l', 't', 5, 'd', 'a', 'e', 'l', 'p', 5, 'd', 'a', 'e', 'l', 'h', 4, 'd', 'a', 'e', 'm', 4, 'd', 'a', 'e', 'b', 5, 'd', 'a', 'e', 'b', 's', 4, 'd', 'a', 'e', 's', 5, 'd', 'a', 'e', 's', 's', 5, 'd', 'a', 'e', 'n', 'g', 4, 'd', 'a', 'e', 'j', 4, 'd', 'a', 'e', 'c', 4, 'd', 'a', 'e', 'k', 4, 'd', 'a', 'e', 't', 4, 'd', 'a', 'e', 'p', 4, 'd', 'a', 'e', 'h', 3, 'd', 'y', 'a', 4, 'd', 'y', 'a', 'g', 5, 'd', 'y', 'a', 'g', 'g', 5, 'd', 'y', 'a', 'g', 's', 4, 'd', 'y', 'a', 'n', 5, 'd', 'y', 'a', 'n', 'j', 5, 'd', 'y', 'a', 'n', 'h', 4, 'd', 'y', 'a', 'd', 4, 'd', 'y', 'a', 'l', 5, 'd', 'y', 'a', 'l', 'g', 5, 'd', 'y', 'a', 'l', 'm', 5, 'd', 'y', 'a', 'l', 'b', 5, 'd', 'y', 'a', 'l', 's', 5, 'd', 'y', 'a', 'l', 't', 5, 'd', 'y', 'a', 'l', 'p', 5, 'd', 'y', 'a', 'l', 'h', 4, 'd', 'y', 'a', 'm', 4, 'd', 'y', 'a', 'b', 5, 'd', 'y', 'a', 'b', 's', 4, 'd', 'y', 'a', 's', 5, 'd', 'y', 'a', 's', 's', 5, 'd', 'y', 'a', 'n', 'g', 4, 'd', 'y', 'a', 'j', 4, 'd', 'y', 'a', 'c', 4, 'd', 'y', 'a', 'k', 4, 'd', 'y', 'a', 't', 4, 'd', 'y', 'a', 'p', 4, 'd', 'y', 'a', 'h', 4, 'd', 'y', 'a', 'e', 5, 'd', 'y', 'a', 'e', 'g', 6, 'd', 'y', 'a', 'e', 'g', 'g', 6, 'd', 'y', 'a', 'e', 'g', 's', 5, 'd', 'y', 'a', 'e', 'n', 6, 'd', 'y', 'a', 'e', 'n', 'j', 6, 'd', 'y', 'a', 'e', 'n', 'h', 5, 'd', 'y', 'a', 'e', 'd', 5, 'd', 'y', 'a', 'e', 'l', 6, 'd', 'y', 'a', 'e', 'l', 'g', 6, 'd', 'y', 'a', 'e', 'l', 'm', 6, 'd', 'y', 'a', 'e', 'l', 'b', 6, 'd', 'y', 'a', 'e', 'l', 's', 6, 'd', 'y', 'a', 'e', 'l', 't', 6, 'd', 'y', 'a', 'e', 'l', 'p', 6, 'd', 'y', 'a', 'e', 'l', 'h', 5, 'd', 'y', 'a', 'e', 'm', 5, 'd', 'y', 'a', 'e', 'b', 6, 'd', 'y', 'a', 'e', 'b', 's', 5, 'd', 'y', 'a', 'e', 's', 6, 'd', 'y', 'a', 'e', 's', 's', 6, 'd', 'y', 'a', 'e', 'n', 'g', 5, 'd', 'y', 'a', 'e', 'j', 5, 'd', 'y', 'a', 'e', 'c', 5, 'd', 'y', 'a', 'e', 'k', 5, 'd', 'y', 'a', 'e', 't', 5, 'd', 'y', 'a', 'e', 'p', 5, 'd', 'y', 'a', 'e', 'h', 3, 'd', 'e', 'o', 4, 'd', 'e', 'o', 'g', 5, 'd', 'e', 'o', 'g', 'g', 5, 'd', 'e', 'o', 'g', 's', 4, 'd', 'e', 'o', 'n', 5, 'd', 'e', 'o', 'n', 'j', 5, 'd', 'e', 'o', 'n', 'h', 4, 'd', 'e', 'o', 'd', 4, 'd', 'e', 'o', 'l', 5, 'd', 'e', 'o', 'l', 'g', 5, 'd', 'e', 'o', 'l', 'm', 5, 'd', 'e', 'o', 'l', 'b', 5, 'd', 'e', 'o', 'l', 's', 5, 'd', 'e', 'o', 'l', 't', 5, 'd', 'e', 'o', 'l', 'p', 5, 'd', 'e', 'o', 'l', 'h', 4, 'd', 'e', 'o', 'm', 4, 'd', 'e', 'o', 'b', 5, 'd', 'e', 'o', 'b', 's', 4, 'd', 'e', 'o', 's', 5, 'd', 'e', 'o', 's', 's', 5, 'd', 'e', 'o', 'n', 'g', 4, 'd', 'e', 'o', 'j', 4, 'd', 'e', 'o', 'c', 4, 'd', 'e', 'o', 'k', 4, 'd', 'e', 'o', 't', 4, 'd', 'e', 'o', 'p', 4, 'd', 'e', 'o', 'h', 2, 'd', 'e', 3, 'd', 'e', 'g', 4, 'd', 'e', 'g', 'g', 4, 'd', 'e', 'g', 's', 3, 'd', 'e', 'n', 4, 'd', 'e', 'n', 'j', 4, 'd', 'e', 'n', 'h', 3, 'd', 'e', 'd', 3, 'd', 'e', 'l', 4, 'd', 'e', 'l', 'g', 4, 'd', 'e', 'l', 'm', 4, 'd', 'e', 'l', 'b', 4, 'd', 'e', 'l', 's', 4, 'd', 'e', 'l', 't', 4, 'd', 'e', 'l', 'p', 4, 'd', 'e', 'l', 'h', 3, 'd', 'e', 'm', 3, 'd', 'e', 'b', 4, 'd', 'e', 'b', 's', 3, 'd', 'e', 's', 4, 'd', 'e', 's', 's', 4, 'd', 'e', 'n', 'g', 3, 'd', 'e', 'j', 3, 'd', 'e', 'c', 3, 'd', 'e', 'k', 3, 'd', 'e', 't', 3, 'd', 'e', 'p', 3, 'd', 'e', 'h', 4, 'd', 'y', 'e', 'o', 5, 'd', 'y', 'e', 'o', 'g', 6, 'd', 'y', 'e', 'o', 'g', 'g', 6, 'd', 'y', 'e', 'o', 'g', 's', 5, 'd', 'y', 'e', 'o', 'n', 6, 'd', 'y', 'e', 'o', 'n', 'j', 6, 'd', 'y', 'e', 'o', 'n', 'h', 5, 'd', 'y', 'e', 'o', 'd', 5, 'd', 'y', 'e', 'o', 'l', 6, 'd', 'y', 'e', 'o', 'l', 'g', 6, 'd', 'y', 'e', 'o', 'l', 'm', 6, 'd', 'y', 'e', 'o', 'l', 'b', 6, 'd', 'y', 'e', 'o', 'l', 's', 6, 'd', 'y', 'e', 'o', 'l', 't', 6, 'd', 'y', 'e', 'o', 'l', 'p', 6, 'd', 'y', 'e', 'o', 'l', 'h', 5, 'd', 'y', 'e', 'o', 'm', 5, 'd', 'y', 'e', 'o', 'b', 6, 'd', 'y', 'e', 'o', 'b', 's', 5, 'd', 'y', 'e', 'o', 's', 6, 'd', 'y', 'e', 'o', 's', 's', 6, 'd', 'y', 'e', 'o', 'n', 'g', 5, 'd', 'y', 'e', 'o', 'j', 5, 'd', 'y', 'e', 'o', 'c', 5, 'd', 'y', 'e', 'o', 'k', 5, 'd', 'y', 'e', 'o', 't', 5, 'd', 'y', 'e', 'o', 'p', 5, 'd', 'y', 'e', 'o', 'h', 3, 'd', 'y', 'e', 4, 'd', 'y', 'e', 'g', 5, 'd', 'y', 'e', 'g', 'g', 5, 'd', 'y', 'e', 'g', 's', 4, 'd', 'y', 'e', 'n', 5, 'd', 'y', 'e', 'n', 'j', 5, 'd', 'y', 'e', 'n', 'h', 4, 'd', 'y', 'e', 'd', 4, 'd', 'y', 'e', 'l', 5, 'd', 'y', 'e', 'l', 'g', 5, 'd', 'y', 'e', 'l', 'm', 5, 'd', 'y', 'e', 'l', 'b', 5, 'd', 'y', 'e', 'l', 's', 5, 'd', 'y', 'e', 'l', 't', 5, 'd', 'y', 'e', 'l', 'p', 5, 'd', 'y', 'e', 'l', 'h', 4, 'd', 'y', 'e', 'm', 4, 'd', 'y', 'e', 'b', 5, 'd', 'y', 'e', 'b', 's', 4, 'd', 'y', 'e', 's', 5, 'd', 'y', 'e', 's', 's', 5, 'd', 'y', 'e', 'n', 'g', 4, 'd', 'y', 'e', 'j', 4, 'd', 'y', 'e', 'c', 4, 'd', 'y', 'e', 'k', 4, 'd', 'y', 'e', 't', 4, 'd', 'y', 'e', 'p', 4, 'd', 'y', 'e', 'h', 2, 'd', 'o', 3, 'd', 'o', 'g', 4, 'd', 'o', 'g', 'g', 4, 'd', 'o', 'g', 's', 3, 'd', 'o', 'n', 4, 'd', 'o', 'n', 'j', 4, 'd', 'o', 'n', 'h', 3, 'd', 'o', 'd', 3, 'd', 'o', 'l', 4, 'd', 'o', 'l', 'g', 4, 'd', 'o', 'l', 'm', 4, 'd', 'o', 'l', 'b', 4, 'd', 'o', 'l', 's', 4, 'd', 'o', 'l', 't', 4, 'd', 'o', 'l', 'p', 4, 'd', 'o', 'l', 'h', 3, 'd', 'o', 'm', 3, 'd', 'o', 'b', 4, 'd', 'o', 'b', 's', 3, 'd', 'o', 's', 4, 'd', 'o', 's', 's', 4, 'd', 'o', 'n', 'g', 3, 'd', 'o', 'j', 3, 'd', 'o', 'c', 3, 'd', 'o', 'k', 3, 'd', 'o', 't', 3, 'd', 'o', 'p', 3, 'd', 'o', 'h', 3, 'd', 'w', 'a', 4, 'd', 'w', 'a', 'g', 5, 'd', 'w', 'a', 'g', 'g', 5, 'd', 'w', 'a', 'g', 's', 4, 'd', 'w', 'a', 'n', 5, 'd', 'w', 'a', 'n', 'j', 5, 'd', 'w', 'a', 'n', 'h', 4, 'd', 'w', 'a', 'd', 4, 'd', 'w', 'a', 'l', 5, 'd', 'w', 'a', 'l', 'g', 5, 'd', 'w', 'a', 'l', 'm', 5, 'd', 'w', 'a', 'l', 'b', 5, 'd', 'w', 'a', 'l', 's', 5, 'd', 'w', 'a', 'l', 't', 5, 'd', 'w', 'a', 'l', 'p', 5, 'd', 'w', 'a', 'l', 'h', 4, 'd', 'w', 'a', 'm', 4, 'd', 'w', 'a', 'b', 5, 'd', 'w', 'a', 'b', 's', 4, 'd', 'w', 'a', 's', 5, 'd', 'w', 'a', 's', 's', 5, 'd', 'w', 'a', 'n', 'g', 4, 'd', 'w', 'a', 'j', 4, 'd', 'w', 'a', 'c', 4, 'd', 'w', 'a', 'k', 4, 'd', 'w', 'a', 't', 4, 'd', 'w', 'a', 'p', 4, 'd', 'w', 'a', 'h', 4, 'd', 'w', 'a', 'e', 5, 'd', 'w', 'a', 'e', 'g', 6, 'd', 'w', 'a', 'e', 'g', 'g', 6, 'd', 'w', 'a', 'e', 'g', 's', 5, 'd', 'w', 'a', 'e', 'n', 6, 'd', 'w', 'a', 'e', 'n', 'j', 6, 'd', 'w', 'a', 'e', 'n', 'h', 5, 'd', 'w', 'a', 'e', 'd', 5, 'd', 'w', 'a', 'e', 'l', 6, 'd', 'w', 'a', 'e', 'l', 'g', 6, 'd', 'w', 'a', 'e', 'l', 'm', 6, 'd', 'w', 'a', 'e', 'l', 'b', 6, 'd', 'w', 'a', 'e', 'l', 's', 6, 'd', 'w', 'a', 'e', 'l', 't', 6, 'd', 'w', 'a', 'e', 'l', 'p', 6, 'd', 'w', 'a', 'e', 'l', 'h', 5, 'd', 'w', 'a', 'e', 'm', 5, 'd', 'w', 'a', 'e', 'b', 6, 'd', 'w', 'a', 'e', 'b', 's', 5, 'd', 'w', 'a', 'e', 's', 6, 'd', 'w', 'a', 'e', 's', 's', 6, 'd', 'w', 'a', 'e', 'n', 'g', 5, 'd', 'w', 'a', 'e', 'j', 5, 'd', 'w', 'a', 'e', 'c', 5, 'd', 'w', 'a', 'e', 'k', 5, 'd', 'w', 'a', 'e', 't', 5, 'd', 'w', 'a', 'e', 'p', 5, 'd', 'w', 'a', 'e', 'h', 3, 'd', 'o', 'e', 4, 'd', 'o', 'e', 'g', 5, 'd', 'o', 'e', 'g', 'g', 5, 'd', 'o', 'e', 'g', 's', 4, 'd', 'o', 'e', 'n', 5, 'd', 'o', 'e', 'n', 'j', 5, 'd', 'o', 'e', 'n', 'h', 4, 'd', 'o', 'e', 'd', 4, 'd', 'o', 'e', 'l', 5, 'd', 'o', 'e', 'l', 'g', 5, 'd', 'o', 'e', 'l', 'm', 5, 'd', 'o', 'e', 'l', 'b', 5, 'd', 'o', 'e', 'l', 's', 5, 'd', 'o', 'e', 'l', 't', 5, 'd', 'o', 'e', 'l', 'p', 5, 'd', 'o', 'e', 'l', 'h', 4, 'd', 'o', 'e', 'm', 4, 'd', 'o', 'e', 'b', 5, 'd', 'o', 'e', 'b', 's', 4, 'd', 'o', 'e', 's', 5, 'd', 'o', 'e', 's', 's', 5, 'd', 'o', 'e', 'n', 'g', 4, 'd', 'o', 'e', 'j', 4, 'd', 'o', 'e', 'c', 4, 'd', 'o', 'e', 'k', 4, 'd', 'o', 'e', 't', 4, 'd', 'o', 'e', 'p', 4, 'd', 'o', 'e', 'h', 3, 'd', 'y', 'o', 4, 'd', 'y', 'o', 'g', 5, 'd', 'y', 'o', 'g', 'g', 5, 'd', 'y', 'o', 'g', 's', 4, 'd', 'y', 'o', 'n', 5, 'd', 'y', 'o', 'n', 'j', 5, 'd', 'y', 'o', 'n', 'h', 4, 'd', 'y', 'o', 'd', 4, 'd', 'y', 'o', 'l', 5, 'd', 'y', 'o', 'l', 'g', 5, 'd', 'y', 'o', 'l', 'm', 5, 'd', 'y', 'o', 'l', 'b', 5, 'd', 'y', 'o', 'l', 's', 5, 'd', 'y', 'o', 'l', 't', 5, 'd', 'y', 'o', 'l', 'p', 5, 'd', 'y', 'o', 'l', 'h', 4, 'd', 'y', 'o', 'm', 4, 'd', 'y', 'o', 'b', 5, 'd', 'y', 'o', 'b', 's', 4, 'd', 'y', 'o', 's', 5, 'd', 'y', 'o', 's', 's', 5, 'd', 'y', 'o', 'n', 'g', 4, 'd', 'y', 'o', 'j', 4, 'd', 'y', 'o', 'c', 4, 'd', 'y', 'o', 'k', 4, 'd', 'y', 'o', 't', 4, 'd', 'y', 'o', 'p', 4, 'd', 'y', 'o', 'h', 2, 'd', 'u', 3, 'd', 'u', 'g', 4, 'd', 'u', 'g', 'g', 4, 'd', 'u', 'g', 's', 3, 'd', 'u', 'n', 4, 'd', 'u', 'n', 'j', 4, 'd', 'u', 'n', 'h', 3, 'd', 'u', 'd', 3, 'd', 'u', 'l', 4, 'd', 'u', 'l', 'g', 4, 'd', 'u', 'l', 'm', 4, 'd', 'u', 'l', 'b', 4, 'd', 'u', 'l', 's', 4, 'd', 'u', 'l', 't', 4, 'd', 'u', 'l', 'p', 4, 'd', 'u', 'l', 'h', 3, 'd', 'u', 'm', 3, 'd', 'u', 'b', 4, 'd', 'u', 'b', 's', 3, 'd', 'u', 's', 4, 'd', 'u', 's', 's', 4, 'd', 'u', 'n', 'g', 3, 'd', 'u', 'j', 3, 'd', 'u', 'c', 3, 'd', 'u', 'k', 3, 'd', 'u', 't', 3, 'd', 'u', 'p', 3, 'd', 'u', 'h', 4, 'd', 'w', 'e', 'o', 5, 'd', 'w', 'e', 'o', 'g', 6, 'd', 'w', 'e', 'o', 'g', 'g', 6, 'd', 'w', 'e', 'o', 'g', 's', 5, 'd', 'w', 'e', 'o', 'n', 6, 'd', 'w', 'e', 'o', 'n', 'j', 6, 'd', 'w', 'e', 'o', 'n', 'h', 5, 'd', 'w', 'e', 'o', 'd', 5, 'd', 'w', 'e', 'o', 'l', 6, 'd', 'w', 'e', 'o', 'l', 'g', 6, 'd', 'w', 'e', 'o', 'l', 'm', 6, 'd', 'w', 'e', 'o', 'l', 'b', 6, 'd', 'w', 'e', 'o', 'l', 's', 6, 'd', 'w', 'e', 'o', 'l', 't', 6, 'd', 'w', 'e', 'o', 'l', 'p', 6, 'd', 'w', 'e', 'o', 'l', 'h', 5, 'd', 'w', 'e', 'o', 'm', 5, 'd', 'w', 'e', 'o', 'b', 6, 'd', 'w', 'e', 'o', 'b', 's', 5, 'd', 'w', 'e', 'o', 's', 6, 'd', 'w', 'e', 'o', 's', 's', 6, 'd', 'w', 'e', 'o', 'n', 'g', 5, 'd', 'w', 'e', 'o', 'j', 5, 'd', 'w', 'e', 'o', 'c', 5, 'd', 'w', 'e', 'o', 'k', 5, 'd', 'w', 'e', 'o', 't', 5, 'd', 'w', 'e', 'o', 'p', 5, 'd', 'w', 'e', 'o', 'h', 3, 'd', 'w', 'e', 4, 'd', 'w', 'e', 'g', 5, 'd', 'w', 'e', 'g', 'g', 5, 'd', 'w', 'e', 'g', 's', 4, 'd', 'w', 'e', 'n', 5, 'd', 'w', 'e', 'n', 'j', 5, 'd', 'w', 'e', 'n', 'h', 4, 'd', 'w', 'e', 'd', 4, 'd', 'w', 'e', 'l', 5, 'd', 'w', 'e', 'l', 'g', 5, 'd', 'w', 'e', 'l', 'm', 5, 'd', 'w', 'e', 'l', 'b', 5, 'd', 'w', 'e', 'l', 's', 5, 'd', 'w', 'e', 'l', 't', 5, 'd', 'w', 'e', 'l', 'p', 5, 'd', 'w', 'e', 'l', 'h', 4, 'd', 'w', 'e', 'm', 4, 'd', 'w', 'e', 'b', 5, 'd', 'w', 'e', 'b', 's', 4, 'd', 'w', 'e', 's', 5, 'd', 'w', 'e', 's', 's', 5, 'd', 'w', 'e', 'n', 'g', 4, 'd', 'w', 'e', 'j', 4, 'd', 'w', 'e', 'c', 4, 'd', 'w', 'e', 'k', 4, 'd', 'w', 'e', 't', 4, 'd', 'w', 'e', 'p', 4, 'd', 'w', 'e', 'h', 3, 'd', 'w', 'i', 4, 'd', 'w', 'i', 'g', 5, 'd', 'w', 'i', 'g', 'g', 5, 'd', 'w', 'i', 'g', 's', 4, 'd', 'w', 'i', 'n', 5, 'd', 'w', 'i', 'n', 'j', 5, 'd', 'w', 'i', 'n', 'h', 4, 'd', 'w', 'i', 'd', 4, 'd', 'w', 'i', 'l', 5, 'd', 'w', 'i', 'l', 'g', 5, 'd', 'w', 'i', 'l', 'm', 5, 'd', 'w', 'i', 'l', 'b', 5, 'd', 'w', 'i', 'l', 's', 5, 'd', 'w', 'i', 'l', 't', 5, 'd', 'w', 'i', 'l', 'p', 5, 'd', 'w', 'i', 'l', 'h', 4, 'd', 'w', 'i', 'm', 4, 'd', 'w', 'i', 'b', 5, 'd', 'w', 'i', 'b', 's', 4, 'd', 'w', 'i', 's', 5, 'd', 'w', 'i', 's', 's', 5, 'd', 'w', 'i', 'n', 'g', 4, 'd', 'w', 'i', 'j', 4, 'd', 'w', 'i', 'c', 4, 'd', 'w', 'i', 'k', 4, 'd', 'w', 'i', 't', 4, 'd', 'w', 'i', 'p', 4, 'd', 'w', 'i', 'h', 3, 'd', 'y', 'u', 4, 'd', 'y', 'u', 'g', 5, 'd', 'y', 'u', 'g', 'g', 5, 'd', 'y', 'u', 'g', 's', 4, 'd', 'y', 'u', 'n', 5, 'd', 'y', 'u', 'n', 'j', 5, 'd', 'y', 'u', 'n', 'h', 4, 'd', 'y', 'u', 'd', 4, 'd', 'y', 'u', 'l', 5, 'd', 'y', 'u', 'l', 'g', 5, 'd', 'y', 'u', 'l', 'm', 5, 'd', 'y', 'u', 'l', 'b', 5, 'd', 'y', 'u', 'l', 's', 5, 'd', 'y', 'u', 'l', 't', 5, 'd', 'y', 'u', 'l', 'p', 5, 'd', 'y', 'u', 'l', 'h', 4, 'd', 'y', 'u', 'm', 4, 'd', 'y', 'u', 'b', 5, 'd', 'y', 'u', 'b', 's', 4, 'd', 'y', 'u', 's', 5, 'd', 'y', 'u', 's', 's', 5, 'd', 'y', 'u', 'n', 'g', 4, 'd', 'y', 'u', 'j', 4, 'd', 'y', 'u', 'c', 4, 'd', 'y', 'u', 'k', 4, 'd', 'y', 'u', 't', 4, 'd', 'y', 'u', 'p', 4, 'd', 'y', 'u', 'h', 3, 'd', 'e', 'u', 4, 'd', 'e', 'u', 'g', 5, 'd', 'e', 'u', 'g', 'g', 5, 'd', 'e', 'u', 'g', 's', 4, 'd', 'e', 'u', 'n', 5, 'd', 'e', 'u', 'n', 'j', 5, 'd', 'e', 'u', 'n', 'h', 4, 'd', 'e', 'u', 'd', 4, 'd', 'e', 'u', 'l', 5, 'd', 'e', 'u', 'l', 'g', 5, 'd', 'e', 'u', 'l', 'm', 5, 'd', 'e', 'u', 'l', 'b', 5, 'd', 'e', 'u', 'l', 's', 5, 'd', 'e', 'u', 'l', 't', 5, 'd', 'e', 'u', 'l', 'p', 5, 'd', 'e', 'u', 'l', 'h', 4, 'd', 'e', 'u', 'm', 4, 'd', 'e', 'u', 'b', 5, 'd', 'e', 'u', 'b', 's', 4, 'd', 'e', 'u', 's', 5, 'd', 'e', 'u', 's', 's', 5, 'd', 'e', 'u', 'n', 'g', 4, 'd', 'e', 'u', 'j', 4, 'd', 'e', 'u', 'c', 4, 'd', 'e', 'u', 'k', 4, 'd', 'e', 'u', 't', 4, 'd', 'e', 'u', 'p', 4, 'd', 'e', 'u', 'h', 3, 'd', 'y', 'i', 4, 'd', 'y', 'i', 'g', 5, 'd', 'y', 'i', 'g', 'g', 5, 'd', 'y', 'i', 'g', 's', 4, 'd', 'y', 'i', 'n', 5, 'd', 'y', 'i', 'n', 'j', 5, 'd', 'y', 'i', 'n', 'h', 4, 'd', 'y', 'i', 'd', 4, 'd', 'y', 'i', 'l', 5, 'd', 'y', 'i', 'l', 'g', 5, 'd', 'y', 'i', 'l', 'm', 5, 'd', 'y', 'i', 'l', 'b', 5, 'd', 'y', 'i', 'l', 's', 5, 'd', 'y', 'i', 'l', 't', 5, 'd', 'y', 'i', 'l', 'p', 5, 'd', 'y', 'i', 'l', 'h', 4, 'd', 'y', 'i', 'm', 4, 'd', 'y', 'i', 'b', 5, 'd', 'y', 'i', 'b', 's', 4, 'd', 'y', 'i', 's', 5, 'd', 'y', 'i', 's', 's', 5, 'd', 'y', 'i', 'n', 'g', 4, 'd', 'y', 'i', 'j', 4, 'd', 'y', 'i', 'c', 4, 'd', 'y', 'i', 'k', 4, 'd', 'y', 'i', 't', 4, 'd', 'y', 'i', 'p', 4, 'd', 'y', 'i', 'h', 2, 'd', 'i', 3, 'd', 'i', 'g', 4, 'd', 'i', 'g', 'g', 4, 'd', 'i', 'g', 's', 3, 'd', 'i', 'n', 4, 'd', 'i', 'n', 'j', 4, 'd', 'i', 'n', 'h', 3, 'd', 'i', 'd', 3, 'd', 'i', 'l', 4, 'd', 'i', 'l', 'g', 4, 'd', 'i', 'l', 'm', 4, 'd', 'i', 'l', 'b', 4, 'd', 'i', 'l', 's', 4, 'd', 'i', 'l', 't', 4, 'd', 'i', 'l', 'p', 4, 'd', 'i', 'l', 'h', 3, 'd', 'i', 'm', 3, 'd', 'i', 'b', 4, 'd', 'i', 'b', 's', 3, 'd', 'i', 's', 4, 'd', 'i', 's', 's', 4, 'd', 'i', 'n', 'g', 3, 'd', 'i', 'j', 3, 'd', 'i', 'c', 3, 'd', 'i', 'k', 3, 'd', 'i', 't', 3, 'd', 'i', 'p', 3, 'd', 'i', 'h', 3, 'd', 'd', 'a', 4, 'd', 'd', 'a', 'g', 5, 'd', 'd', 'a', 'g', 'g', 5, 'd', 'd', 'a', 'g', 's', 4, 'd', 'd', 'a', 'n', 5, 'd', 'd', 'a', 'n', 'j', 5, 'd', 'd', 'a', 'n', 'h', 4, 'd', 'd', 'a', 'd', 4, 'd', 'd', 'a', 'l', 5, 'd', 'd', 'a', 'l', 'g', 5, 'd', 'd', 'a', 'l', 'm', 5, 'd', 'd', 'a', 'l', 'b', 5, 'd', 'd', 'a', 'l', 's', 5, 'd', 'd', 'a', 'l', 't', 5, 'd', 'd', 'a', 'l', 'p', 5, 'd', 'd', 'a', 'l', 'h', 4, 'd', 'd', 'a', 'm', 4, 'd', 'd', 'a', 'b', 5, 'd', 'd', 'a', 'b', 's', 4, 'd', 'd', 'a', 's', 5, 'd', 'd', 'a', 's', 's', 5, 'd', 'd', 'a', 'n', 'g', 4, 'd', 'd', 'a', 'j', 4, 'd', 'd', 'a', 'c', 4, 'd', 'd', 'a', 'k', 4, 'd', 'd', 'a', 't', 4, 'd', 'd', 'a', 'p', 4, 'd', 'd', 'a', 'h', 4, 'd', 'd', 'a', 'e', 5, 'd', 'd', 'a', 'e', 'g', 6, 'd', 'd', 'a', 'e', 'g', 'g', 6, 'd', 'd', 'a', 'e', 'g', 's', 5, 'd', 'd', 'a', 'e', 'n', 6, 'd', 'd', 'a', 'e', 'n', 'j', 6, 'd', 'd', 'a', 'e', 'n', 'h', 5, 'd', 'd', 'a', 'e', 'd', 5, 'd', 'd', 'a', 'e', 'l', 6, 'd', 'd', 'a', 'e', 'l', 'g', 6, 'd', 'd', 'a', 'e', 'l', 'm', 6, 'd', 'd', 'a', 'e', 'l', 'b', 6, 'd', 'd', 'a', 'e', 'l', 's', 6, 'd', 'd', 'a', 'e', 'l', 't', 6, 'd', 'd', 'a', 'e', 'l', 'p', 6, 'd', 'd', 'a', 'e', 'l', 'h', 5, 'd', 'd', 'a', 'e', 'm', 5, 'd', 'd', 'a', 'e', 'b', 6, 'd', 'd', 'a', 'e', 'b', 's', 5, 'd', 'd', 'a', 'e', 's', 6, 'd', 'd', 'a', 'e', 's', 's', 6, 'd', 'd', 'a', 'e', 'n', 'g', 5, 'd', 'd', 'a', 'e', 'j', 5, 'd', 'd', 'a', 'e', 'c', 5, 'd', 'd', 'a', 'e', 'k', 5, 'd', 'd', 'a', 'e', 't', 5, 'd', 'd', 'a', 'e', 'p', 5, 'd', 'd', 'a', 'e', 'h', 4, 'd', 'd', 'y', 'a', 5, 'd', 'd', 'y', 'a', 'g', 6, 'd', 'd', 'y', 'a', 'g', 'g', 6, 'd', 'd', 'y', 'a', 'g', 's', 5, 'd', 'd', 'y', 'a', 'n', 6, 'd', 'd', 'y', 'a', 'n', 'j', 6, 'd', 'd', 'y', 'a', 'n', 'h', 5, 'd', 'd', 'y', 'a', 'd', 5, 'd', 'd', 'y', 'a', 'l', 6, 'd', 'd', 'y', 'a', 'l', 'g', 6, 'd', 'd', 'y', 'a', 'l', 'm', 6, 'd', 'd', 'y', 'a', 'l', 'b', 6, 'd', 'd', 'y', 'a', 'l', 's', 6, 'd', 'd', 'y', 'a', 'l', 't', 6, 'd', 'd', 'y', 'a', 'l', 'p', 6, 'd', 'd', 'y', 'a', 'l', 'h', 5, 'd', 'd', 'y', 'a', 'm', 5, 'd', 'd', 'y', 'a', 'b', 6, 'd', 'd', 'y', 'a', 'b', 's', 5, 'd', 'd', 'y', 'a', 's', 6, 'd', 'd', 'y', 'a', 's', 's', 6, 'd', 'd', 'y', 'a', 'n', 'g', 5, 'd', 'd', 'y', 'a', 'j', 5, 'd', 'd', 'y', 'a', 'c', 5, 'd', 'd', 'y', 'a', 'k', 5, 'd', 'd', 'y', 'a', 't', 5, 'd', 'd', 'y', 'a', 'p', 5, 'd', 'd', 'y', 'a', 'h', 5, 'd', 'd', 'y', 'a', 'e', 6, 'd', 'd', 'y', 'a', 'e', 'g', 7, 'd', 'd', 'y', 'a', 'e', 'g', 'g', 7, 'd', 'd', 'y', 'a', 'e', 'g', 's', 6, 'd', 'd', 'y', 'a', 'e', 'n', 7, 'd', 'd', 'y', 'a', 'e', 'n', 'j', 7, 'd', 'd', 'y', 'a', 'e', 'n', 'h', 6, 'd', 'd', 'y', 'a', 'e', 'd', 6, 'd', 'd', 'y', 'a', 'e', 'l', 7, 'd', 'd', 'y', 'a', 'e', 'l', 'g', 7, 'd', 'd', 'y', 'a', 'e', 'l', 'm', 7, 'd', 'd', 'y', 'a', 'e', 'l', 'b', 7, 'd', 'd', 'y', 'a', 'e', 'l', 's', 7, 'd', 'd', 'y', 'a', 'e', 'l', 't', 7, 'd', 'd', 'y', 'a', 'e', 'l', 'p', 7, 'd', 'd', 'y', 'a', 'e', 'l', 'h', 6, 'd', 'd', 'y', 'a', 'e', 'm', 6, 'd', 'd', 'y', 'a', 'e', 'b', 7, 'd', 'd', 'y', 'a', 'e', 'b', 's', 6, 'd', 'd', 'y', 'a', 'e', 's', 7, 'd', 'd', 'y', 'a', 'e', 's', 's', 7, 'd', 'd', 'y', 'a', 'e', 'n', 'g', 6, 'd', 'd', 'y', 'a', 'e', 'j', 6, 'd', 'd', 'y', 'a', 'e', 'c', 6, 'd', 'd', 'y', 'a', 'e', 'k', 6, 'd', 'd', 'y', 'a', 'e', 't', 6, 'd', 'd', 'y', 'a', 'e', 'p', 6, 'd', 'd', 'y', 'a', 'e', 'h', 4, 'd', 'd', 'e', 'o', 5, 'd', 'd', 'e', 'o', 'g', 6, 'd', 'd', 'e', 'o', 'g', 'g', 6, 'd', 'd', 'e', 'o', 'g', 's', 5, 'd', 'd', 'e', 'o', 'n', 6, 'd', 'd', 'e', 'o', 'n', 'j', 6, 'd', 'd', 'e', 'o', 'n', 'h', 5, 'd', 'd', 'e', 'o', 'd', 5, 'd', 'd', 'e', 'o', 'l', 6, 'd', 'd', 'e', 'o', 'l', 'g', 6, 'd', 'd', 'e', 'o', 'l', 'm', 6, 'd', 'd', 'e', 'o', 'l', 'b', 6, 'd', 'd', 'e', 'o', 'l', 's', 6, 'd', 'd', 'e', 'o', 'l', 't', 6, 'd', 'd', 'e', 'o', 'l', 'p', 6, 'd', 'd', 'e', 'o', 'l', 'h', 5, 'd', 'd', 'e', 'o', 'm', 5, 'd', 'd', 'e', 'o', 'b', 6, 'd', 'd', 'e', 'o', 'b', 's', 5, 'd', 'd', 'e', 'o', 's', 6, 'd', 'd', 'e', 'o', 's', 's', 6, 'd', 'd', 'e', 'o', 'n', 'g', 5, 'd', 'd', 'e', 'o', 'j', 5, 'd', 'd', 'e', 'o', 'c', 5, 'd', 'd', 'e', 'o', 'k', 5, 'd', 'd', 'e', 'o', 't', 5, 'd', 'd', 'e', 'o', 'p', 5, 'd', 'd', 'e', 'o', 'h', 3, 'd', 'd', 'e', 4, 'd', 'd', 'e', 'g', 5, 'd', 'd', 'e', 'g', 'g', 5, 'd', 'd', 'e', 'g', 's', 4, 'd', 'd', 'e', 'n', 5, 'd', 'd', 'e', 'n', 'j', 5, 'd', 'd', 'e', 'n', 'h', 4, 'd', 'd', 'e', 'd', 4, 'd', 'd', 'e', 'l', 5, 'd', 'd', 'e', 'l', 'g', 5, 'd', 'd', 'e', 'l', 'm', 5, 'd', 'd', 'e', 'l', 'b', 5, 'd', 'd', 'e', 'l', 's', 5, 'd', 'd', 'e', 'l', 't', 5, 'd', 'd', 'e', 'l', 'p', 5, 'd', 'd', 'e', 'l', 'h', 4, 'd', 'd', 'e', 'm', 4, 'd', 'd', 'e', 'b', 5, 'd', 'd', 'e', 'b', 's', 4, 'd', 'd', 'e', 's', 5, 'd', 'd', 'e', 's', 's', 5, 'd', 'd', 'e', 'n', 'g', 4, 'd', 'd', 'e', 'j', 4, 'd', 'd', 'e', 'c', 4, 'd', 'd', 'e', 'k', 4, 'd', 'd', 'e', 't', 4, 'd', 'd', 'e', 'p', 4, 'd', 'd', 'e', 'h', 5, 'd', 'd', 'y', 'e', 'o', 6, 'd', 'd', 'y', 'e', 'o', 'g', 7, 'd', 'd', 'y', 'e', 'o', 'g', 'g', 7, 'd', 'd', 'y', 'e', 'o', 'g', 's', 6, 'd', 'd', 'y', 'e', 'o', 'n', 7, 'd', 'd', 'y', 'e', 'o', 'n', 'j', 7, 'd', 'd', 'y', 'e', 'o', 'n', 'h', 6, 'd', 'd', 'y', 'e', 'o', 'd', 6, 'd', 'd', 'y', 'e', 'o', 'l', 7, 'd', 'd', 'y', 'e', 'o', 'l', 'g', 7, 'd', 'd', 'y', 'e', 'o', 'l', 'm', 7, 'd', 'd', 'y', 'e', 'o', 'l', 'b', 7, 'd', 'd', 'y', 'e', 'o', 'l', 's', 7, 'd', 'd', 'y', 'e', 'o', 'l', 't', 7, 'd', 'd', 'y', 'e', 'o', 'l', 'p', 7, 'd', 'd', 'y', 'e', 'o', 'l', 'h', 6, 'd', 'd', 'y', 'e', 'o', 'm', 6, 'd', 'd', 'y', 'e', 'o', 'b', 7, 'd', 'd', 'y', 'e', 'o', 'b', 's', 6, 'd', 'd', 'y', 'e', 'o', 's', 7, 'd', 'd', 'y', 'e', 'o', 's', 's', 7, 'd', 'd', 'y', 'e', 'o', 'n', 'g', 6, 'd', 'd', 'y', 'e', 'o', 'j', 6, 'd', 'd', 'y', 'e', 'o', 'c', 6, 'd', 'd', 'y', 'e', 'o', 'k', 6, 'd', 'd', 'y', 'e', 'o', 't', 6, 'd', 'd', 'y', 'e', 'o', 'p', 6, 'd', 'd', 'y', 'e', 'o', 'h', 4, 'd', 'd', 'y', 'e', 5, 'd', 'd', 'y', 'e', 'g', 6, 'd', 'd', 'y', 'e', 'g', 'g', 6, 'd', 'd', 'y', 'e', 'g', 's', 5, 'd', 'd', 'y', 'e', 'n', 6, 'd', 'd', 'y', 'e', 'n', 'j', 6, 'd', 'd', 'y', 'e', 'n', 'h', 5, 'd', 'd', 'y', 'e', 'd', 5, 'd', 'd', 'y', 'e', 'l', 6, 'd', 'd', 'y', 'e', 'l', 'g', 6, 'd', 'd', 'y', 'e', 'l', 'm', 6, 'd', 'd', 'y', 'e', 'l', 'b', 6, 'd', 'd', 'y', 'e', 'l', 's', 6, 'd', 'd', 'y', 'e', 'l', 't', 6, 'd', 'd', 'y', 'e', 'l', 'p', 6, 'd', 'd', 'y', 'e', 'l', 'h', 5, 'd', 'd', 'y', 'e', 'm', 5, 'd', 'd', 'y', 'e', 'b', 6, 'd', 'd', 'y', 'e', 'b', 's', 5, 'd', 'd', 'y', 'e', 's', 6, 'd', 'd', 'y', 'e', 's', 's', 6, 'd', 'd', 'y', 'e', 'n', 'g', 5, 'd', 'd', 'y', 'e', 'j', 5, 'd', 'd', 'y', 'e', 'c', 5, 'd', 'd', 'y', 'e', 'k', 5, 'd', 'd', 'y', 'e', 't', 5, 'd', 'd', 'y', 'e', 'p', 5, 'd', 'd', 'y', 'e', 'h', 3, 'd', 'd', 'o', 4, 'd', 'd', 'o', 'g', 5, 'd', 'd', 'o', 'g', 'g', 5, 'd', 'd', 'o', 'g', 's', 4, 'd', 'd', 'o', 'n', 5, 'd', 'd', 'o', 'n', 'j', 5, 'd', 'd', 'o', 'n', 'h', 4, 'd', 'd', 'o', 'd', 4, 'd', 'd', 'o', 'l', 5, 'd', 'd', 'o', 'l', 'g', 5, 'd', 'd', 'o', 'l', 'm', 5, 'd', 'd', 'o', 'l', 'b', 5, 'd', 'd', 'o', 'l', 's', 5, 'd', 'd', 'o', 'l', 't', 5, 'd', 'd', 'o', 'l', 'p', 5, 'd', 'd', 'o', 'l', 'h', 4, 'd', 'd', 'o', 'm', 4, 'd', 'd', 'o', 'b', 5, 'd', 'd', 'o', 'b', 's', 4, 'd', 'd', 'o', 's', 5, 'd', 'd', 'o', 's', 's', 5, 'd', 'd', 'o', 'n', 'g', 4, 'd', 'd', 'o', 'j', 4, 'd', 'd', 'o', 'c', 4, 'd', 'd', 'o', 'k', 4, 'd', 'd', 'o', 't', 4, 'd', 'd', 'o', 'p', 4, 'd', 'd', 'o', 'h', 4, 'd', 'd', 'w', 'a', 5, 'd', 'd', 'w', 'a', 'g', 6, 'd', 'd', 'w', 'a', 'g', 'g', 6, 'd', 'd', 'w', 'a', 'g', 's', 5, 'd', 'd', 'w', 'a', 'n', 6, 'd', 'd', 'w', 'a', 'n', 'j', 6, 'd', 'd', 'w', 'a', 'n', 'h', 5, 'd', 'd', 'w', 'a', 'd', 5, 'd', 'd', 'w', 'a', 'l', 6, 'd', 'd', 'w', 'a', 'l', 'g', 6, 'd', 'd', 'w', 'a', 'l', 'm', 6, 'd', 'd', 'w', 'a', 'l', 'b', 6, 'd', 'd', 'w', 'a', 'l', 's', 6, 'd', 'd', 'w', 'a', 'l', 't', 6, 'd', 'd', 'w', 'a', 'l', 'p', 6, 'd', 'd', 'w', 'a', 'l', 'h', 5, 'd', 'd', 'w', 'a', 'm', 5, 'd', 'd', 'w', 'a', 'b', 6, 'd', 'd', 'w', 'a', 'b', 's', 5, 'd', 'd', 'w', 'a', 's', 6, 'd', 'd', 'w', 'a', 's', 's', 6, 'd', 'd', 'w', 'a', 'n', 'g', 5, 'd', 'd', 'w', 'a', 'j', 5, 'd', 'd', 'w', 'a', 'c', 5, 'd', 'd', 'w', 'a', 'k', 5, 'd', 'd', 'w', 'a', 't', 5, 'd', 'd', 'w', 'a', 'p', 5, 'd', 'd', 'w', 'a', 'h', 5, 'd', 'd', 'w', 'a', 'e', 6, 'd', 'd', 'w', 'a', 'e', 'g', 7, 'd', 'd', 'w', 'a', 'e', 'g', 'g', 7, 'd', 'd', 'w', 'a', 'e', 'g', 's', 6, 'd', 'd', 'w', 'a', 'e', 'n', 7, 'd', 'd', 'w', 'a', 'e', 'n', 'j', 7, 'd', 'd', 'w', 'a', 'e', 'n', 'h', 6, 'd', 'd', 'w', 'a', 'e', 'd', 6, 'd', 'd', 'w', 'a', 'e', 'l', 7, 'd', 'd', 'w', 'a', 'e', 'l', 'g', 7, 'd', 'd', 'w', 'a', 'e', 'l', 'm', 7, 'd', 'd', 'w', 'a', 'e', 'l', 'b', 7, 'd', 'd', 'w', 'a', 'e', 'l', 's', 7, 'd', 'd', 'w', 'a', 'e', 'l', 't', 7, 'd', 'd', 'w', 'a', 'e', 'l', 'p', 7, 'd', 'd', 'w', 'a', 'e', 'l', 'h', 6, 'd', 'd', 'w', 'a', 'e', 'm', 6, 'd', 'd', 'w', 'a', 'e', 'b', 7, 'd', 'd', 'w', 'a', 'e', 'b', 's', 6, 'd', 'd', 'w', 'a', 'e', 's', 7, 'd', 'd', 'w', 'a', 'e', 's', 's', 7, 'd', 'd', 'w', 'a', 'e', 'n', 'g', 6, 'd', 'd', 'w', 'a', 'e', 'j', 6, 'd', 'd', 'w', 'a', 'e', 'c', 6, 'd', 'd', 'w', 'a', 'e', 'k', 6, 'd', 'd', 'w', 'a', 'e', 't', 6, 'd', 'd', 'w', 'a', 'e', 'p', 6, 'd', 'd', 'w', 'a', 'e', 'h', 4, 'd', 'd', 'o', 'e', 5, 'd', 'd', 'o', 'e', 'g', 6, 'd', 'd', 'o', 'e', 'g', 'g', 6, 'd', 'd', 'o', 'e', 'g', 's', 5, 'd', 'd', 'o', 'e', 'n', 6, 'd', 'd', 'o', 'e', 'n', 'j', 6, 'd', 'd', 'o', 'e', 'n', 'h', 5, 'd', 'd', 'o', 'e', 'd', 5, 'd', 'd', 'o', 'e', 'l', 6, 'd', 'd', 'o', 'e', 'l', 'g', 6, 'd', 'd', 'o', 'e', 'l', 'm', 6, 'd', 'd', 'o', 'e', 'l', 'b', 6, 'd', 'd', 'o', 'e', 'l', 's', 6, 'd', 'd', 'o', 'e', 'l', 't', 6, 'd', 'd', 'o', 'e', 'l', 'p', 6, 'd', 'd', 'o', 'e', 'l', 'h', 5, 'd', 'd', 'o', 'e', 'm', 5, 'd', 'd', 'o', 'e', 'b', 6, 'd', 'd', 'o', 'e', 'b', 's', 5, 'd', 'd', 'o', 'e', 's', 6, 'd', 'd', 'o', 'e', 's', 's', 6, 'd', 'd', 'o', 'e', 'n', 'g', 5, 'd', 'd', 'o', 'e', 'j', 5, 'd', 'd', 'o', 'e', 'c', 5, 'd', 'd', 'o', 'e', 'k', 5, 'd', 'd', 'o', 'e', 't', 5, 'd', 'd', 'o', 'e', 'p', 5, 'd', 'd', 'o', 'e', 'h', 4, 'd', 'd', 'y', 'o', 5, 'd', 'd', 'y', 'o', 'g', 6, 'd', 'd', 'y', 'o', 'g', 'g', 6, 'd', 'd', 'y', 'o', 'g', 's', 5, 'd', 'd', 'y', 'o', 'n', 6, 'd', 'd', 'y', 'o', 'n', 'j', 6, 'd', 'd', 'y', 'o', 'n', 'h', 5, 'd', 'd', 'y', 'o', 'd', 5, 'd', 'd', 'y', 'o', 'l', 6, 'd', 'd', 'y', 'o', 'l', 'g', 6, 'd', 'd', 'y', 'o', 'l', 'm', 6, 'd', 'd', 'y', 'o', 'l', 'b', 6, 'd', 'd', 'y', 'o', 'l', 's', 6, 'd', 'd', 'y', 'o', 'l', 't', 6, 'd', 'd', 'y', 'o', 'l', 'p', 6, 'd', 'd', 'y', 'o', 'l', 'h', 5, 'd', 'd', 'y', 'o', 'm', 5, 'd', 'd', 'y', 'o', 'b', 6, 'd', 'd', 'y', 'o', 'b', 's', 5, 'd', 'd', 'y', 'o', 's', 6, 'd', 'd', 'y', 'o', 's', 's', 6, 'd', 'd', 'y', 'o', 'n', 'g', 5, 'd', 'd', 'y', 'o', 'j', 5, 'd', 'd', 'y', 'o', 'c', 5, 'd', 'd', 'y', 'o', 'k', 5, 'd', 'd', 'y', 'o', 't', 5, 'd', 'd', 'y', 'o', 'p', 5, 'd', 'd', 'y', 'o', 'h', 3, 'd', 'd', 'u', 4, 'd', 'd', 'u', 'g', 5, 'd', 'd', 'u', 'g', 'g', 5, 'd', 'd', 'u', 'g', 's', 4, 'd', 'd', 'u', 'n', 5, 'd', 'd', 'u', 'n', 'j', 5, 'd', 'd', 'u', 'n', 'h', 4, 'd', 'd', 'u', 'd', 4, 'd', 'd', 'u', 'l', 5, 'd', 'd', 'u', 'l', 'g', 5, 'd', 'd', 'u', 'l', 'm', 5, 'd', 'd', 'u', 'l', 'b', 5, 'd', 'd', 'u', 'l', 's', 5, 'd', 'd', 'u', 'l', 't', 5, 'd', 'd', 'u', 'l', 'p', 5, 'd', 'd', 'u', 'l', 'h', 4, 'd', 'd', 'u', 'm', 4, 'd', 'd', 'u', 'b', 5, 'd', 'd', 'u', 'b', 's', 4, 'd', 'd', 'u', 's', 5, 'd', 'd', 'u', 's', 's', 5, 'd', 'd', 'u', 'n', 'g', 4, 'd', 'd', 'u', 'j', 4, 'd', 'd', 'u', 'c', 4, 'd', 'd', 'u', 'k', 4, 'd', 'd', 'u', 't', 4, 'd', 'd', 'u', 'p', 4, 'd', 'd', 'u', 'h', 5, 'd', 'd', 'w', 'e', 'o', 6, 'd', 'd', 'w', 'e', 'o', 'g', 7, 'd', 'd', 'w', 'e', 'o', 'g', 'g', 7, 'd', 'd', 'w', 'e', 'o', 'g', 's', 6, 'd', 'd', 'w', 'e', 'o', 'n', 7, 'd', 'd', 'w', 'e', 'o', 'n', 'j', 7, 'd', 'd', 'w', 'e', 'o', 'n', 'h', 6, 'd', 'd', 'w', 'e', 'o', 'd', 6, 'd', 'd', 'w', 'e', 'o', 'l', 7, 'd', 'd', 'w', 'e', 'o', 'l', 'g', 7, 'd', 'd', 'w', 'e', 'o', 'l', 'm', 7, 'd', 'd', 'w', 'e', 'o', 'l', 'b', 7, 'd', 'd', 'w', 'e', 'o', 'l', 's', 7, 'd', 'd', 'w', 'e', 'o', 'l', 't', 7, 'd', 'd', 'w', 'e', 'o', 'l', 'p', 7, 'd', 'd', 'w', 'e', 'o', 'l', 'h', 6, 'd', 'd', 'w', 'e', 'o', 'm', 6, 'd', 'd', 'w', 'e', 'o', 'b', 7, 'd', 'd', 'w', 'e', 'o', 'b', 's', 6, 'd', 'd', 'w', 'e', 'o', 's', 7, 'd', 'd', 'w', 'e', 'o', 's', 's', 7, 'd', 'd', 'w', 'e', 'o', 'n', 'g', 6, 'd', 'd', 'w', 'e', 'o', 'j', 6, 'd', 'd', 'w', 'e', 'o', 'c', 6, 'd', 'd', 'w', 'e', 'o', 'k', 6, 'd', 'd', 'w', 'e', 'o', 't', 6, 'd', 'd', 'w', 'e', 'o', 'p', 6, 'd', 'd', 'w', 'e', 'o', 'h', 4, 'd', 'd', 'w', 'e', 5, 'd', 'd', 'w', 'e', 'g', 6, 'd', 'd', 'w', 'e', 'g', 'g', 6, 'd', 'd', 'w', 'e', 'g', 's', 5, 'd', 'd', 'w', 'e', 'n', 6, 'd', 'd', 'w', 'e', 'n', 'j', 6, 'd', 'd', 'w', 'e', 'n', 'h', 5, 'd', 'd', 'w', 'e', 'd', 5, 'd', 'd', 'w', 'e', 'l', 6, 'd', 'd', 'w', 'e', 'l', 'g', 6, 'd', 'd', 'w', 'e', 'l', 'm', 6, 'd', 'd', 'w', 'e', 'l', 'b', 6, 'd', 'd', 'w', 'e', 'l', 's', 6, 'd', 'd', 'w', 'e', 'l', 't', 6, 'd', 'd', 'w', 'e', 'l', 'p', 6, 'd', 'd', 'w', 'e', 'l', 'h', 5, 'd', 'd', 'w', 'e', 'm', 5, 'd', 'd', 'w', 'e', 'b', 6, 'd', 'd', 'w', 'e', 'b', 's', 5, 'd', 'd', 'w', 'e', 's', 6, 'd', 'd', 'w', 'e', 's', 's', 6, 'd', 'd', 'w', 'e', 'n', 'g', 5, 'd', 'd', 'w', 'e', 'j', 5, 'd', 'd', 'w', 'e', 'c', 5, 'd', 'd', 'w', 'e', 'k', 5, 'd', 'd', 'w', 'e', 't', 5, 'd', 'd', 'w', 'e', 'p', 5, 'd', 'd', 'w', 'e', 'h', 4, 'd', 'd', 'w', 'i', 5, 'd', 'd', 'w', 'i', 'g', 6, 'd', 'd', 'w', 'i', 'g', 'g', 6, 'd', 'd', 'w', 'i', 'g', 's', 5, 'd', 'd', 'w', 'i', 'n', 6, 'd', 'd', 'w', 'i', 'n', 'j', 6, 'd', 'd', 'w', 'i', 'n', 'h', 5, 'd', 'd', 'w', 'i', 'd', 5, 'd', 'd', 'w', 'i', 'l', 6, 'd', 'd', 'w', 'i', 'l', 'g', 6, 'd', 'd', 'w', 'i', 'l', 'm', 6, 'd', 'd', 'w', 'i', 'l', 'b', 6, 'd', 'd', 'w', 'i', 'l', 's', 6, 'd', 'd', 'w', 'i', 'l', 't', 6, 'd', 'd', 'w', 'i', 'l', 'p', 6, 'd', 'd', 'w', 'i', 'l', 'h', 5, 'd', 'd', 'w', 'i', 'm', 5, 'd', 'd', 'w', 'i', 'b', 6, 'd', 'd', 'w', 'i', 'b', 's', 5, 'd', 'd', 'w', 'i', 's', 6, 'd', 'd', 'w', 'i', 's', 's', 6, 'd', 'd', 'w', 'i', 'n', 'g', 5, 'd', 'd', 'w', 'i', 'j', 5, 'd', 'd', 'w', 'i', 'c', 5, 'd', 'd', 'w', 'i', 'k', 5, 'd', 'd', 'w', 'i', 't', 5, 'd', 'd', 'w', 'i', 'p', 5, 'd', 'd', 'w', 'i', 'h', 4, 'd', 'd', 'y', 'u', 5, 'd', 'd', 'y', 'u', 'g', 6, 'd', 'd', 'y', 'u', 'g', 'g', 6, 'd', 'd', 'y', 'u', 'g', 's', 5, 'd', 'd', 'y', 'u', 'n', 6, 'd', 'd', 'y', 'u', 'n', 'j', 6, 'd', 'd', 'y', 'u', 'n', 'h', 5, 'd', 'd', 'y', 'u', 'd', 5, 'd', 'd', 'y', 'u', 'l', 6, 'd', 'd', 'y', 'u', 'l', 'g', 6, 'd', 'd', 'y', 'u', 'l', 'm', 6, 'd', 'd', 'y', 'u', 'l', 'b', 6, 'd', 'd', 'y', 'u', 'l', 's', 6, 'd', 'd', 'y', 'u', 'l', 't', 6, 'd', 'd', 'y', 'u', 'l', 'p', 6, 'd', 'd', 'y', 'u', 'l', 'h', 5, 'd', 'd', 'y', 'u', 'm', 5, 'd', 'd', 'y', 'u', 'b', 6, 'd', 'd', 'y', 'u', 'b', 's', 5, 'd', 'd', 'y', 'u', 's', 6, 'd', 'd', 'y', 'u', 's', 's', 6, 'd', 'd', 'y', 'u', 'n', 'g', 5, 'd', 'd', 'y', 'u', 'j', 5, 'd', 'd', 'y', 'u', 'c', 5, 'd', 'd', 'y', 'u', 'k', 5, 'd', 'd', 'y', 'u', 't', 5, 'd', 'd', 'y', 'u', 'p', 5, 'd', 'd', 'y', 'u', 'h', 4, 'd', 'd', 'e', 'u', 5, 'd', 'd', 'e', 'u', 'g', 6, 'd', 'd', 'e', 'u', 'g', 'g', 6, 'd', 'd', 'e', 'u', 'g', 's', 5, 'd', 'd', 'e', 'u', 'n', 6, 'd', 'd', 'e', 'u', 'n', 'j', 6, 'd', 'd', 'e', 'u', 'n', 'h', 5, 'd', 'd', 'e', 'u', 'd', 5, 'd', 'd', 'e', 'u', 'l', 6, 'd', 'd', 'e', 'u', 'l', 'g', 6, 'd', 'd', 'e', 'u', 'l', 'm', 6, 'd', 'd', 'e', 'u', 'l', 'b', 6, 'd', 'd', 'e', 'u', 'l', 's', 6, 'd', 'd', 'e', 'u', 'l', 't', 6, 'd', 'd', 'e', 'u', 'l', 'p', 6, 'd', 'd', 'e', 'u', 'l', 'h', 5, 'd', 'd', 'e', 'u', 'm', 5, 'd', 'd', 'e', 'u', 'b', 6, 'd', 'd', 'e', 'u', 'b', 's', 5, 'd', 'd', 'e', 'u', 's', 6, 'd', 'd', 'e', 'u', 's', 's', 6, 'd', 'd', 'e', 'u', 'n', 'g', 5, 'd', 'd', 'e', 'u', 'j', 5, 'd', 'd', 'e', 'u', 'c', 5, 'd', 'd', 'e', 'u', 'k', 5, 'd', 'd', 'e', 'u', 't', 5, 'd', 'd', 'e', 'u', 'p', 5, 'd', 'd', 'e', 'u', 'h', 4, 'd', 'd', 'y', 'i', 5, 'd', 'd', 'y', 'i', 'g', 6, 'd', 'd', 'y', 'i', 'g', 'g', 6, 'd', 'd', 'y', 'i', 'g', 's', 5, 'd', 'd', 'y', 'i', 'n', 6, 'd', 'd', 'y', 'i', 'n', 'j', 6, 'd', 'd', 'y', 'i', 'n', 'h', 5, 'd', 'd', 'y', 'i', 'd', 5, 'd', 'd', 'y', 'i', 'l', 6, 'd', 'd', 'y', 'i', 'l', 'g', 6, 'd', 'd', 'y', 'i', 'l', 'm', 6, 'd', 'd', 'y', 'i', 'l', 'b', 6, 'd', 'd', 'y', 'i', 'l', 's', 6, 'd', 'd', 'y', 'i', 'l', 't', 6, 'd', 'd', 'y', 'i', 'l', 'p', 6, 'd', 'd', 'y', 'i', 'l', 'h', 5, 'd', 'd', 'y', 'i', 'm', 5, 'd', 'd', 'y', 'i', 'b', 6, 'd', 'd', 'y', 'i', 'b', 's', 5, 'd', 'd', 'y', 'i', 's', 6, 'd', 'd', 'y', 'i', 's', 's', 6, 'd', 'd', 'y', 'i', 'n', 'g', 5, 'd', 'd', 'y', 'i', 'j', 5, 'd', 'd', 'y', 'i', 'c', 5, 'd', 'd', 'y', 'i', 'k', 5, 'd', 'd', 'y', 'i', 't', 5, 'd', 'd', 'y', 'i', 'p', 5, 'd', 'd', 'y', 'i', 'h', 3, 'd', 'd', 'i', 4, 'd', 'd', 'i', 'g', 5, 'd', 'd', 'i', 'g', 'g', 5, 'd', 'd', 'i', 'g', 's', 4, 'd', 'd', 'i', 'n', 5, 'd', 'd', 'i', 'n', 'j', 5, 'd', 'd', 'i', 'n', 'h', 4, 'd', 'd', 'i', 'd', 4, 'd', 'd', 'i', 'l', 5, 'd', 'd', 'i', 'l', 'g', 5, 'd', 'd', 'i', 'l', 'm', 5, 'd', 'd', 'i', 'l', 'b', 5, 'd', 'd', 'i', 'l', 's', 5, 'd', 'd', 'i', 'l', 't', 5, 'd', 'd', 'i', 'l', 'p', 5, 'd', 'd', 'i', 'l', 'h', 4, 'd', 'd', 'i', 'm', 4, 'd', 'd', 'i', 'b', 5, 'd', 'd', 'i', 'b', 's', 4, 'd', 'd', 'i', 's', 5, 'd', 'd', 'i', 's', 's', 5, 'd', 'd', 'i', 'n', 'g', 4, 'd', 'd', 'i', 'j', 4, 'd', 'd', 'i', 'c', 4, 'd', 'd', 'i', 'k', 4, 'd', 'd', 'i', 't', 4, 'd', 'd', 'i', 'p', 4, 'd', 'd', 'i', 'h', 2, 'r', 'a', 3, 'r', 'a', 'g', 4, 'r', 'a', 'g', 'g', 4, 'r', 'a', 'g', 's', 3, 'r', 'a', 'n', 4, 'r', 'a', 'n', 'j', 4, 'r', 'a', 'n', 'h', 3, 'r', 'a', 'd', 3, 'r', 'a', 'l', 4, 'r', 'a', 'l', 'g', 4, 'r', 'a', 'l', 'm', 4, 'r', 'a', 'l', 'b', 4, 'r', 'a', 'l', 's', 4, 'r', 'a', 'l', 't', 4, 'r', 'a', 'l', 'p', 4, 'r', 'a', 'l', 'h', 3, 'r', 'a', 'm', 3, 'r', 'a', 'b', 4, 'r', 'a', 'b', 's', 3, 'r', 'a', 's', 4, 'r', 'a', 's', 's', 4, 'r', 'a', 'n', 'g', 3, 'r', 'a', 'j', 3, 'r', 'a', 'c', 3, 'r', 'a', 'k', 3, 'r', 'a', 't', 3, 'r', 'a', 'p', 3, 'r', 'a', 'h', 3, 'r', 'a', 'e', 4, 'r', 'a', 'e', 'g', 5, 'r', 'a', 'e', 'g', 'g', 5, 'r', 'a', 'e', 'g', 's', 4, 'r', 'a', 'e', 'n', 5, 'r', 'a', 'e', 'n', 'j', 5, 'r', 'a', 'e', 'n', 'h', 4, 'r', 'a', 'e', 'd', 4, 'r', 'a', 'e', 'l', 5, 'r', 'a', 'e', 'l', 'g', 5, 'r', 'a', 'e', 'l', 'm', 5, 'r', 'a', 'e', 'l', 'b', 5, 'r', 'a', 'e', 'l', 's', 5, 'r', 'a', 'e', 'l', 't', 5, 'r', 'a', 'e', 'l', 'p', 5, 'r', 'a', 'e', 'l', 'h', 4, 'r', 'a', 'e', 'm', 4, 'r', 'a', 'e', 'b', 5, 'r', 'a', 'e', 'b', 's', 4, 'r', 'a', 'e', 's', 5, 'r', 'a', 'e', 's', 's', 5, 'r', 'a', 'e', 'n', 'g', 4, 'r', 'a', 'e', 'j', 4, 'r', 'a', 'e', 'c', 4, 'r', 'a', 'e', 'k', 4, 'r', 'a', 'e', 't', 4, 'r', 'a', 'e', 'p', 4, 'r', 'a', 'e', 'h', 3, 'r', 'y', 'a', 4, 'r', 'y', 'a', 'g', 5, 'r', 'y', 'a', 'g', 'g', 5, 'r', 'y', 'a', 'g', 's', 4, 'r', 'y', 'a', 'n', 5, 'r', 'y', 'a', 'n', 'j', 5, 'r', 'y', 'a', 'n', 'h', 4, 'r', 'y', 'a', 'd', 4, 'r', 'y', 'a', 'l', 5, 'r', 'y', 'a', 'l', 'g', 5, 'r', 'y', 'a', 'l', 'm', 5, 'r', 'y', 'a', 'l', 'b', 5, 'r', 'y', 'a', 'l', 's', 5, 'r', 'y', 'a', 'l', 't', 5, 'r', 'y', 'a', 'l', 'p', 5, 'r', 'y', 'a', 'l', 'h', 4, 'r', 'y', 'a', 'm', 4, 'r', 'y', 'a', 'b', 5, 'r', 'y', 'a', 'b', 's', 4, 'r', 'y', 'a', 's', 5, 'r', 'y', 'a', 's', 's', 5, 'r', 'y', 'a', 'n', 'g', 4, 'r', 'y', 'a', 'j', 4, 'r', 'y', 'a', 'c', 4, 'r', 'y', 'a', 'k', 4, 'r', 'y', 'a', 't', 4, 'r', 'y', 'a', 'p', 4, 'r', 'y', 'a', 'h', 4, 'r', 'y', 'a', 'e', 5, 'r', 'y', 'a', 'e', 'g', 6, 'r', 'y', 'a', 'e', 'g', 'g', 6, 'r', 'y', 'a', 'e', 'g', 's', 5, 'r', 'y', 'a', 'e', 'n', 6, 'r', 'y', 'a', 'e', 'n', 'j', 6, 'r', 'y', 'a', 'e', 'n', 'h', 5, 'r', 'y', 'a', 'e', 'd', 5, 'r', 'y', 'a', 'e', 'l', 6, 'r', 'y', 'a', 'e', 'l', 'g', 6, 'r', 'y', 'a', 'e', 'l', 'm', 6, 'r', 'y', 'a', 'e', 'l', 'b', 6, 'r', 'y', 'a', 'e', 'l', 's', 6, 'r', 'y', 'a', 'e', 'l', 't', 6, 'r', 'y', 'a', 'e', 'l', 'p', 6, 'r', 'y', 'a', 'e', 'l', 'h', 5, 'r', 'y', 'a', 'e', 'm', 5, 'r', 'y', 'a', 'e', 'b', 6, 'r', 'y', 'a', 'e', 'b', 's', 5, 'r', 'y', 'a', 'e', 's', 6, 'r', 'y', 'a', 'e', 's', 's', 6, 'r', 'y', 'a', 'e', 'n', 'g', 5, 'r', 'y', 'a', 'e', 'j', 5, 'r', 'y', 'a', 'e', 'c', 5, 'r', 'y', 'a', 'e', 'k', 5, 'r', 'y', 'a', 'e', 't', 5, 'r', 'y', 'a', 'e', 'p', 5, 'r', 'y', 'a', 'e', 'h', 3, 'r', 'e', 'o', 4, 'r', 'e', 'o', 'g', 5, 'r', 'e', 'o', 'g', 'g', 5, 'r', 'e', 'o', 'g', 's', 4, 'r', 'e', 'o', 'n', 5, 'r', 'e', 'o', 'n', 'j', 5, 'r', 'e', 'o', 'n', 'h', 4, 'r', 'e', 'o', 'd', 4, 'r', 'e', 'o', 'l', 5, 'r', 'e', 'o', 'l', 'g', 5, 'r', 'e', 'o', 'l', 'm', 5, 'r', 'e', 'o', 'l', 'b', 5, 'r', 'e', 'o', 'l', 's', 5, 'r', 'e', 'o', 'l', 't', 5, 'r', 'e', 'o', 'l', 'p', 5, 'r', 'e', 'o', 'l', 'h', 4, 'r', 'e', 'o', 'm', 4, 'r', 'e', 'o', 'b', 5, 'r', 'e', 'o', 'b', 's', 4, 'r', 'e', 'o', 's', 5, 'r', 'e', 'o', 's', 's', 5, 'r', 'e', 'o', 'n', 'g', 4, 'r', 'e', 'o', 'j', 4, 'r', 'e', 'o', 'c', 4, 'r', 'e', 'o', 'k', 4, 'r', 'e', 'o', 't', 4, 'r', 'e', 'o', 'p', 4, 'r', 'e', 'o', 'h', 2, 'r', 'e', 3, 'r', 'e', 'g', 4, 'r', 'e', 'g', 'g', 4, 'r', 'e', 'g', 's', 3, 'r', 'e', 'n', 4, 'r', 'e', 'n', 'j', 4, 'r', 'e', 'n', 'h', 3, 'r', 'e', 'd', 3, 'r', 'e', 'l', 4, 'r', 'e', 'l', 'g', 4, 'r', 'e', 'l', 'm', 4, 'r', 'e', 'l', 'b', 4, 'r', 'e', 'l', 's', 4, 'r', 'e', 'l', 't', 4, 'r', 'e', 'l', 'p', 4, 'r', 'e', 'l', 'h', 3, 'r', 'e', 'm', 3, 'r', 'e', 'b', 4, 'r', 'e', 'b', 's', 3, 'r', 'e', 's', 4, 'r', 'e', 's', 's', 4, 'r', 'e', 'n', 'g', 3, 'r', 'e', 'j', 3, 'r', 'e', 'c', 3, 'r', 'e', 'k', 3, 'r', 'e', 't', 3, 'r', 'e', 'p', 3, 'r', 'e', 'h', 4, 'r', 'y', 'e', 'o', 5, 'r', 'y', 'e', 'o', 'g', 6, 'r', 'y', 'e', 'o', 'g', 'g', 6, 'r', 'y', 'e', 'o', 'g', 's', 5, 'r', 'y', 'e', 'o', 'n', 6, 'r', 'y', 'e', 'o', 'n', 'j', 6, 'r', 'y', 'e', 'o', 'n', 'h', 5, 'r', 'y', 'e', 'o', 'd', 5, 'r', 'y', 'e', 'o', 'l', 6, 'r', 'y', 'e', 'o', 'l', 'g', 6, 'r', 'y', 'e', 'o', 'l', 'm', 6, 'r', 'y', 'e', 'o', 'l', 'b', 6, 'r', 'y', 'e', 'o', 'l', 's', 6, 'r', 'y', 'e', 'o', 'l', 't', 6, 'r', 'y', 'e', 'o', 'l', 'p', 6, 'r', 'y', 'e', 'o', 'l', 'h', 5, 'r', 'y', 'e', 'o', 'm', 5, 'r', 'y', 'e', 'o', 'b', 6, 'r', 'y', 'e', 'o', 'b', 's', 5, 'r', 'y', 'e', 'o', 's', 6, 'r', 'y', 'e', 'o', 's', 's', 6, 'r', 'y', 'e', 'o', 'n', 'g', 5, 'r', 'y', 'e', 'o', 'j', 5, 'r', 'y', 'e', 'o', 'c', 5, 'r', 'y', 'e', 'o', 'k', 5, 'r', 'y', 'e', 'o', 't', 5, 'r', 'y', 'e', 'o', 'p', 5, 'r', 'y', 'e', 'o', 'h', 3, 'r', 'y', 'e', 4, 'r', 'y', 'e', 'g', 5, 'r', 'y', 'e', 'g', 'g', 5, 'r', 'y', 'e', 'g', 's', 4, 'r', 'y', 'e', 'n', 5, 'r', 'y', 'e', 'n', 'j', 5, 'r', 'y', 'e', 'n', 'h', 4, 'r', 'y', 'e', 'd', 4, 'r', 'y', 'e', 'l', 5, 'r', 'y', 'e', 'l', 'g', 5, 'r', 'y', 'e', 'l', 'm', 5, 'r', 'y', 'e', 'l', 'b', 5, 'r', 'y', 'e', 'l', 's', 5, 'r', 'y', 'e', 'l', 't', 5, 'r', 'y', 'e', 'l', 'p', 5, 'r', 'y', 'e', 'l', 'h', 4, 'r', 'y', 'e', 'm', 4, 'r', 'y', 'e', 'b', 5, 'r', 'y', 'e', 'b', 's', 4, 'r', 'y', 'e', 's', 5, 'r', 'y', 'e', 's', 's', 5, 'r', 'y', 'e', 'n', 'g', 4, 'r', 'y', 'e', 'j', 4, 'r', 'y', 'e', 'c', 4, 'r', 'y', 'e', 'k', 4, 'r', 'y', 'e', 't', 4, 'r', 'y', 'e', 'p', 4, 'r', 'y', 'e', 'h', 2, 'r', 'o', 3, 'r', 'o', 'g', 4, 'r', 'o', 'g', 'g', 4, 'r', 'o', 'g', 's', 3, 'r', 'o', 'n', 4, 'r', 'o', 'n', 'j', 4, 'r', 'o', 'n', 'h', 3, 'r', 'o', 'd', 3, 'r', 'o', 'l', 4, 'r', 'o', 'l', 'g', 4, 'r', 'o', 'l', 'm', 4, 'r', 'o', 'l', 'b', 4, 'r', 'o', 'l', 's', 4, 'r', 'o', 'l', 't', 4, 'r', 'o', 'l', 'p', 4, 'r', 'o', 'l', 'h', 3, 'r', 'o', 'm', 3, 'r', 'o', 'b', 4, 'r', 'o', 'b', 's', 3, 'r', 'o', 's', 4, 'r', 'o', 's', 's', 4, 'r', 'o', 'n', 'g', 3, 'r', 'o', 'j', 3, 'r', 'o', 'c', 3, 'r', 'o', 'k', 3, 'r', 'o', 't', 3, 'r', 'o', 'p', 3, 'r', 'o', 'h', 3, 'r', 'w', 'a', 4, 'r', 'w', 'a', 'g', 5, 'r', 'w', 'a', 'g', 'g', 5, 'r', 'w', 'a', 'g', 's', 4, 'r', 'w', 'a', 'n', 5, 'r', 'w', 'a', 'n', 'j', 5, 'r', 'w', 'a', 'n', 'h', 4, 'r', 'w', 'a', 'd', 4, 'r', 'w', 'a', 'l', 5, 'r', 'w', 'a', 'l', 'g', 5, 'r', 'w', 'a', 'l', 'm', 5, 'r', 'w', 'a', 'l', 'b', 5, 'r', 'w', 'a', 'l', 's', 5, 'r', 'w', 'a', 'l', 't', 5, 'r', 'w', 'a', 'l', 'p', 5, 'r', 'w', 'a', 'l', 'h', 4, 'r', 'w', 'a', 'm', 4, 'r', 'w', 'a', 'b', 5, 'r', 'w', 'a', 'b', 's', 4, 'r', 'w', 'a', 's', 5, 'r', 'w', 'a', 's', 's', 5, 'r', 'w', 'a', 'n', 'g', 4, 'r', 'w', 'a', 'j', 4, 'r', 'w', 'a', 'c', 4, 'r', 'w', 'a', 'k', 4, 'r', 'w', 'a', 't', 4, 'r', 'w', 'a', 'p', 4, 'r', 'w', 'a', 'h', 4, 'r', 'w', 'a', 'e', 5, 'r', 'w', 'a', 'e', 'g', 6, 'r', 'w', 'a', 'e', 'g', 'g', 6, 'r', 'w', 'a', 'e', 'g', 's', 5, 'r', 'w', 'a', 'e', 'n', 6, 'r', 'w', 'a', 'e', 'n', 'j', 6, 'r', 'w', 'a', 'e', 'n', 'h', 5, 'r', 'w', 'a', 'e', 'd', 5, 'r', 'w', 'a', 'e', 'l', 6, 'r', 'w', 'a', 'e', 'l', 'g', 6, 'r', 'w', 'a', 'e', 'l', 'm', 6, 'r', 'w', 'a', 'e', 'l', 'b', 6, 'r', 'w', 'a', 'e', 'l', 's', 6, 'r', 'w', 'a', 'e', 'l', 't', 6, 'r', 'w', 'a', 'e', 'l', 'p', 6, 'r', 'w', 'a', 'e', 'l', 'h', 5, 'r', 'w', 'a', 'e', 'm', 5, 'r', 'w', 'a', 'e', 'b', 6, 'r', 'w', 'a', 'e', 'b', 's', 5, 'r', 'w', 'a', 'e', 's', 6, 'r', 'w', 'a', 'e', 's', 's', 6, 'r', 'w', 'a', 'e', 'n', 'g', 5, 'r', 'w', 'a', 'e', 'j', 5, 'r', 'w', 'a', 'e', 'c', 5, 'r', 'w', 'a', 'e', 'k', 5, 'r', 'w', 'a', 'e', 't', 5, 'r', 'w', 'a', 'e', 'p', 5, 'r', 'w', 'a', 'e', 'h', 3, 'r', 'o', 'e', 4, 'r', 'o', 'e', 'g', 5, 'r', 'o', 'e', 'g', 'g', 5, 'r', 'o', 'e', 'g', 's', 4, 'r', 'o', 'e', 'n', 5, 'r', 'o', 'e', 'n', 'j', 5, 'r', 'o', 'e', 'n', 'h', 4, 'r', 'o', 'e', 'd', 4, 'r', 'o', 'e', 'l', 5, 'r', 'o', 'e', 'l', 'g', 5, 'r', 'o', 'e', 'l', 'm', 5, 'r', 'o', 'e', 'l', 'b', 5, 'r', 'o', 'e', 'l', 's', 5, 'r', 'o', 'e', 'l', 't', 5, 'r', 'o', 'e', 'l', 'p', 5, 'r', 'o', 'e', 'l', 'h', 4, 'r', 'o', 'e', 'm', 4, 'r', 'o', 'e', 'b', 5, 'r', 'o', 'e', 'b', 's', 4, 'r', 'o', 'e', 's', 5, 'r', 'o', 'e', 's', 's', 5, 'r', 'o', 'e', 'n', 'g', 4, 'r', 'o', 'e', 'j', 4, 'r', 'o', 'e', 'c', 4, 'r', 'o', 'e', 'k', 4, 'r', 'o', 'e', 't', 4, 'r', 'o', 'e', 'p', 4, 'r', 'o', 'e', 'h', 3, 'r', 'y', 'o', 4, 'r', 'y', 'o', 'g', 5, 'r', 'y', 'o', 'g', 'g', 5, 'r', 'y', 'o', 'g', 's', 4, 'r', 'y', 'o', 'n', 5, 'r', 'y', 'o', 'n', 'j', 5, 'r', 'y', 'o', 'n', 'h', 4, 'r', 'y', 'o', 'd', 4, 'r', 'y', 'o', 'l', 5, 'r', 'y', 'o', 'l', 'g', 5, 'r', 'y', 'o', 'l', 'm', 5, 'r', 'y', 'o', 'l', 'b', 5, 'r', 'y', 'o', 'l', 's', 5, 'r', 'y', 'o', 'l', 't', 5, 'r', 'y', 'o', 'l', 'p', 5, 'r', 'y', 'o', 'l', 'h', 4, 'r', 'y', 'o', 'm', 4, 'r', 'y', 'o', 'b', 5, 'r', 'y', 'o', 'b', 's', 4, 'r', 'y', 'o', 's', 5, 'r', 'y', 'o', 's', 's', 5, 'r', 'y', 'o', 'n', 'g', 4, 'r', 'y', 'o', 'j', 4, 'r', 'y', 'o', 'c', 4, 'r', 'y', 'o', 'k', 4, 'r', 'y', 'o', 't', 4, 'r', 'y', 'o', 'p', 4, 'r', 'y', 'o', 'h', 2, 'r', 'u', 3, 'r', 'u', 'g', 4, 'r', 'u', 'g', 'g', 4, 'r', 'u', 'g', 's', 3, 'r', 'u', 'n', 4, 'r', 'u', 'n', 'j', 4, 'r', 'u', 'n', 'h', 3, 'r', 'u', 'd', 3, 'r', 'u', 'l', 4, 'r', 'u', 'l', 'g', 4, 'r', 'u', 'l', 'm', 4, 'r', 'u', 'l', 'b', 4, 'r', 'u', 'l', 's', 4, 'r', 'u', 'l', 't', 4, 'r', 'u', 'l', 'p', 4, 'r', 'u', 'l', 'h', 3, 'r', 'u', 'm', 3, 'r', 'u', 'b', 4, 'r', 'u', 'b', 's', 3, 'r', 'u', 's', 4, 'r', 'u', 's', 's', 4, 'r', 'u', 'n', 'g', 3, 'r', 'u', 'j', 3, 'r', 'u', 'c', 3, 'r', 'u', 'k', 3, 'r', 'u', 't', 3, 'r', 'u', 'p', 3, 'r', 'u', 'h', 4, 'r', 'w', 'e', 'o', 5, 'r', 'w', 'e', 'o', 'g', 6, 'r', 'w', 'e', 'o', 'g', 'g', 6, 'r', 'w', 'e', 'o', 'g', 's', 5, 'r', 'w', 'e', 'o', 'n', 6, 'r', 'w', 'e', 'o', 'n', 'j', 6, 'r', 'w', 'e', 'o', 'n', 'h', 5, 'r', 'w', 'e', 'o', 'd', 5, 'r', 'w', 'e', 'o', 'l', 6, 'r', 'w', 'e', 'o', 'l', 'g', 6, 'r', 'w', 'e', 'o', 'l', 'm', 6, 'r', 'w', 'e', 'o', 'l', 'b', 6, 'r', 'w', 'e', 'o', 'l', 's', 6, 'r', 'w', 'e', 'o', 'l', 't', 6, 'r', 'w', 'e', 'o', 'l', 'p', 6, 'r', 'w', 'e', 'o', 'l', 'h', 5, 'r', 'w', 'e', 'o', 'm', 5, 'r', 'w', 'e', 'o', 'b', 6, 'r', 'w', 'e', 'o', 'b', 's', 5, 'r', 'w', 'e', 'o', 's', 6, 'r', 'w', 'e', 'o', 's', 's', 6, 'r', 'w', 'e', 'o', 'n', 'g', 5, 'r', 'w', 'e', 'o', 'j', 5, 'r', 'w', 'e', 'o', 'c', 5, 'r', 'w', 'e', 'o', 'k', 5, 'r', 'w', 'e', 'o', 't', 5, 'r', 'w', 'e', 'o', 'p', 5, 'r', 'w', 'e', 'o', 'h', 3, 'r', 'w', 'e', 4, 'r', 'w', 'e', 'g', 5, 'r', 'w', 'e', 'g', 'g', 5, 'r', 'w', 'e', 'g', 's', 4, 'r', 'w', 'e', 'n', 5, 'r', 'w', 'e', 'n', 'j', 5, 'r', 'w', 'e', 'n', 'h', 4, 'r', 'w', 'e', 'd', 4, 'r', 'w', 'e', 'l', 5, 'r', 'w', 'e', 'l', 'g', 5, 'r', 'w', 'e', 'l', 'm', 5, 'r', 'w', 'e', 'l', 'b', 5, 'r', 'w', 'e', 'l', 's', 5, 'r', 'w', 'e', 'l', 't', 5, 'r', 'w', 'e', 'l', 'p', 5, 'r', 'w', 'e', 'l', 'h', 4, 'r', 'w', 'e', 'm', 4, 'r', 'w', 'e', 'b', 5, 'r', 'w', 'e', 'b', 's', 4, 'r', 'w', 'e', 's', 5, 'r', 'w', 'e', 's', 's', 5, 'r', 'w', 'e', 'n', 'g', 4, 'r', 'w', 'e', 'j', 4, 'r', 'w', 'e', 'c', 4, 'r', 'w', 'e', 'k', 4, 'r', 'w', 'e', 't', 4, 'r', 'w', 'e', 'p', 4, 'r', 'w', 'e', 'h', 3, 'r', 'w', 'i', 4, 'r', 'w', 'i', 'g', 5, 'r', 'w', 'i', 'g', 'g', 5, 'r', 'w', 'i', 'g', 's', 4, 'r', 'w', 'i', 'n', 5, 'r', 'w', 'i', 'n', 'j', 5, 'r', 'w', 'i', 'n', 'h', 4, 'r', 'w', 'i', 'd', 4, 'r', 'w', 'i', 'l', 5, 'r', 'w', 'i', 'l', 'g', 5, 'r', 'w', 'i', 'l', 'm', 5, 'r', 'w', 'i', 'l', 'b', 5, 'r', 'w', 'i', 'l', 's', 5, 'r', 'w', 'i', 'l', 't', 5, 'r', 'w', 'i', 'l', 'p', 5, 'r', 'w', 'i', 'l', 'h', 4, 'r', 'w', 'i', 'm', 4, 'r', 'w', 'i', 'b', 5, 'r', 'w', 'i', 'b', 's', 4, 'r', 'w', 'i', 's', 5, 'r', 'w', 'i', 's', 's', 5, 'r', 'w', 'i', 'n', 'g', 4, 'r', 'w', 'i', 'j', 4, 'r', 'w', 'i', 'c', 4, 'r', 'w', 'i', 'k', 4, 'r', 'w', 'i', 't', 4, 'r', 'w', 'i', 'p', 4, 'r', 'w', 'i', 'h', 3, 'r', 'y', 'u', 4, 'r', 'y', 'u', 'g', 5, 'r', 'y', 'u', 'g', 'g', 5, 'r', 'y', 'u', 'g', 's', 4, 'r', 'y', 'u', 'n', 5, 'r', 'y', 'u', 'n', 'j', 5, 'r', 'y', 'u', 'n', 'h', 4, 'r', 'y', 'u', 'd', 4, 'r', 'y', 'u', 'l', 5, 'r', 'y', 'u', 'l', 'g', 5, 'r', 'y', 'u', 'l', 'm', 5, 'r', 'y', 'u', 'l', 'b', 5, 'r', 'y', 'u', 'l', 's', 5, 'r', 'y', 'u', 'l', 't', 5, 'r', 'y', 'u', 'l', 'p', 5, 'r', 'y', 'u', 'l', 'h', 4, 'r', 'y', 'u', 'm', 4, 'r', 'y', 'u', 'b', 5, 'r', 'y', 'u', 'b', 's', 4, 'r', 'y', 'u', 's', 5, 'r', 'y', 'u', 's', 's', 5, 'r', 'y', 'u', 'n', 'g', 4, 'r', 'y', 'u', 'j', 4, 'r', 'y', 'u', 'c', 4, 'r', 'y', 'u', 'k', 4, 'r', 'y', 'u', 't', 4, 'r', 'y', 'u', 'p', 4, 'r', 'y', 'u', 'h', 3, 'r', 'e', 'u', 4, 'r', 'e', 'u', 'g', 5, 'r', 'e', 'u', 'g', 'g', 5, 'r', 'e', 'u', 'g', 's', 4, 'r', 'e', 'u', 'n', 5, 'r', 'e', 'u', 'n', 'j', 5, 'r', 'e', 'u', 'n', 'h', 4, 'r', 'e', 'u', 'd', 4, 'r', 'e', 'u', 'l', 5, 'r', 'e', 'u', 'l', 'g', 5, 'r', 'e', 'u', 'l', 'm', 5, 'r', 'e', 'u', 'l', 'b', 5, 'r', 'e', 'u', 'l', 's', 5, 'r', 'e', 'u', 'l', 't', 5, 'r', 'e', 'u', 'l', 'p', 5, 'r', 'e', 'u', 'l', 'h', 4, 'r', 'e', 'u', 'm', 4, 'r', 'e', 'u', 'b', 5, 'r', 'e', 'u', 'b', 's', 4, 'r', 'e', 'u', 's', 5, 'r', 'e', 'u', 's', 's', 5, 'r', 'e', 'u', 'n', 'g', 4, 'r', 'e', 'u', 'j', 4, 'r', 'e', 'u', 'c', 4, 'r', 'e', 'u', 'k', 4, 'r', 'e', 'u', 't', 4, 'r', 'e', 'u', 'p', 4, 'r', 'e', 'u', 'h', 3, 'r', 'y', 'i', 4, 'r', 'y', 'i', 'g', 5, 'r', 'y', 'i', 'g', 'g', 5, 'r', 'y', 'i', 'g', 's', 4, 'r', 'y', 'i', 'n', 5, 'r', 'y', 'i', 'n', 'j', 5, 'r', 'y', 'i', 'n', 'h', 4, 'r', 'y', 'i', 'd', 4, 'r', 'y', 'i', 'l', 5, 'r', 'y', 'i', 'l', 'g', 5, 'r', 'y', 'i', 'l', 'm', 5, 'r', 'y', 'i', 'l', 'b', 5, 'r', 'y', 'i', 'l', 's', 5, 'r', 'y', 'i', 'l', 't', 5, 'r', 'y', 'i', 'l', 'p', 5, 'r', 'y', 'i', 'l', 'h', 4, 'r', 'y', 'i', 'm', 4, 'r', 'y', 'i', 'b', 5, 'r', 'y', 'i', 'b', 's', 4, 'r', 'y', 'i', 's', 5, 'r', 'y', 'i', 's', 's', 5, 'r', 'y', 'i', 'n', 'g', 4, 'r', 'y', 'i', 'j', 4, 'r', 'y', 'i', 'c', 4, 'r', 'y', 'i', 'k', 4, 'r', 'y', 'i', 't', 4, 'r', 'y', 'i', 'p', 4, 'r', 'y', 'i', 'h', 2, 'r', 'i', 3, 'r', 'i', 'g', 4, 'r', 'i', 'g', 'g', 4, 'r', 'i', 'g', 's', 3, 'r', 'i', 'n', 4, 'r', 'i', 'n', 'j', 4, 'r', 'i', 'n', 'h', 3, 'r', 'i', 'd', 3, 'r', 'i', 'l', 4, 'r', 'i', 'l', 'g', 4, 'r', 'i', 'l', 'm', 4, 'r', 'i', 'l', 'b', 4, 'r', 'i', 'l', 's', 4, 'r', 'i', 'l', 't', 4, 'r', 'i', 'l', 'p', 4, 'r', 'i', 'l', 'h', 3, 'r', 'i', 'm', 3, 'r', 'i', 'b', 4, 'r', 'i', 'b', 's', 3, 'r', 'i', 's', 4, 'r', 'i', 's', 's', 4, 'r', 'i', 'n', 'g', 3, 'r', 'i', 'j', 3, 'r', 'i', 'c', 3, 'r', 'i', 'k', 3, 'r', 'i', 't', 3, 'r', 'i', 'p', 3, 'r', 'i', 'h', 2, 'm', 'a', 3, 'm', 'a', 'g', 4, 'm', 'a', 'g', 'g', 4, 'm', 'a', 'g', 's', 3, 'm', 'a', 'n', 4, 'm', 'a', 'n', 'j', 4, 'm', 'a', 'n', 'h', 3, 'm', 'a', 'd', 3, 'm', 'a', 'l', 4, 'm', 'a', 'l', 'g', 4, 'm', 'a', 'l', 'm', 4, 'm', 'a', 'l', 'b', 4, 'm', 'a', 'l', 's', 4, 'm', 'a', 'l', 't', 4, 'm', 'a', 'l', 'p', 4, 'm', 'a', 'l', 'h', 3, 'm', 'a', 'm', 3, 'm', 'a', 'b', 4, 'm', 'a', 'b', 's', 3, 'm', 'a', 's', 4, 'm', 'a', 's', 's', 4, 'm', 'a', 'n', 'g', 3, 'm', 'a', 'j', 3, 'm', 'a', 'c', 3, 'm', 'a', 'k', 3, 'm', 'a', 't', 3, 'm', 'a', 'p', 3, 'm', 'a', 'h', 3, 'm', 'a', 'e', 4, 'm', 'a', 'e', 'g', 5, 'm', 'a', 'e', 'g', 'g', 5, 'm', 'a', 'e', 'g', 's', 4, 'm', 'a', 'e', 'n', 5, 'm', 'a', 'e', 'n', 'j', 5, 'm', 'a', 'e', 'n', 'h', 4, 'm', 'a', 'e', 'd', 4, 'm', 'a', 'e', 'l', 5, 'm', 'a', 'e', 'l', 'g', 5, 'm', 'a', 'e', 'l', 'm', 5, 'm', 'a', 'e', 'l', 'b', 5, 'm', 'a', 'e', 'l', 's', 5, 'm', 'a', 'e', 'l', 't', 5, 'm', 'a', 'e', 'l', 'p', 5, 'm', 'a', 'e', 'l', 'h', 4, 'm', 'a', 'e', 'm', 4, 'm', 'a', 'e', 'b', 5, 'm', 'a', 'e', 'b', 's', 4, 'm', 'a', 'e', 's', 5, 'm', 'a', 'e', 's', 's', 5, 'm', 'a', 'e', 'n', 'g', 4, 'm', 'a', 'e', 'j', 4, 'm', 'a', 'e', 'c', 4, 'm', 'a', 'e', 'k', 4, 'm', 'a', 'e', 't', 4, 'm', 'a', 'e', 'p', 4, 'm', 'a', 'e', 'h', 3, 'm', 'y', 'a', 4, 'm', 'y', 'a', 'g', 5, 'm', 'y', 'a', 'g', 'g', 5, 'm', 'y', 'a', 'g', 's', 4, 'm', 'y', 'a', 'n', 5, 'm', 'y', 'a', 'n', 'j', 5, 'm', 'y', 'a', 'n', 'h', 4, 'm', 'y', 'a', 'd', 4, 'm', 'y', 'a', 'l', 5, 'm', 'y', 'a', 'l', 'g', 5, 'm', 'y', 'a', 'l', 'm', 5, 'm', 'y', 'a', 'l', 'b', 5, 'm', 'y', 'a', 'l', 's', 5, 'm', 'y', 'a', 'l', 't', 5, 'm', 'y', 'a', 'l', 'p', 5, 'm', 'y', 'a', 'l', 'h', 4, 'm', 'y', 'a', 'm', 4, 'm', 'y', 'a', 'b', 5, 'm', 'y', 'a', 'b', 's', 4, 'm', 'y', 'a', 's', 5, 'm', 'y', 'a', 's', 's', 5, 'm', 'y', 'a', 'n', 'g', 4, 'm', 'y', 'a', 'j', 4, 'm', 'y', 'a', 'c', 4, 'm', 'y', 'a', 'k', 4, 'm', 'y', 'a', 't', 4, 'm', 'y', 'a', 'p', 4, 'm', 'y', 'a', 'h', 4, 'm', 'y', 'a', 'e', 5, 'm', 'y', 'a', 'e', 'g', 6, 'm', 'y', 'a', 'e', 'g', 'g', 6, 'm', 'y', 'a', 'e', 'g', 's', 5, 'm', 'y', 'a', 'e', 'n', 6, 'm', 'y', 'a', 'e', 'n', 'j', 6, 'm', 'y', 'a', 'e', 'n', 'h', 5, 'm', 'y', 'a', 'e', 'd', 5, 'm', 'y', 'a', 'e', 'l', 6, 'm', 'y', 'a', 'e', 'l', 'g', 6, 'm', 'y', 'a', 'e', 'l', 'm', 6, 'm', 'y', 'a', 'e', 'l', 'b', 6, 'm', 'y', 'a', 'e', 'l', 's', 6, 'm', 'y', 'a', 'e', 'l', 't', 6, 'm', 'y', 'a', 'e', 'l', 'p', 6, 'm', 'y', 'a', 'e', 'l', 'h', 5, 'm', 'y', 'a', 'e', 'm', 5, 'm', 'y', 'a', 'e', 'b', 6, 'm', 'y', 'a', 'e', 'b', 's', 5, 'm', 'y', 'a', 'e', 's', 6, 'm', 'y', 'a', 'e', 's', 's', 6, 'm', 'y', 'a', 'e', 'n', 'g', 5, 'm', 'y', 'a', 'e', 'j', 5, 'm', 'y', 'a', 'e', 'c', 5, 'm', 'y', 'a', 'e', 'k', 5, 'm', 'y', 'a', 'e', 't', 5, 'm', 'y', 'a', 'e', 'p', 5, 'm', 'y', 'a', 'e', 'h', 3, 'm', 'e', 'o', 4, 'm', 'e', 'o', 'g', 5, 'm', 'e', 'o', 'g', 'g', 5, 'm', 'e', 'o', 'g', 's', 4, 'm', 'e', 'o', 'n', 5, 'm', 'e', 'o', 'n', 'j', 5, 'm', 'e', 'o', 'n', 'h', 4, 'm', 'e', 'o', 'd', 4, 'm', 'e', 'o', 'l', 5, 'm', 'e', 'o', 'l', 'g', 5, 'm', 'e', 'o', 'l', 'm', 5, 'm', 'e', 'o', 'l', 'b', 5, 'm', 'e', 'o', 'l', 's', 5, 'm', 'e', 'o', 'l', 't', 5, 'm', 'e', 'o', 'l', 'p', 5, 'm', 'e', 'o', 'l', 'h', 4, 'm', 'e', 'o', 'm', 4, 'm', 'e', 'o', 'b', 5, 'm', 'e', 'o', 'b', 's', 4, 'm', 'e', 'o', 's', 5, 'm', 'e', 'o', 's', 's', 5, 'm', 'e', 'o', 'n', 'g', 4, 'm', 'e', 'o', 'j', 4, 'm', 'e', 'o', 'c', 4, 'm', 'e', 'o', 'k', 4, 'm', 'e', 'o', 't', 4, 'm', 'e', 'o', 'p', 4, 'm', 'e', 'o', 'h', 2, 'm', 'e', 3, 'm', 'e', 'g', 4, 'm', 'e', 'g', 'g', 4, 'm', 'e', 'g', 's', 3, 'm', 'e', 'n', 4, 'm', 'e', 'n', 'j', 4, 'm', 'e', 'n', 'h', 3, 'm', 'e', 'd', 3, 'm', 'e', 'l', 4, 'm', 'e', 'l', 'g', 4, 'm', 'e', 'l', 'm', 4, 'm', 'e', 'l', 'b', 4, 'm', 'e', 'l', 's', 4, 'm', 'e', 'l', 't', 4, 'm', 'e', 'l', 'p', 4, 'm', 'e', 'l', 'h', 3, 'm', 'e', 'm', 3, 'm', 'e', 'b', 4, 'm', 'e', 'b', 's', 3, 'm', 'e', 's', 4, 'm', 'e', 's', 's', 4, 'm', 'e', 'n', 'g', 3, 'm', 'e', 'j', 3, 'm', 'e', 'c', 3, 'm', 'e', 'k', 3, 'm', 'e', 't', 3, 'm', 'e', 'p', 3, 'm', 'e', 'h', 4, 'm', 'y', 'e', 'o', 5, 'm', 'y', 'e', 'o', 'g', 6, 'm', 'y', 'e', 'o', 'g', 'g', 6, 'm', 'y', 'e', 'o', 'g', 's', 5, 'm', 'y', 'e', 'o', 'n', 6, 'm', 'y', 'e', 'o', 'n', 'j', 6, 'm', 'y', 'e', 'o', 'n', 'h', 5, 'm', 'y', 'e', 'o', 'd', 5, 'm', 'y', 'e', 'o', 'l', 6, 'm', 'y', 'e', 'o', 'l', 'g', 6, 'm', 'y', 'e', 'o', 'l', 'm', 6, 'm', 'y', 'e', 'o', 'l', 'b', 6, 'm', 'y', 'e', 'o', 'l', 's', 6, 'm', 'y', 'e', 'o', 'l', 't', 6, 'm', 'y', 'e', 'o', 'l', 'p', 6, 'm', 'y', 'e', 'o', 'l', 'h', 5, 'm', 'y', 'e', 'o', 'm', 5, 'm', 'y', 'e', 'o', 'b', 6, 'm', 'y', 'e', 'o', 'b', 's', 5, 'm', 'y', 'e', 'o', 's', 6, 'm', 'y', 'e', 'o', 's', 's', 6, 'm', 'y', 'e', 'o', 'n', 'g', 5, 'm', 'y', 'e', 'o', 'j', 5, 'm', 'y', 'e', 'o', 'c', 5, 'm', 'y', 'e', 'o', 'k', 5, 'm', 'y', 'e', 'o', 't', 5, 'm', 'y', 'e', 'o', 'p', 5, 'm', 'y', 'e', 'o', 'h', 3, 'm', 'y', 'e', 4, 'm', 'y', 'e', 'g', 5, 'm', 'y', 'e', 'g', 'g', 5, 'm', 'y', 'e', 'g', 's', 4, 'm', 'y', 'e', 'n', 5, 'm', 'y', 'e', 'n', 'j', 5, 'm', 'y', 'e', 'n', 'h', 4, 'm', 'y', 'e', 'd', 4, 'm', 'y', 'e', 'l', 5, 'm', 'y', 'e', 'l', 'g', 5, 'm', 'y', 'e', 'l', 'm', 5, 'm', 'y', 'e', 'l', 'b', 5, 'm', 'y', 'e', 'l', 's', 5, 'm', 'y', 'e', 'l', 't', 5, 'm', 'y', 'e', 'l', 'p', 5, 'm', 'y', 'e', 'l', 'h', 4, 'm', 'y', 'e', 'm', 4, 'm', 'y', 'e', 'b', 5, 'm', 'y', 'e', 'b', 's', 4, 'm', 'y', 'e', 's', 5, 'm', 'y', 'e', 's', 's', 5, 'm', 'y', 'e', 'n', 'g', 4, 'm', 'y', 'e', 'j', 4, 'm', 'y', 'e', 'c', 4, 'm', 'y', 'e', 'k', 4, 'm', 'y', 'e', 't', 4, 'm', 'y', 'e', 'p', 4, 'm', 'y', 'e', 'h', 2, 'm', 'o', 3, 'm', 'o', 'g', 4, 'm', 'o', 'g', 'g', 4, 'm', 'o', 'g', 's', 3, 'm', 'o', 'n', 4, 'm', 'o', 'n', 'j', 4, 'm', 'o', 'n', 'h', 3, 'm', 'o', 'd', 3, 'm', 'o', 'l', 4, 'm', 'o', 'l', 'g', 4, 'm', 'o', 'l', 'm', 4, 'm', 'o', 'l', 'b', 4, 'm', 'o', 'l', 's', 4, 'm', 'o', 'l', 't', 4, 'm', 'o', 'l', 'p', 4, 'm', 'o', 'l', 'h', 3, 'm', 'o', 'm', 3, 'm', 'o', 'b', 4, 'm', 'o', 'b', 's', 3, 'm', 'o', 's', 4, 'm', 'o', 's', 's', 4, 'm', 'o', 'n', 'g', 3, 'm', 'o', 'j', 3, 'm', 'o', 'c', 3, 'm', 'o', 'k', 3, 'm', 'o', 't', 3, 'm', 'o', 'p', 3, 'm', 'o', 'h', 3, 'm', 'w', 'a', 4, 'm', 'w', 'a', 'g', 5, 'm', 'w', 'a', 'g', 'g', 5, 'm', 'w', 'a', 'g', 's', 4, 'm', 'w', 'a', 'n', 5, 'm', 'w', 'a', 'n', 'j', 5, 'm', 'w', 'a', 'n', 'h', 4, 'm', 'w', 'a', 'd', 4, 'm', 'w', 'a', 'l', 5, 'm', 'w', 'a', 'l', 'g', 5, 'm', 'w', 'a', 'l', 'm', 5, 'm', 'w', 'a', 'l', 'b', 5, 'm', 'w', 'a', 'l', 's', 5, 'm', 'w', 'a', 'l', 't', 5, 'm', 'w', 'a', 'l', 'p', 5, 'm', 'w', 'a', 'l', 'h', 4, 'm', 'w', 'a', 'm', 4, 'm', 'w', 'a', 'b', 5, 'm', 'w', 'a', 'b', 's', 4, 'm', 'w', 'a', 's', 5, 'm', 'w', 'a', 's', 's', 5, 'm', 'w', 'a', 'n', 'g', 4, 'm', 'w', 'a', 'j', 4, 'm', 'w', 'a', 'c', 4, 'm', 'w', 'a', 'k', 4, 'm', 'w', 'a', 't', 4, 'm', 'w', 'a', 'p', 4, 'm', 'w', 'a', 'h', 4, 'm', 'w', 'a', 'e', 5, 'm', 'w', 'a', 'e', 'g', 6, 'm', 'w', 'a', 'e', 'g', 'g', 6, 'm', 'w', 'a', 'e', 'g', 's', 5, 'm', 'w', 'a', 'e', 'n', 6, 'm', 'w', 'a', 'e', 'n', 'j', 6, 'm', 'w', 'a', 'e', 'n', 'h', 5, 'm', 'w', 'a', 'e', 'd', 5, 'm', 'w', 'a', 'e', 'l', 6, 'm', 'w', 'a', 'e', 'l', 'g', 6, 'm', 'w', 'a', 'e', 'l', 'm', 6, 'm', 'w', 'a', 'e', 'l', 'b', 6, 'm', 'w', 'a', 'e', 'l', 's', 6, 'm', 'w', 'a', 'e', 'l', 't', 6, 'm', 'w', 'a', 'e', 'l', 'p', 6, 'm', 'w', 'a', 'e', 'l', 'h', 5, 'm', 'w', 'a', 'e', 'm', 5, 'm', 'w', 'a', 'e', 'b', 6, 'm', 'w', 'a', 'e', 'b', 's', 5, 'm', 'w', 'a', 'e', 's', 6, 'm', 'w', 'a', 'e', 's', 's', 6, 'm', 'w', 'a', 'e', 'n', 'g', 5, 'm', 'w', 'a', 'e', 'j', 5, 'm', 'w', 'a', 'e', 'c', 5, 'm', 'w', 'a', 'e', 'k', 5, 'm', 'w', 'a', 'e', 't', 5, 'm', 'w', 'a', 'e', 'p', 5, 'm', 'w', 'a', 'e', 'h', 3, 'm', 'o', 'e', 4, 'm', 'o', 'e', 'g', 5, 'm', 'o', 'e', 'g', 'g', 5, 'm', 'o', 'e', 'g', 's', 4, 'm', 'o', 'e', 'n', 5, 'm', 'o', 'e', 'n', 'j', 5, 'm', 'o', 'e', 'n', 'h', 4, 'm', 'o', 'e', 'd', 4, 'm', 'o', 'e', 'l', 5, 'm', 'o', 'e', 'l', 'g', 5, 'm', 'o', 'e', 'l', 'm', 5, 'm', 'o', 'e', 'l', 'b', 5, 'm', 'o', 'e', 'l', 's', 5, 'm', 'o', 'e', 'l', 't', 5, 'm', 'o', 'e', 'l', 'p', 5, 'm', 'o', 'e', 'l', 'h', 4, 'm', 'o', 'e', 'm', 4, 'm', 'o', 'e', 'b', 5, 'm', 'o', 'e', 'b', 's', 4, 'm', 'o', 'e', 's', 5, 'm', 'o', 'e', 's', 's', 5, 'm', 'o', 'e', 'n', 'g', 4, 'm', 'o', 'e', 'j', 4, 'm', 'o', 'e', 'c', 4, 'm', 'o', 'e', 'k', 4, 'm', 'o', 'e', 't', 4, 'm', 'o', 'e', 'p', 4, 'm', 'o', 'e', 'h', 3, 'm', 'y', 'o', 4, 'm', 'y', 'o', 'g', 5, 'm', 'y', 'o', 'g', 'g', 5, 'm', 'y', 'o', 'g', 's', 4, 'm', 'y', 'o', 'n', 5, 'm', 'y', 'o', 'n', 'j', 5, 'm', 'y', 'o', 'n', 'h', 4, 'm', 'y', 'o', 'd', 4, 'm', 'y', 'o', 'l', 5, 'm', 'y', 'o', 'l', 'g', 5, 'm', 'y', 'o', 'l', 'm', 5, 'm', 'y', 'o', 'l', 'b', 5, 'm', 'y', 'o', 'l', 's', 5, 'm', 'y', 'o', 'l', 't', 5, 'm', 'y', 'o', 'l', 'p', 5, 'm', 'y', 'o', 'l', 'h', 4, 'm', 'y', 'o', 'm', 4, 'm', 'y', 'o', 'b', 5, 'm', 'y', 'o', 'b', 's', 4, 'm', 'y', 'o', 's', 5, 'm', 'y', 'o', 's', 's', 5, 'm', 'y', 'o', 'n', 'g', 4, 'm', 'y', 'o', 'j', 4, 'm', 'y', 'o', 'c', 4, 'm', 'y', 'o', 'k', 4, 'm', 'y', 'o', 't', 4, 'm', 'y', 'o', 'p', 4, 'm', 'y', 'o', 'h', 2, 'm', 'u', 3, 'm', 'u', 'g', 4, 'm', 'u', 'g', 'g', 4, 'm', 'u', 'g', 's', 3, 'm', 'u', 'n', 4, 'm', 'u', 'n', 'j', 4, 'm', 'u', 'n', 'h', 3, 'm', 'u', 'd', 3, 'm', 'u', 'l', 4, 'm', 'u', 'l', 'g', 4, 'm', 'u', 'l', 'm', 4, 'm', 'u', 'l', 'b', 4, 'm', 'u', 'l', 's', 4, 'm', 'u', 'l', 't', 4, 'm', 'u', 'l', 'p', 4, 'm', 'u', 'l', 'h', 3, 'm', 'u', 'm', 3, 'm', 'u', 'b', 4, 'm', 'u', 'b', 's', 3, 'm', 'u', 's', 4, 'm', 'u', 's', 's', 4, 'm', 'u', 'n', 'g', 3, 'm', 'u', 'j', 3, 'm', 'u', 'c', 3, 'm', 'u', 'k', 3, 'm', 'u', 't', 3, 'm', 'u', 'p', 3, 'm', 'u', 'h', 4, 'm', 'w', 'e', 'o', 5, 'm', 'w', 'e', 'o', 'g', 6, 'm', 'w', 'e', 'o', 'g', 'g', 6, 'm', 'w', 'e', 'o', 'g', 's', 5, 'm', 'w', 'e', 'o', 'n', 6, 'm', 'w', 'e', 'o', 'n', 'j', 6, 'm', 'w', 'e', 'o', 'n', 'h', 5, 'm', 'w', 'e', 'o', 'd', 5, 'm', 'w', 'e', 'o', 'l', 6, 'm', 'w', 'e', 'o', 'l', 'g', 6, 'm', 'w', 'e', 'o', 'l', 'm', 6, 'm', 'w', 'e', 'o', 'l', 'b', 6, 'm', 'w', 'e', 'o', 'l', 's', 6, 'm', 'w', 'e', 'o', 'l', 't', 6, 'm', 'w', 'e', 'o', 'l', 'p', 6, 'm', 'w', 'e', 'o', 'l', 'h', 5, 'm', 'w', 'e', 'o', 'm', 5, 'm', 'w', 'e', 'o', 'b', 6, 'm', 'w', 'e', 'o', 'b', 's', 5, 'm', 'w', 'e', 'o', 's', 6, 'm', 'w', 'e', 'o', 's', 's', 6, 'm', 'w', 'e', 'o', 'n', 'g', 5, 'm', 'w', 'e', 'o', 'j', 5, 'm', 'w', 'e', 'o', 'c', 5, 'm', 'w', 'e', 'o', 'k', 5, 'm', 'w', 'e', 'o', 't', 5, 'm', 'w', 'e', 'o', 'p', 5, 'm', 'w', 'e', 'o', 'h', 3, 'm', 'w', 'e', 4, 'm', 'w', 'e', 'g', 5, 'm', 'w', 'e', 'g', 'g', 5, 'm', 'w', 'e', 'g', 's', 4, 'm', 'w', 'e', 'n', 5, 'm', 'w', 'e', 'n', 'j', 5, 'm', 'w', 'e', 'n', 'h', 4, 'm', 'w', 'e', 'd', 4, 'm', 'w', 'e', 'l', 5, 'm', 'w', 'e', 'l', 'g', 5, 'm', 'w', 'e', 'l', 'm', 5, 'm', 'w', 'e', 'l', 'b', 5, 'm', 'w', 'e', 'l', 's', 5, 'm', 'w', 'e', 'l', 't', 5, 'm', 'w', 'e', 'l', 'p', 5, 'm', 'w', 'e', 'l', 'h', 4, 'm', 'w', 'e', 'm', 4, 'm', 'w', 'e', 'b', 5, 'm', 'w', 'e', 'b', 's', 4, 'm', 'w', 'e', 's', 5, 'm', 'w', 'e', 's', 's', 5, 'm', 'w', 'e', 'n', 'g', 4, 'm', 'w', 'e', 'j', 4, 'm', 'w', 'e', 'c', 4, 'm', 'w', 'e', 'k', 4, 'm', 'w', 'e', 't', 4, 'm', 'w', 'e', 'p', 4, 'm', 'w', 'e', 'h', 3, 'm', 'w', 'i', 4, 'm', 'w', 'i', 'g', 5, 'm', 'w', 'i', 'g', 'g', 5, 'm', 'w', 'i', 'g', 's', 4, 'm', 'w', 'i', 'n', 5, 'm', 'w', 'i', 'n', 'j', 5, 'm', 'w', 'i', 'n', 'h', 4, 'm', 'w', 'i', 'd', 4, 'm', 'w', 'i', 'l', 5, 'm', 'w', 'i', 'l', 'g', 5, 'm', 'w', 'i', 'l', 'm', 5, 'm', 'w', 'i', 'l', 'b', 5, 'm', 'w', 'i', 'l', 's', 5, 'm', 'w', 'i', 'l', 't', 5, 'm', 'w', 'i', 'l', 'p', 5, 'm', 'w', 'i', 'l', 'h', 4, 'm', 'w', 'i', 'm', 4, 'm', 'w', 'i', 'b', 5, 'm', 'w', 'i', 'b', 's', 4, 'm', 'w', 'i', 's', 5, 'm', 'w', 'i', 's', 's', 5, 'm', 'w', 'i', 'n', 'g', 4, 'm', 'w', 'i', 'j', 4, 'm', 'w', 'i', 'c', 4, 'm', 'w', 'i', 'k', 4, 'm', 'w', 'i', 't', 4, 'm', 'w', 'i', 'p', 4, 'm', 'w', 'i', 'h', 3, 'm', 'y', 'u', 4, 'm', 'y', 'u', 'g', 5, 'm', 'y', 'u', 'g', 'g', 5, 'm', 'y', 'u', 'g', 's', 4, 'm', 'y', 'u', 'n', 5, 'm', 'y', 'u', 'n', 'j', 5, 'm', 'y', 'u', 'n', 'h', 4, 'm', 'y', 'u', 'd', 4, 'm', 'y', 'u', 'l', 5, 'm', 'y', 'u', 'l', 'g', 5, 'm', 'y', 'u', 'l', 'm', 5, 'm', 'y', 'u', 'l', 'b', 5, 'm', 'y', 'u', 'l', 's', 5, 'm', 'y', 'u', 'l', 't', 5, 'm', 'y', 'u', 'l', 'p', 5, 'm', 'y', 'u', 'l', 'h', 4, 'm', 'y', 'u', 'm', 4, 'm', 'y', 'u', 'b', 5, 'm', 'y', 'u', 'b', 's', 4, 'm', 'y', 'u', 's', 5, 'm', 'y', 'u', 's', 's', 5, 'm', 'y', 'u', 'n', 'g', 4, 'm', 'y', 'u', 'j', 4, 'm', 'y', 'u', 'c', 4, 'm', 'y', 'u', 'k', 4, 'm', 'y', 'u', 't', 4, 'm', 'y', 'u', 'p', 4, 'm', 'y', 'u', 'h', 3, 'm', 'e', 'u', 4, 'm', 'e', 'u', 'g', 5, 'm', 'e', 'u', 'g', 'g', 5, 'm', 'e', 'u', 'g', 's', 4, 'm', 'e', 'u', 'n', 5, 'm', 'e', 'u', 'n', 'j', 5, 'm', 'e', 'u', 'n', 'h', 4, 'm', 'e', 'u', 'd', 4, 'm', 'e', 'u', 'l', 5, 'm', 'e', 'u', 'l', 'g', 5, 'm', 'e', 'u', 'l', 'm', 5, 'm', 'e', 'u', 'l', 'b', 5, 'm', 'e', 'u', 'l', 's', 5, 'm', 'e', 'u', 'l', 't', 5, 'm', 'e', 'u', 'l', 'p', 5, 'm', 'e', 'u', 'l', 'h', 4, 'm', 'e', 'u', 'm', 4, 'm', 'e', 'u', 'b', 5, 'm', 'e', 'u', 'b', 's', 4, 'm', 'e', 'u', 's', 5, 'm', 'e', 'u', 's', 's', 5, 'm', 'e', 'u', 'n', 'g', 4, 'm', 'e', 'u', 'j', 4, 'm', 'e', 'u', 'c', 4, 'm', 'e', 'u', 'k', 4, 'm', 'e', 'u', 't', 4, 'm', 'e', 'u', 'p', 4, 'm', 'e', 'u', 'h', 3, 'm', 'y', 'i', 4, 'm', 'y', 'i', 'g', 5, 'm', 'y', 'i', 'g', 'g', 5, 'm', 'y', 'i', 'g', 's', 4, 'm', 'y', 'i', 'n', 5, 'm', 'y', 'i', 'n', 'j', 5, 'm', 'y', 'i', 'n', 'h', 4, 'm', 'y', 'i', 'd', 4, 'm', 'y', 'i', 'l', 5, 'm', 'y', 'i', 'l', 'g', 5, 'm', 'y', 'i', 'l', 'm', 5, 'm', 'y', 'i', 'l', 'b', 5, 'm', 'y', 'i', 'l', 's', 5, 'm', 'y', 'i', 'l', 't', 5, 'm', 'y', 'i', 'l', 'p', 5, 'm', 'y', 'i', 'l', 'h', 4, 'm', 'y', 'i', 'm', 4, 'm', 'y', 'i', 'b', 5, 'm', 'y', 'i', 'b', 's', 4, 'm', 'y', 'i', 's', 5, 'm', 'y', 'i', 's', 's', 5, 'm', 'y', 'i', 'n', 'g', 4, 'm', 'y', 'i', 'j', 4, 'm', 'y', 'i', 'c', 4, 'm', 'y', 'i', 'k', 4, 'm', 'y', 'i', 't', 4, 'm', 'y', 'i', 'p', 4, 'm', 'y', 'i', 'h', 2, 'm', 'i', 3, 'm', 'i', 'g', 4, 'm', 'i', 'g', 'g', 4, 'm', 'i', 'g', 's', 3, 'm', 'i', 'n', 4, 'm', 'i', 'n', 'j', 4, 'm', 'i', 'n', 'h', 3, 'm', 'i', 'd', 3, 'm', 'i', 'l', 4, 'm', 'i', 'l', 'g', 4, 'm', 'i', 'l', 'm', 4, 'm', 'i', 'l', 'b', 4, 'm', 'i', 'l', 's', 4, 'm', 'i', 'l', 't', 4, 'm', 'i', 'l', 'p', 4, 'm', 'i', 'l', 'h', 3, 'm', 'i', 'm', 3, 'm', 'i', 'b', 4, 'm', 'i', 'b', 's', 3, 'm', 'i', 's', 4, 'm', 'i', 's', 's', 4, 'm', 'i', 'n', 'g', 3, 'm', 'i', 'j', 3, 'm', 'i', 'c', 3, 'm', 'i', 'k', 3, 'm', 'i', 't', 3, 'm', 'i', 'p', 3, 'm', 'i', 'h', 2, 'b', 'a', 3, 'b', 'a', 'g', 4, 'b', 'a', 'g', 'g', 4, 'b', 'a', 'g', 's', 3, 'b', 'a', 'n', 4, 'b', 'a', 'n', 'j', 4, 'b', 'a', 'n', 'h', 3, 'b', 'a', 'd', 3, 'b', 'a', 'l', 4, 'b', 'a', 'l', 'g', 4, 'b', 'a', 'l', 'm', 4, 'b', 'a', 'l', 'b', 4, 'b', 'a', 'l', 's', 4, 'b', 'a', 'l', 't', 4, 'b', 'a', 'l', 'p', 4, 'b', 'a', 'l', 'h', 3, 'b', 'a', 'm', 3, 'b', 'a', 'b', 4, 'b', 'a', 'b', 's', 3, 'b', 'a', 's', 4, 'b', 'a', 's', 's', 4, 'b', 'a', 'n', 'g', 3, 'b', 'a', 'j', 3, 'b', 'a', 'c', 3, 'b', 'a', 'k', 3, 'b', 'a', 't', 3, 'b', 'a', 'p', 3, 'b', 'a', 'h', 3, 'b', 'a', 'e', 4, 'b', 'a', 'e', 'g', 5, 'b', 'a', 'e', 'g', 'g', 5, 'b', 'a', 'e', 'g', 's', 4, 'b', 'a', 'e', 'n', 5, 'b', 'a', 'e', 'n', 'j', 5, 'b', 'a', 'e', 'n', 'h', 4, 'b', 'a', 'e', 'd', 4, 'b', 'a', 'e', 'l', 5, 'b', 'a', 'e', 'l', 'g', 5, 'b', 'a', 'e', 'l', 'm', 5, 'b', 'a', 'e', 'l', 'b', 5, 'b', 'a', 'e', 'l', 's', 5, 'b', 'a', 'e', 'l', 't', 5, 'b', 'a', 'e', 'l', 'p', 5, 'b', 'a', 'e', 'l', 'h', 4, 'b', 'a', 'e', 'm', 4, 'b', 'a', 'e', 'b', 5, 'b', 'a', 'e', 'b', 's', 4, 'b', 'a', 'e', 's', 5, 'b', 'a', 'e', 's', 's', 5, 'b', 'a', 'e', 'n', 'g', 4, 'b', 'a', 'e', 'j', 4, 'b', 'a', 'e', 'c', 4, 'b', 'a', 'e', 'k', 4, 'b', 'a', 'e', 't', 4, 'b', 'a', 'e', 'p', 4, 'b', 'a', 'e', 'h', 3, 'b', 'y', 'a', 4, 'b', 'y', 'a', 'g', 5, 'b', 'y', 'a', 'g', 'g', 5, 'b', 'y', 'a', 'g', 's', 4, 'b', 'y', 'a', 'n', 5, 'b', 'y', 'a', 'n', 'j', 5, 'b', 'y', 'a', 'n', 'h', 4, 'b', 'y', 'a', 'd', 4, 'b', 'y', 'a', 'l', 5, 'b', 'y', 'a', 'l', 'g', 5, 'b', 'y', 'a', 'l', 'm', 5, 'b', 'y', 'a', 'l', 'b', 5, 'b', 'y', 'a', 'l', 's', 5, 'b', 'y', 'a', 'l', 't', 5, 'b', 'y', 'a', 'l', 'p', 5, 'b', 'y', 'a', 'l', 'h', 4, 'b', 'y', 'a', 'm', 4, 'b', 'y', 'a', 'b', 5, 'b', 'y', 'a', 'b', 's', 4, 'b', 'y', 'a', 's', 5, 'b', 'y', 'a', 's', 's', 5, 'b', 'y', 'a', 'n', 'g', 4, 'b', 'y', 'a', 'j', 4, 'b', 'y', 'a', 'c', 4, 'b', 'y', 'a', 'k', 4, 'b', 'y', 'a', 't', 4, 'b', 'y', 'a', 'p', 4, 'b', 'y', 'a', 'h', 4, 'b', 'y', 'a', 'e', 5, 'b', 'y', 'a', 'e', 'g', 6, 'b', 'y', 'a', 'e', 'g', 'g', 6, 'b', 'y', 'a', 'e', 'g', 's', 5, 'b', 'y', 'a', 'e', 'n', 6, 'b', 'y', 'a', 'e', 'n', 'j', 6, 'b', 'y', 'a', 'e', 'n', 'h', 5, 'b', 'y', 'a', 'e', 'd', 5, 'b', 'y', 'a', 'e', 'l', 6, 'b', 'y', 'a', 'e', 'l', 'g', 6, 'b', 'y', 'a', 'e', 'l', 'm', 6, 'b', 'y', 'a', 'e', 'l', 'b', 6, 'b', 'y', 'a', 'e', 'l', 's', 6, 'b', 'y', 'a', 'e', 'l', 't', 6, 'b', 'y', 'a', 'e', 'l', 'p', 6, 'b', 'y', 'a', 'e', 'l', 'h', 5, 'b', 'y', 'a', 'e', 'm', 5, 'b', 'y', 'a', 'e', 'b', 6, 'b', 'y', 'a', 'e', 'b', 's', 5, 'b', 'y', 'a', 'e', 's', 6, 'b', 'y', 'a', 'e', 's', 's', 6, 'b', 'y', 'a', 'e', 'n', 'g', 5, 'b', 'y', 'a', 'e', 'j', 5, 'b', 'y', 'a', 'e', 'c', 5, 'b', 'y', 'a', 'e', 'k', 5, 'b', 'y', 'a', 'e', 't', 5, 'b', 'y', 'a', 'e', 'p', 5, 'b', 'y', 'a', 'e', 'h', 3, 'b', 'e', 'o', 4, 'b', 'e', 'o', 'g', 5, 'b', 'e', 'o', 'g', 'g', 5, 'b', 'e', 'o', 'g', 's', 4, 'b', 'e', 'o', 'n', 5, 'b', 'e', 'o', 'n', 'j', 5, 'b', 'e', 'o', 'n', 'h', 4, 'b', 'e', 'o', 'd', 4, 'b', 'e', 'o', 'l', 5, 'b', 'e', 'o', 'l', 'g', 5, 'b', 'e', 'o', 'l', 'm', 5, 'b', 'e', 'o', 'l', 'b', 5, 'b', 'e', 'o', 'l', 's', 5, 'b', 'e', 'o', 'l', 't', 5, 'b', 'e', 'o', 'l', 'p', 5, 'b', 'e', 'o', 'l', 'h', 4, 'b', 'e', 'o', 'm', 4, 'b', 'e', 'o', 'b', 5, 'b', 'e', 'o', 'b', 's', 4, 'b', 'e', 'o', 's', 5, 'b', 'e', 'o', 's', 's', 5, 'b', 'e', 'o', 'n', 'g', 4, 'b', 'e', 'o', 'j', 4, 'b', 'e', 'o', 'c', 4, 'b', 'e', 'o', 'k', 4, 'b', 'e', 'o', 't', 4, 'b', 'e', 'o', 'p', 4, 'b', 'e', 'o', 'h', 2, 'b', 'e', 3, 'b', 'e', 'g', 4, 'b', 'e', 'g', 'g', 4, 'b', 'e', 'g', 's', 3, 'b', 'e', 'n', 4, 'b', 'e', 'n', 'j', 4, 'b', 'e', 'n', 'h', 3, 'b', 'e', 'd', 3, 'b', 'e', 'l', 4, 'b', 'e', 'l', 'g', 4, 'b', 'e', 'l', 'm', 4, 'b', 'e', 'l', 'b', 4, 'b', 'e', 'l', 's', 4, 'b', 'e', 'l', 't', 4, 'b', 'e', 'l', 'p', 4, 'b', 'e', 'l', 'h', 3, 'b', 'e', 'm', 3, 'b', 'e', 'b', 4, 'b', 'e', 'b', 's', 3, 'b', 'e', 's', 4, 'b', 'e', 's', 's', 4, 'b', 'e', 'n', 'g', 3, 'b', 'e', 'j', 3, 'b', 'e', 'c', 3, 'b', 'e', 'k', 3, 'b', 'e', 't', 3, 'b', 'e', 'p', 3, 'b', 'e', 'h', 4, 'b', 'y', 'e', 'o', 5, 'b', 'y', 'e', 'o', 'g', 6, 'b', 'y', 'e', 'o', 'g', 'g', 6, 'b', 'y', 'e', 'o', 'g', 's', 5, 'b', 'y', 'e', 'o', 'n', 6, 'b', 'y', 'e', 'o', 'n', 'j', 6, 'b', 'y', 'e', 'o', 'n', 'h', 5, 'b', 'y', 'e', 'o', 'd', 5, 'b', 'y', 'e', 'o', 'l', 6, 'b', 'y', 'e', 'o', 'l', 'g', 6, 'b', 'y', 'e', 'o', 'l', 'm', 6, 'b', 'y', 'e', 'o', 'l', 'b', 6, 'b', 'y', 'e', 'o', 'l', 's', 6, 'b', 'y', 'e', 'o', 'l', 't', 6, 'b', 'y', 'e', 'o', 'l', 'p', 6, 'b', 'y', 'e', 'o', 'l', 'h', 5, 'b', 'y', 'e', 'o', 'm', 5, 'b', 'y', 'e', 'o', 'b', 6, 'b', 'y', 'e', 'o', 'b', 's', 5, 'b', 'y', 'e', 'o', 's', 6, 'b', 'y', 'e', 'o', 's', 's', 6, 'b', 'y', 'e', 'o', 'n', 'g', 5, 'b', 'y', 'e', 'o', 'j', 5, 'b', 'y', 'e', 'o', 'c', 5, 'b', 'y', 'e', 'o', 'k', 5, 'b', 'y', 'e', 'o', 't', 5, 'b', 'y', 'e', 'o', 'p', 5, 'b', 'y', 'e', 'o', 'h', 3, 'b', 'y', 'e', 4, 'b', 'y', 'e', 'g', 5, 'b', 'y', 'e', 'g', 'g', 5, 'b', 'y', 'e', 'g', 's', 4, 'b', 'y', 'e', 'n', 5, 'b', 'y', 'e', 'n', 'j', 5, 'b', 'y', 'e', 'n', 'h', 4, 'b', 'y', 'e', 'd', 4, 'b', 'y', 'e', 'l', 5, 'b', 'y', 'e', 'l', 'g', 5, 'b', 'y', 'e', 'l', 'm', 5, 'b', 'y', 'e', 'l', 'b', 5, 'b', 'y', 'e', 'l', 's', 5, 'b', 'y', 'e', 'l', 't', 5, 'b', 'y', 'e', 'l', 'p', 5, 'b', 'y', 'e', 'l', 'h', 4, 'b', 'y', 'e', 'm', 4, 'b', 'y', 'e', 'b', 5, 'b', 'y', 'e', 'b', 's', 4, 'b', 'y', 'e', 's', 5, 'b', 'y', 'e', 's', 's', 5, 'b', 'y', 'e', 'n', 'g', 4, 'b', 'y', 'e', 'j', 4, 'b', 'y', 'e', 'c', 4, 'b', 'y', 'e', 'k', 4, 'b', 'y', 'e', 't', 4, 'b', 'y', 'e', 'p', 4, 'b', 'y', 'e', 'h', 2, 'b', 'o', 3, 'b', 'o', 'g', 4, 'b', 'o', 'g', 'g', 4, 'b', 'o', 'g', 's', 3, 'b', 'o', 'n', 4, 'b', 'o', 'n', 'j', 4, 'b', 'o', 'n', 'h', 3, 'b', 'o', 'd', 3, 'b', 'o', 'l', 4, 'b', 'o', 'l', 'g', 4, 'b', 'o', 'l', 'm', 4, 'b', 'o', 'l', 'b', 4, 'b', 'o', 'l', 's', 4, 'b', 'o', 'l', 't', 4, 'b', 'o', 'l', 'p', 4, 'b', 'o', 'l', 'h', 3, 'b', 'o', 'm', 3, 'b', 'o', 'b', 4, 'b', 'o', 'b', 's', 3, 'b', 'o', 's', 4, 'b', 'o', 's', 's', 4, 'b', 'o', 'n', 'g', 3, 'b', 'o', 'j', 3, 'b', 'o', 'c', 3, 'b', 'o', 'k', 3, 'b', 'o', 't', 3, 'b', 'o', 'p', 3, 'b', 'o', 'h', 3, 'b', 'w', 'a', 4, 'b', 'w', 'a', 'g', 5, 'b', 'w', 'a', 'g', 'g', 5, 'b', 'w', 'a', 'g', 's', 4, 'b', 'w', 'a', 'n', 5, 'b', 'w', 'a', 'n', 'j', 5, 'b', 'w', 'a', 'n', 'h', 4, 'b', 'w', 'a', 'd', 4, 'b', 'w', 'a', 'l', 5, 'b', 'w', 'a', 'l', 'g', 5, 'b', 'w', 'a', 'l', 'm', 5, 'b', 'w', 'a', 'l', 'b', 5, 'b', 'w', 'a', 'l', 's', 5, 'b', 'w', 'a', 'l', 't', 5, 'b', 'w', 'a', 'l', 'p', 5, 'b', 'w', 'a', 'l', 'h', 4, 'b', 'w', 'a', 'm', 4, 'b', 'w', 'a', 'b', 5, 'b', 'w', 'a', 'b', 's', 4, 'b', 'w', 'a', 's', 5, 'b', 'w', 'a', 's', 's', 5, 'b', 'w', 'a', 'n', 'g', 4, 'b', 'w', 'a', 'j', 4, 'b', 'w', 'a', 'c', 4, 'b', 'w', 'a', 'k', 4, 'b', 'w', 'a', 't', 4, 'b', 'w', 'a', 'p', 4, 'b', 'w', 'a', 'h', 4, 'b', 'w', 'a', 'e', 5, 'b', 'w', 'a', 'e', 'g', 6, 'b', 'w', 'a', 'e', 'g', 'g', 6, 'b', 'w', 'a', 'e', 'g', 's', 5, 'b', 'w', 'a', 'e', 'n', 6, 'b', 'w', 'a', 'e', 'n', 'j', 6, 'b', 'w', 'a', 'e', 'n', 'h', 5, 'b', 'w', 'a', 'e', 'd', 5, 'b', 'w', 'a', 'e', 'l', 6, 'b', 'w', 'a', 'e', 'l', 'g', 6, 'b', 'w', 'a', 'e', 'l', 'm', 6, 'b', 'w', 'a', 'e', 'l', 'b', 6, 'b', 'w', 'a', 'e', 'l', 's', 6, 'b', 'w', 'a', 'e', 'l', 't', 6, 'b', 'w', 'a', 'e', 'l', 'p', 6, 'b', 'w', 'a', 'e', 'l', 'h', 5, 'b', 'w', 'a', 'e', 'm', 5, 'b', 'w', 'a', 'e', 'b', 6, 'b', 'w', 'a', 'e', 'b', 's', 5, 'b', 'w', 'a', 'e', 's', 6, 'b', 'w', 'a', 'e', 's', 's', 6, 'b', 'w', 'a', 'e', 'n', 'g', 5, 'b', 'w', 'a', 'e', 'j', 5, 'b', 'w', 'a', 'e', 'c', 5, 'b', 'w', 'a', 'e', 'k', 5, 'b', 'w', 'a', 'e', 't', 5, 'b', 'w', 'a', 'e', 'p', 5, 'b', 'w', 'a', 'e', 'h', 3, 'b', 'o', 'e', 4, 'b', 'o', 'e', 'g', 5, 'b', 'o', 'e', 'g', 'g', 5, 'b', 'o', 'e', 'g', 's', 4, 'b', 'o', 'e', 'n', 5, 'b', 'o', 'e', 'n', 'j', 5, 'b', 'o', 'e', 'n', 'h', 4, 'b', 'o', 'e', 'd', 4, 'b', 'o', 'e', 'l', 5, 'b', 'o', 'e', 'l', 'g', 5, 'b', 'o', 'e', 'l', 'm', 5, 'b', 'o', 'e', 'l', 'b', 5, 'b', 'o', 'e', 'l', 's', 5, 'b', 'o', 'e', 'l', 't', 5, 'b', 'o', 'e', 'l', 'p', 5, 'b', 'o', 'e', 'l', 'h', 4, 'b', 'o', 'e', 'm', 4, 'b', 'o', 'e', 'b', 5, 'b', 'o', 'e', 'b', 's', 4, 'b', 'o', 'e', 's', 5, 'b', 'o', 'e', 's', 's', 5, 'b', 'o', 'e', 'n', 'g', 4, 'b', 'o', 'e', 'j', 4, 'b', 'o', 'e', 'c', 4, 'b', 'o', 'e', 'k', 4, 'b', 'o', 'e', 't', 4, 'b', 'o', 'e', 'p', 4, 'b', 'o', 'e', 'h', 3, 'b', 'y', 'o', 4, 'b', 'y', 'o', 'g', 5, 'b', 'y', 'o', 'g', 'g', 5, 'b', 'y', 'o', 'g', 's', 4, 'b', 'y', 'o', 'n', 5, 'b', 'y', 'o', 'n', 'j', 5, 'b', 'y', 'o', 'n', 'h', 4, 'b', 'y', 'o', 'd', 4, 'b', 'y', 'o', 'l', 5, 'b', 'y', 'o', 'l', 'g', 5, 'b', 'y', 'o', 'l', 'm', 5, 'b', 'y', 'o', 'l', 'b', 5, 'b', 'y', 'o', 'l', 's', 5, 'b', 'y', 'o', 'l', 't', 5, 'b', 'y', 'o', 'l', 'p', 5, 'b', 'y', 'o', 'l', 'h', 4, 'b', 'y', 'o', 'm', 4, 'b', 'y', 'o', 'b', 5, 'b', 'y', 'o', 'b', 's', 4, 'b', 'y', 'o', 's', 5, 'b', 'y', 'o', 's', 's', 5, 'b', 'y', 'o', 'n', 'g', 4, 'b', 'y', 'o', 'j', 4, 'b', 'y', 'o', 'c', 4, 'b', 'y', 'o', 'k', 4, 'b', 'y', 'o', 't', 4, 'b', 'y', 'o', 'p', 4, 'b', 'y', 'o', 'h', 2, 'b', 'u', 3, 'b', 'u', 'g', 4, 'b', 'u', 'g', 'g', 4, 'b', 'u', 'g', 's', 3, 'b', 'u', 'n', 4, 'b', 'u', 'n', 'j', 4, 'b', 'u', 'n', 'h', 3, 'b', 'u', 'd', 3, 'b', 'u', 'l', 4, 'b', 'u', 'l', 'g', 4, 'b', 'u', 'l', 'm', 4, 'b', 'u', 'l', 'b', 4, 'b', 'u', 'l', 's', 4, 'b', 'u', 'l', 't', 4, 'b', 'u', 'l', 'p', 4, 'b', 'u', 'l', 'h', 3, 'b', 'u', 'm', 3, 'b', 'u', 'b', 4, 'b', 'u', 'b', 's', 3, 'b', 'u', 's', 4, 'b', 'u', 's', 's', 4, 'b', 'u', 'n', 'g', 3, 'b', 'u', 'j', 3, 'b', 'u', 'c', 3, 'b', 'u', 'k', 3, 'b', 'u', 't', 3, 'b', 'u', 'p', 3, 'b', 'u', 'h', 4, 'b', 'w', 'e', 'o', 5, 'b', 'w', 'e', 'o', 'g', 6, 'b', 'w', 'e', 'o', 'g', 'g', 6, 'b', 'w', 'e', 'o', 'g', 's', 5, 'b', 'w', 'e', 'o', 'n', 6, 'b', 'w', 'e', 'o', 'n', 'j', 6, 'b', 'w', 'e', 'o', 'n', 'h', 5, 'b', 'w', 'e', 'o', 'd', 5, 'b', 'w', 'e', 'o', 'l', 6, 'b', 'w', 'e', 'o', 'l', 'g', 6, 'b', 'w', 'e', 'o', 'l', 'm', 6, 'b', 'w', 'e', 'o', 'l', 'b', 6, 'b', 'w', 'e', 'o', 'l', 's', 6, 'b', 'w', 'e', 'o', 'l', 't', 6, 'b', 'w', 'e', 'o', 'l', 'p', 6, 'b', 'w', 'e', 'o', 'l', 'h', 5, 'b', 'w', 'e', 'o', 'm', 5, 'b', 'w', 'e', 'o', 'b', 6, 'b', 'w', 'e', 'o', 'b', 's', 5, 'b', 'w', 'e', 'o', 's', 6, 'b', 'w', 'e', 'o', 's', 's', 6, 'b', 'w', 'e', 'o', 'n', 'g', 5, 'b', 'w', 'e', 'o', 'j', 5, 'b', 'w', 'e', 'o', 'c', 5, 'b', 'w', 'e', 'o', 'k', 5, 'b', 'w', 'e', 'o', 't', 5, 'b', 'w', 'e', 'o', 'p', 5, 'b', 'w', 'e', 'o', 'h', 3, 'b', 'w', 'e', 4, 'b', 'w', 'e', 'g', 5, 'b', 'w', 'e', 'g', 'g', 5, 'b', 'w', 'e', 'g', 's', 4, 'b', 'w', 'e', 'n', 5, 'b', 'w', 'e', 'n', 'j', 5, 'b', 'w', 'e', 'n', 'h', 4, 'b', 'w', 'e', 'd', 4, 'b', 'w', 'e', 'l', 5, 'b', 'w', 'e', 'l', 'g', 5, 'b', 'w', 'e', 'l', 'm', 5, 'b', 'w', 'e', 'l', 'b', 5, 'b', 'w', 'e', 'l', 's', 5, 'b', 'w', 'e', 'l', 't', 5, 'b', 'w', 'e', 'l', 'p', 5, 'b', 'w', 'e', 'l', 'h', 4, 'b', 'w', 'e', 'm', 4, 'b', 'w', 'e', 'b', 5, 'b', 'w', 'e', 'b', 's', 4, 'b', 'w', 'e', 's', 5, 'b', 'w', 'e', 's', 's', 5, 'b', 'w', 'e', 'n', 'g', 4, 'b', 'w', 'e', 'j', 4, 'b', 'w', 'e', 'c', 4, 'b', 'w', 'e', 'k', 4, 'b', 'w', 'e', 't', 4, 'b', 'w', 'e', 'p', 4, 'b', 'w', 'e', 'h', 3, 'b', 'w', 'i', 4, 'b', 'w', 'i', 'g', 5, 'b', 'w', 'i', 'g', 'g', 5, 'b', 'w', 'i', 'g', 's', 4, 'b', 'w', 'i', 'n', 5, 'b', 'w', 'i', 'n', 'j', 5, 'b', 'w', 'i', 'n', 'h', 4, 'b', 'w', 'i', 'd', 4, 'b', 'w', 'i', 'l', 5, 'b', 'w', 'i', 'l', 'g', 5, 'b', 'w', 'i', 'l', 'm', 5, 'b', 'w', 'i', 'l', 'b', 5, 'b', 'w', 'i', 'l', 's', 5, 'b', 'w', 'i', 'l', 't', 5, 'b', 'w', 'i', 'l', 'p', 5, 'b', 'w', 'i', 'l', 'h', 4, 'b', 'w', 'i', 'm', 4, 'b', 'w', 'i', 'b', 5, 'b', 'w', 'i', 'b', 's', 4, 'b', 'w', 'i', 's', 5, 'b', 'w', 'i', 's', 's', 5, 'b', 'w', 'i', 'n', 'g', 4, 'b', 'w', 'i', 'j', 4, 'b', 'w', 'i', 'c', 4, 'b', 'w', 'i', 'k', 4, 'b', 'w', 'i', 't', 4, 'b', 'w', 'i', 'p', 4, 'b', 'w', 'i', 'h', 3, 'b', 'y', 'u', 4, 'b', 'y', 'u', 'g', 5, 'b', 'y', 'u', 'g', 'g', 5, 'b', 'y', 'u', 'g', 's', 4, 'b', 'y', 'u', 'n', 5, 'b', 'y', 'u', 'n', 'j', 5, 'b', 'y', 'u', 'n', 'h', 4, 'b', 'y', 'u', 'd', 4, 'b', 'y', 'u', 'l', 5, 'b', 'y', 'u', 'l', 'g', 5, 'b', 'y', 'u', 'l', 'm', 5, 'b', 'y', 'u', 'l', 'b', 5, 'b', 'y', 'u', 'l', 's', 5, 'b', 'y', 'u', 'l', 't', 5, 'b', 'y', 'u', 'l', 'p', 5, 'b', 'y', 'u', 'l', 'h', 4, 'b', 'y', 'u', 'm', 4, 'b', 'y', 'u', 'b', 5, 'b', 'y', 'u', 'b', 's', 4, 'b', 'y', 'u', 's', 5, 'b', 'y', 'u', 's', 's', 5, 'b', 'y', 'u', 'n', 'g', 4, 'b', 'y', 'u', 'j', 4, 'b', 'y', 'u', 'c', 4, 'b', 'y', 'u', 'k', 4, 'b', 'y', 'u', 't', 4, 'b', 'y', 'u', 'p', 4, 'b', 'y', 'u', 'h', 3, 'b', 'e', 'u', 4, 'b', 'e', 'u', 'g', 5, 'b', 'e', 'u', 'g', 'g', 5, 'b', 'e', 'u', 'g', 's', 4, 'b', 'e', 'u', 'n', 5, 'b', 'e', 'u', 'n', 'j', 5, 'b', 'e', 'u', 'n', 'h', 4, 'b', 'e', 'u', 'd', 4, 'b', 'e', 'u', 'l', 5, 'b', 'e', 'u', 'l', 'g', 5, 'b', 'e', 'u', 'l', 'm', 5, 'b', 'e', 'u', 'l', 'b', 5, 'b', 'e', 'u', 'l', 's', 5, 'b', 'e', 'u', 'l', 't', 5, 'b', 'e', 'u', 'l', 'p', 5, 'b', 'e', 'u', 'l', 'h', 4, 'b', 'e', 'u', 'm', 4, 'b', 'e', 'u', 'b', 5, 'b', 'e', 'u', 'b', 's', 4, 'b', 'e', 'u', 's', 5, 'b', 'e', 'u', 's', 's', 5, 'b', 'e', 'u', 'n', 'g', 4, 'b', 'e', 'u', 'j', 4, 'b', 'e', 'u', 'c', 4, 'b', 'e', 'u', 'k', 4, 'b', 'e', 'u', 't', 4, 'b', 'e', 'u', 'p', 4, 'b', 'e', 'u', 'h', 3, 'b', 'y', 'i', 4, 'b', 'y', 'i', 'g', 5, 'b', 'y', 'i', 'g', 'g', 5, 'b', 'y', 'i', 'g', 's', 4, 'b', 'y', 'i', 'n', 5, 'b', 'y', 'i', 'n', 'j', 5, 'b', 'y', 'i', 'n', 'h', 4, 'b', 'y', 'i', 'd', 4, 'b', 'y', 'i', 'l', 5, 'b', 'y', 'i', 'l', 'g', 5, 'b', 'y', 'i', 'l', 'm', 5, 'b', 'y', 'i', 'l', 'b', 5, 'b', 'y', 'i', 'l', 's', 5, 'b', 'y', 'i', 'l', 't', 5, 'b', 'y', 'i', 'l', 'p', 5, 'b', 'y', 'i', 'l', 'h', 4, 'b', 'y', 'i', 'm', 4, 'b', 'y', 'i', 'b', 5, 'b', 'y', 'i', 'b', 's', 4, 'b', 'y', 'i', 's', 5, 'b', 'y', 'i', 's', 's', 5, 'b', 'y', 'i', 'n', 'g', 4, 'b', 'y', 'i', 'j', 4, 'b', 'y', 'i', 'c', 4, 'b', 'y', 'i', 'k', 4, 'b', 'y', 'i', 't', 4, 'b', 'y', 'i', 'p', 4, 'b', 'y', 'i', 'h', 2, 'b', 'i', 3, 'b', 'i', 'g', 4, 'b', 'i', 'g', 'g', 4, 'b', 'i', 'g', 's', 3, 'b', 'i', 'n', 4, 'b', 'i', 'n', 'j', 4, 'b', 'i', 'n', 'h', 3, 'b', 'i', 'd', 3, 'b', 'i', 'l', 4, 'b', 'i', 'l', 'g', 4, 'b', 'i', 'l', 'm', 4, 'b', 'i', 'l', 'b', 4, 'b', 'i', 'l', 's', 4, 'b', 'i', 'l', 't', 4, 'b', 'i', 'l', 'p', 4, 'b', 'i', 'l', 'h', 3, 'b', 'i', 'm', 3, 'b', 'i', 'b', 4, 'b', 'i', 'b', 's', 3, 'b', 'i', 's', 4, 'b', 'i', 's', 's', 4, 'b', 'i', 'n', 'g', 3, 'b', 'i', 'j', 3, 'b', 'i', 'c', 3, 'b', 'i', 'k', 3, 'b', 'i', 't', 3, 'b', 'i', 'p', 3, 'b', 'i', 'h', 3, 'b', 'b', 'a', 4, 'b', 'b', 'a', 'g', 5, 'b', 'b', 'a', 'g', 'g', 5, 'b', 'b', 'a', 'g', 's', 4, 'b', 'b', 'a', 'n', 5, 'b', 'b', 'a', 'n', 'j', 5, 'b', 'b', 'a', 'n', 'h', 4, 'b', 'b', 'a', 'd', 4, 'b', 'b', 'a', 'l', 5, 'b', 'b', 'a', 'l', 'g', 5, 'b', 'b', 'a', 'l', 'm', 5, 'b', 'b', 'a', 'l', 'b', 5, 'b', 'b', 'a', 'l', 's', 5, 'b', 'b', 'a', 'l', 't', 5, 'b', 'b', 'a', 'l', 'p', 5, 'b', 'b', 'a', 'l', 'h', 4, 'b', 'b', 'a', 'm', 4, 'b', 'b', 'a', 'b', 5, 'b', 'b', 'a', 'b', 's', 4, 'b', 'b', 'a', 's', 5, 'b', 'b', 'a', 's', 's', 5, 'b', 'b', 'a', 'n', 'g', 4, 'b', 'b', 'a', 'j', 4, 'b', 'b', 'a', 'c', 4, 'b', 'b', 'a', 'k', 4, 'b', 'b', 'a', 't', 4, 'b', 'b', 'a', 'p', 4, 'b', 'b', 'a', 'h', 4, 'b', 'b', 'a', 'e', 5, 'b', 'b', 'a', 'e', 'g', 6, 'b', 'b', 'a', 'e', 'g', 'g', 6, 'b', 'b', 'a', 'e', 'g', 's', 5, 'b', 'b', 'a', 'e', 'n', 6, 'b', 'b', 'a', 'e', 'n', 'j', 6, 'b', 'b', 'a', 'e', 'n', 'h', 5, 'b', 'b', 'a', 'e', 'd', 5, 'b', 'b', 'a', 'e', 'l', 6, 'b', 'b', 'a', 'e', 'l', 'g', 6, 'b', 'b', 'a', 'e', 'l', 'm', 6, 'b', 'b', 'a', 'e', 'l', 'b', 6, 'b', 'b', 'a', 'e', 'l', 's', 6, 'b', 'b', 'a', 'e', 'l', 't', 6, 'b', 'b', 'a', 'e', 'l', 'p', 6, 'b', 'b', 'a', 'e', 'l', 'h', 5, 'b', 'b', 'a', 'e', 'm', 5, 'b', 'b', 'a', 'e', 'b', 6, 'b', 'b', 'a', 'e', 'b', 's', 5, 'b', 'b', 'a', 'e', 's', 6, 'b', 'b', 'a', 'e', 's', 's', 6, 'b', 'b', 'a', 'e', 'n', 'g', 5, 'b', 'b', 'a', 'e', 'j', 5, 'b', 'b', 'a', 'e', 'c', 5, 'b', 'b', 'a', 'e', 'k', 5, 'b', 'b', 'a', 'e', 't', 5, 'b', 'b', 'a', 'e', 'p', 5, 'b', 'b', 'a', 'e', 'h', 4, 'b', 'b', 'y', 'a', 5, 'b', 'b', 'y', 'a', 'g', 6, 'b', 'b', 'y', 'a', 'g', 'g', 6, 'b', 'b', 'y', 'a', 'g', 's', 5, 'b', 'b', 'y', 'a', 'n', 6, 'b', 'b', 'y', 'a', 'n', 'j', 6, 'b', 'b', 'y', 'a', 'n', 'h', 5, 'b', 'b', 'y', 'a', 'd', 5, 'b', 'b', 'y', 'a', 'l', 6, 'b', 'b', 'y', 'a', 'l', 'g', 6, 'b', 'b', 'y', 'a', 'l', 'm', 6, 'b', 'b', 'y', 'a', 'l', 'b', 6, 'b', 'b', 'y', 'a', 'l', 's', 6, 'b', 'b', 'y', 'a', 'l', 't', 6, 'b', 'b', 'y', 'a', 'l', 'p', 6, 'b', 'b', 'y', 'a', 'l', 'h', 5, 'b', 'b', 'y', 'a', 'm', 5, 'b', 'b', 'y', 'a', 'b', 6, 'b', 'b', 'y', 'a', 'b', 's', 5, 'b', 'b', 'y', 'a', 's', 6, 'b', 'b', 'y', 'a', 's', 's', 6, 'b', 'b', 'y', 'a', 'n', 'g', 5, 'b', 'b', 'y', 'a', 'j', 5, 'b', 'b', 'y', 'a', 'c', 5, 'b', 'b', 'y', 'a', 'k', 5, 'b', 'b', 'y', 'a', 't', 5, 'b', 'b', 'y', 'a', 'p', 5, 'b', 'b', 'y', 'a', 'h', 5, 'b', 'b', 'y', 'a', 'e', 6, 'b', 'b', 'y', 'a', 'e', 'g', 7, 'b', 'b', 'y', 'a', 'e', 'g', 'g', 7, 'b', 'b', 'y', 'a', 'e', 'g', 's', 6, 'b', 'b', 'y', 'a', 'e', 'n', 7, 'b', 'b', 'y', 'a', 'e', 'n', 'j', 7, 'b', 'b', 'y', 'a', 'e', 'n', 'h', 6, 'b', 'b', 'y', 'a', 'e', 'd', 6, 'b', 'b', 'y', 'a', 'e', 'l', 7, 'b', 'b', 'y', 'a', 'e', 'l', 'g', 7, 'b', 'b', 'y', 'a', 'e', 'l', 'm', 7, 'b', 'b', 'y', 'a', 'e', 'l', 'b', 7, 'b', 'b', 'y', 'a', 'e', 'l', 's', 7, 'b', 'b', 'y', 'a', 'e', 'l', 't', 7, 'b', 'b', 'y', 'a', 'e', 'l', 'p', 7, 'b', 'b', 'y', 'a', 'e', 'l', 'h', 6, 'b', 'b', 'y', 'a', 'e', 'm', 6, 'b', 'b', 'y', 'a', 'e', 'b', 7, 'b', 'b', 'y', 'a', 'e', 'b', 's', 6, 'b', 'b', 'y', 'a', 'e', 's', 7, 'b', 'b', 'y', 'a', 'e', 's', 's', 7, 'b', 'b', 'y', 'a', 'e', 'n', 'g', 6, 'b', 'b', 'y', 'a', 'e', 'j', 6, 'b', 'b', 'y', 'a', 'e', 'c', 6, 'b', 'b', 'y', 'a', 'e', 'k', 6, 'b', 'b', 'y', 'a', 'e', 't', 6, 'b', 'b', 'y', 'a', 'e', 'p', 6, 'b', 'b', 'y', 'a', 'e', 'h', 4, 'b', 'b', 'e', 'o', 5, 'b', 'b', 'e', 'o', 'g', 6, 'b', 'b', 'e', 'o', 'g', 'g', 6, 'b', 'b', 'e', 'o', 'g', 's', 5, 'b', 'b', 'e', 'o', 'n', 6, 'b', 'b', 'e', 'o', 'n', 'j', 6, 'b', 'b', 'e', 'o', 'n', 'h', 5, 'b', 'b', 'e', 'o', 'd', 5, 'b', 'b', 'e', 'o', 'l', 6, 'b', 'b', 'e', 'o', 'l', 'g', 6, 'b', 'b', 'e', 'o', 'l', 'm', 6, 'b', 'b', 'e', 'o', 'l', 'b', 6, 'b', 'b', 'e', 'o', 'l', 's', 6, 'b', 'b', 'e', 'o', 'l', 't', 6, 'b', 'b', 'e', 'o', 'l', 'p', 6, 'b', 'b', 'e', 'o', 'l', 'h', 5, 'b', 'b', 'e', 'o', 'm', 5, 'b', 'b', 'e', 'o', 'b', 6, 'b', 'b', 'e', 'o', 'b', 's', 5, 'b', 'b', 'e', 'o', 's', 6, 'b', 'b', 'e', 'o', 's', 's', 6, 'b', 'b', 'e', 'o', 'n', 'g', 5, 'b', 'b', 'e', 'o', 'j', 5, 'b', 'b', 'e', 'o', 'c', 5, 'b', 'b', 'e', 'o', 'k', 5, 'b', 'b', 'e', 'o', 't', 5, 'b', 'b', 'e', 'o', 'p', 5, 'b', 'b', 'e', 'o', 'h', 3, 'b', 'b', 'e', 4, 'b', 'b', 'e', 'g', 5, 'b', 'b', 'e', 'g', 'g', 5, 'b', 'b', 'e', 'g', 's', 4, 'b', 'b', 'e', 'n', 5, 'b', 'b', 'e', 'n', 'j', 5, 'b', 'b', 'e', 'n', 'h', 4, 'b', 'b', 'e', 'd', 4, 'b', 'b', 'e', 'l', 5, 'b', 'b', 'e', 'l', 'g', 5, 'b', 'b', 'e', 'l', 'm', 5, 'b', 'b', 'e', 'l', 'b', 5, 'b', 'b', 'e', 'l', 's', 5, 'b', 'b', 'e', 'l', 't', 5, 'b', 'b', 'e', 'l', 'p', 5, 'b', 'b', 'e', 'l', 'h', 4, 'b', 'b', 'e', 'm', 4, 'b', 'b', 'e', 'b', 5, 'b', 'b', 'e', 'b', 's', 4, 'b', 'b', 'e', 's', 5, 'b', 'b', 'e', 's', 's', 5, 'b', 'b', 'e', 'n', 'g', 4, 'b', 'b', 'e', 'j', 4, 'b', 'b', 'e', 'c', 4, 'b', 'b', 'e', 'k', 4, 'b', 'b', 'e', 't', 4, 'b', 'b', 'e', 'p', 4, 'b', 'b', 'e', 'h', 5, 'b', 'b', 'y', 'e', 'o', 6, 'b', 'b', 'y', 'e', 'o', 'g', 7, 'b', 'b', 'y', 'e', 'o', 'g', 'g', 7, 'b', 'b', 'y', 'e', 'o', 'g', 's', 6, 'b', 'b', 'y', 'e', 'o', 'n', 7, 'b', 'b', 'y', 'e', 'o', 'n', 'j', 7, 'b', 'b', 'y', 'e', 'o', 'n', 'h', 6, 'b', 'b', 'y', 'e', 'o', 'd', 6, 'b', 'b', 'y', 'e', 'o', 'l', 7, 'b', 'b', 'y', 'e', 'o', 'l', 'g', 7, 'b', 'b', 'y', 'e', 'o', 'l', 'm', 7, 'b', 'b', 'y', 'e', 'o', 'l', 'b', 7, 'b', 'b', 'y', 'e', 'o', 'l', 's', 7, 'b', 'b', 'y', 'e', 'o', 'l', 't', 7, 'b', 'b', 'y', 'e', 'o', 'l', 'p', 7, 'b', 'b', 'y', 'e', 'o', 'l', 'h', 6, 'b', 'b', 'y', 'e', 'o', 'm', 6, 'b', 'b', 'y', 'e', 'o', 'b', 7, 'b', 'b', 'y', 'e', 'o', 'b', 's', 6, 'b', 'b', 'y', 'e', 'o', 's', 7, 'b', 'b', 'y', 'e', 'o', 's', 's', 7, 'b', 'b', 'y', 'e', 'o', 'n', 'g', 6, 'b', 'b', 'y', 'e', 'o', 'j', 6, 'b', 'b', 'y', 'e', 'o', 'c', 6, 'b', 'b', 'y', 'e', 'o', 'k', 6, 'b', 'b', 'y', 'e', 'o', 't', 6, 'b', 'b', 'y', 'e', 'o', 'p', 6, 'b', 'b', 'y', 'e', 'o', 'h', 4, 'b', 'b', 'y', 'e', 5, 'b', 'b', 'y', 'e', 'g', 6, 'b', 'b', 'y', 'e', 'g', 'g', 6, 'b', 'b', 'y', 'e', 'g', 's', 5, 'b', 'b', 'y', 'e', 'n', 6, 'b', 'b', 'y', 'e', 'n', 'j', 6, 'b', 'b', 'y', 'e', 'n', 'h', 5, 'b', 'b', 'y', 'e', 'd', 5, 'b', 'b', 'y', 'e', 'l', 6, 'b', 'b', 'y', 'e', 'l', 'g', 6, 'b', 'b', 'y', 'e', 'l', 'm', 6, 'b', 'b', 'y', 'e', 'l', 'b', 6, 'b', 'b', 'y', 'e', 'l', 's', 6, 'b', 'b', 'y', 'e', 'l', 't', 6, 'b', 'b', 'y', 'e', 'l', 'p', 6, 'b', 'b', 'y', 'e', 'l', 'h', 5, 'b', 'b', 'y', 'e', 'm', 5, 'b', 'b', 'y', 'e', 'b', 6, 'b', 'b', 'y', 'e', 'b', 's', 5, 'b', 'b', 'y', 'e', 's', 6, 'b', 'b', 'y', 'e', 's', 's', 6, 'b', 'b', 'y', 'e', 'n', 'g', 5, 'b', 'b', 'y', 'e', 'j', 5, 'b', 'b', 'y', 'e', 'c', 5, 'b', 'b', 'y', 'e', 'k', 5, 'b', 'b', 'y', 'e', 't', 5, 'b', 'b', 'y', 'e', 'p', 5, 'b', 'b', 'y', 'e', 'h', 3, 'b', 'b', 'o', 4, 'b', 'b', 'o', 'g', 5, 'b', 'b', 'o', 'g', 'g', 5, 'b', 'b', 'o', 'g', 's', 4, 'b', 'b', 'o', 'n', 5, 'b', 'b', 'o', 'n', 'j', 5, 'b', 'b', 'o', 'n', 'h', 4, 'b', 'b', 'o', 'd', 4, 'b', 'b', 'o', 'l', 5, 'b', 'b', 'o', 'l', 'g', 5, 'b', 'b', 'o', 'l', 'm', 5, 'b', 'b', 'o', 'l', 'b', 5, 'b', 'b', 'o', 'l', 's', 5, 'b', 'b', 'o', 'l', 't', 5, 'b', 'b', 'o', 'l', 'p', 5, 'b', 'b', 'o', 'l', 'h', 4, 'b', 'b', 'o', 'm', 4, 'b', 'b', 'o', 'b', 5, 'b', 'b', 'o', 'b', 's', 4, 'b', 'b', 'o', 's', 5, 'b', 'b', 'o', 's', 's', 5, 'b', 'b', 'o', 'n', 'g', 4, 'b', 'b', 'o', 'j', 4, 'b', 'b', 'o', 'c', 4, 'b', 'b', 'o', 'k', 4, 'b', 'b', 'o', 't', 4, 'b', 'b', 'o', 'p', 4, 'b', 'b', 'o', 'h', 4, 'b', 'b', 'w', 'a', 5, 'b', 'b', 'w', 'a', 'g', 6, 'b', 'b', 'w', 'a', 'g', 'g', 6, 'b', 'b', 'w', 'a', 'g', 's', 5, 'b', 'b', 'w', 'a', 'n', 6, 'b', 'b', 'w', 'a', 'n', 'j', 6, 'b', 'b', 'w', 'a', 'n', 'h', 5, 'b', 'b', 'w', 'a', 'd', 5, 'b', 'b', 'w', 'a', 'l', 6, 'b', 'b', 'w', 'a', 'l', 'g', 6, 'b', 'b', 'w', 'a', 'l', 'm', 6, 'b', 'b', 'w', 'a', 'l', 'b', 6, 'b', 'b', 'w', 'a', 'l', 's', 6, 'b', 'b', 'w', 'a', 'l', 't', 6, 'b', 'b', 'w', 'a', 'l', 'p', 6, 'b', 'b', 'w', 'a', 'l', 'h', 5, 'b', 'b', 'w', 'a', 'm', 5, 'b', 'b', 'w', 'a', 'b', 6, 'b', 'b', 'w', 'a', 'b', 's', 5, 'b', 'b', 'w', 'a', 's', 6, 'b', 'b', 'w', 'a', 's', 's', 6, 'b', 'b', 'w', 'a', 'n', 'g', 5, 'b', 'b', 'w', 'a', 'j', 5, 'b', 'b', 'w', 'a', 'c', 5, 'b', 'b', 'w', 'a', 'k', 5, 'b', 'b', 'w', 'a', 't', 5, 'b', 'b', 'w', 'a', 'p', 5, 'b', 'b', 'w', 'a', 'h', 5, 'b', 'b', 'w', 'a', 'e', 6, 'b', 'b', 'w', 'a', 'e', 'g', 7, 'b', 'b', 'w', 'a', 'e', 'g', 'g', 7, 'b', 'b', 'w', 'a', 'e', 'g', 's', 6, 'b', 'b', 'w', 'a', 'e', 'n', 7, 'b', 'b', 'w', 'a', 'e', 'n', 'j', 7, 'b', 'b', 'w', 'a', 'e', 'n', 'h', 6, 'b', 'b', 'w', 'a', 'e', 'd', 6, 'b', 'b', 'w', 'a', 'e', 'l', 7, 'b', 'b', 'w', 'a', 'e', 'l', 'g', 7, 'b', 'b', 'w', 'a', 'e', 'l', 'm', 7, 'b', 'b', 'w', 'a', 'e', 'l', 'b', 7, 'b', 'b', 'w', 'a', 'e', 'l', 's', 7, 'b', 'b', 'w', 'a', 'e', 'l', 't', 7, 'b', 'b', 'w', 'a', 'e', 'l', 'p', 7, 'b', 'b', 'w', 'a', 'e', 'l', 'h', 6, 'b', 'b', 'w', 'a', 'e', 'm', 6, 'b', 'b', 'w', 'a', 'e', 'b', 7, 'b', 'b', 'w', 'a', 'e', 'b', 's', 6, 'b', 'b', 'w', 'a', 'e', 's', 7, 'b', 'b', 'w', 'a', 'e', 's', 's', 7, 'b', 'b', 'w', 'a', 'e', 'n', 'g', 6, 'b', 'b', 'w', 'a', 'e', 'j', 6, 'b', 'b', 'w', 'a', 'e', 'c', 6, 'b', 'b', 'w', 'a', 'e', 'k', 6, 'b', 'b', 'w', 'a', 'e', 't', 6, 'b', 'b', 'w', 'a', 'e', 'p', 6, 'b', 'b', 'w', 'a', 'e', 'h', 4, 'b', 'b', 'o', 'e', 5, 'b', 'b', 'o', 'e', 'g', 6, 'b', 'b', 'o', 'e', 'g', 'g', 6, 'b', 'b', 'o', 'e', 'g', 's', 5, 'b', 'b', 'o', 'e', 'n', 6, 'b', 'b', 'o', 'e', 'n', 'j', 6, 'b', 'b', 'o', 'e', 'n', 'h', 5, 'b', 'b', 'o', 'e', 'd', 5, 'b', 'b', 'o', 'e', 'l', 6, 'b', 'b', 'o', 'e', 'l', 'g', 6, 'b', 'b', 'o', 'e', 'l', 'm', 6, 'b', 'b', 'o', 'e', 'l', 'b', 6, 'b', 'b', 'o', 'e', 'l', 's', 6, 'b', 'b', 'o', 'e', 'l', 't', 6, 'b', 'b', 'o', 'e', 'l', 'p', 6, 'b', 'b', 'o', 'e', 'l', 'h', 5, 'b', 'b', 'o', 'e', 'm', 5, 'b', 'b', 'o', 'e', 'b', 6, 'b', 'b', 'o', 'e', 'b', 's', 5, 'b', 'b', 'o', 'e', 's', 6, 'b', 'b', 'o', 'e', 's', 's', 6, 'b', 'b', 'o', 'e', 'n', 'g', 5, 'b', 'b', 'o', 'e', 'j', 5, 'b', 'b', 'o', 'e', 'c', 5, 'b', 'b', 'o', 'e', 'k', 5, 'b', 'b', 'o', 'e', 't', 5, 'b', 'b', 'o', 'e', 'p', 5, 'b', 'b', 'o', 'e', 'h', 4, 'b', 'b', 'y', 'o', 5, 'b', 'b', 'y', 'o', 'g', 6, 'b', 'b', 'y', 'o', 'g', 'g', 6, 'b', 'b', 'y', 'o', 'g', 's', 5, 'b', 'b', 'y', 'o', 'n', 6, 'b', 'b', 'y', 'o', 'n', 'j', 6, 'b', 'b', 'y', 'o', 'n', 'h', 5, 'b', 'b', 'y', 'o', 'd', 5, 'b', 'b', 'y', 'o', 'l', 6, 'b', 'b', 'y', 'o', 'l', 'g', 6, 'b', 'b', 'y', 'o', 'l', 'm', 6, 'b', 'b', 'y', 'o', 'l', 'b', 6, 'b', 'b', 'y', 'o', 'l', 's', 6, 'b', 'b', 'y', 'o', 'l', 't', 6, 'b', 'b', 'y', 'o', 'l', 'p', 6, 'b', 'b', 'y', 'o', 'l', 'h', 5, 'b', 'b', 'y', 'o', 'm', 5, 'b', 'b', 'y', 'o', 'b', 6, 'b', 'b', 'y', 'o', 'b', 's', 5, 'b', 'b', 'y', 'o', 's', 6, 'b', 'b', 'y', 'o', 's', 's', 6, 'b', 'b', 'y', 'o', 'n', 'g', 5, 'b', 'b', 'y', 'o', 'j', 5, 'b', 'b', 'y', 'o', 'c', 5, 'b', 'b', 'y', 'o', 'k', 5, 'b', 'b', 'y', 'o', 't', 5, 'b', 'b', 'y', 'o', 'p', 5, 'b', 'b', 'y', 'o', 'h', 3, 'b', 'b', 'u', 4, 'b', 'b', 'u', 'g', 5, 'b', 'b', 'u', 'g', 'g', 5, 'b', 'b', 'u', 'g', 's', 4, 'b', 'b', 'u', 'n', 5, 'b', 'b', 'u', 'n', 'j', 5, 'b', 'b', 'u', 'n', 'h', 4, 'b', 'b', 'u', 'd', 4, 'b', 'b', 'u', 'l', 5, 'b', 'b', 'u', 'l', 'g', 5, 'b', 'b', 'u', 'l', 'm', 5, 'b', 'b', 'u', 'l', 'b', 5, 'b', 'b', 'u', 'l', 's', 5, 'b', 'b', 'u', 'l', 't', 5, 'b', 'b', 'u', 'l', 'p', 5, 'b', 'b', 'u', 'l', 'h', 4, 'b', 'b', 'u', 'm', 4, 'b', 'b', 'u', 'b', 5, 'b', 'b', 'u', 'b', 's', 4, 'b', 'b', 'u', 's', 5, 'b', 'b', 'u', 's', 's', 5, 'b', 'b', 'u', 'n', 'g', 4, 'b', 'b', 'u', 'j', 4, 'b', 'b', 'u', 'c', 4, 'b', 'b', 'u', 'k', 4, 'b', 'b', 'u', 't', 4, 'b', 'b', 'u', 'p', 4, 'b', 'b', 'u', 'h', 5, 'b', 'b', 'w', 'e', 'o', 6, 'b', 'b', 'w', 'e', 'o', 'g', 7, 'b', 'b', 'w', 'e', 'o', 'g', 'g', 7, 'b', 'b', 'w', 'e', 'o', 'g', 's', 6, 'b', 'b', 'w', 'e', 'o', 'n', 7, 'b', 'b', 'w', 'e', 'o', 'n', 'j', 7, 'b', 'b', 'w', 'e', 'o', 'n', 'h', 6, 'b', 'b', 'w', 'e', 'o', 'd', 6, 'b', 'b', 'w', 'e', 'o', 'l', 7, 'b', 'b', 'w', 'e', 'o', 'l', 'g', 7, 'b', 'b', 'w', 'e', 'o', 'l', 'm', 7, 'b', 'b', 'w', 'e', 'o', 'l', 'b', 7, 'b', 'b', 'w', 'e', 'o', 'l', 's', 7, 'b', 'b', 'w', 'e', 'o', 'l', 't', 7, 'b', 'b', 'w', 'e', 'o', 'l', 'p', 7, 'b', 'b', 'w', 'e', 'o', 'l', 'h', 6, 'b', 'b', 'w', 'e', 'o', 'm', 6, 'b', 'b', 'w', 'e', 'o', 'b', 7, 'b', 'b', 'w', 'e', 'o', 'b', 's', 6, 'b', 'b', 'w', 'e', 'o', 's', 7, 'b', 'b', 'w', 'e', 'o', 's', 's', 7, 'b', 'b', 'w', 'e', 'o', 'n', 'g', 6, 'b', 'b', 'w', 'e', 'o', 'j', 6, 'b', 'b', 'w', 'e', 'o', 'c', 6, 'b', 'b', 'w', 'e', 'o', 'k', 6, 'b', 'b', 'w', 'e', 'o', 't', 6, 'b', 'b', 'w', 'e', 'o', 'p', 6, 'b', 'b', 'w', 'e', 'o', 'h', 4, 'b', 'b', 'w', 'e', 5, 'b', 'b', 'w', 'e', 'g', 6, 'b', 'b', 'w', 'e', 'g', 'g', 6, 'b', 'b', 'w', 'e', 'g', 's', 5, 'b', 'b', 'w', 'e', 'n', 6, 'b', 'b', 'w', 'e', 'n', 'j', 6, 'b', 'b', 'w', 'e', 'n', 'h', 5, 'b', 'b', 'w', 'e', 'd', 5, 'b', 'b', 'w', 'e', 'l', 6, 'b', 'b', 'w', 'e', 'l', 'g', 6, 'b', 'b', 'w', 'e', 'l', 'm', 6, 'b', 'b', 'w', 'e', 'l', 'b', 6, 'b', 'b', 'w', 'e', 'l', 's', 6, 'b', 'b', 'w', 'e', 'l', 't', 6, 'b', 'b', 'w', 'e', 'l', 'p', 6, 'b', 'b', 'w', 'e', 'l', 'h', 5, 'b', 'b', 'w', 'e', 'm', 5, 'b', 'b', 'w', 'e', 'b', 6, 'b', 'b', 'w', 'e', 'b', 's', 5, 'b', 'b', 'w', 'e', 's', 6, 'b', 'b', 'w', 'e', 's', 's', 6, 'b', 'b', 'w', 'e', 'n', 'g', 5, 'b', 'b', 'w', 'e', 'j', 5, 'b', 'b', 'w', 'e', 'c', 5, 'b', 'b', 'w', 'e', 'k', 5, 'b', 'b', 'w', 'e', 't', 5, 'b', 'b', 'w', 'e', 'p', 5, 'b', 'b', 'w', 'e', 'h', 4, 'b', 'b', 'w', 'i', 5, 'b', 'b', 'w', 'i', 'g', 6, 'b', 'b', 'w', 'i', 'g', 'g', 6, 'b', 'b', 'w', 'i', 'g', 's', 5, 'b', 'b', 'w', 'i', 'n', 6, 'b', 'b', 'w', 'i', 'n', 'j', 6, 'b', 'b', 'w', 'i', 'n', 'h', 5, 'b', 'b', 'w', 'i', 'd', 5, 'b', 'b', 'w', 'i', 'l', 6, 'b', 'b', 'w', 'i', 'l', 'g', 6, 'b', 'b', 'w', 'i', 'l', 'm', 6, 'b', 'b', 'w', 'i', 'l', 'b', 6, 'b', 'b', 'w', 'i', 'l', 's', 6, 'b', 'b', 'w', 'i', 'l', 't', 6, 'b', 'b', 'w', 'i', 'l', 'p', 6, 'b', 'b', 'w', 'i', 'l', 'h', 5, 'b', 'b', 'w', 'i', 'm', 5, 'b', 'b', 'w', 'i', 'b', 6, 'b', 'b', 'w', 'i', 'b', 's', 5, 'b', 'b', 'w', 'i', 's', 6, 'b', 'b', 'w', 'i', 's', 's', 6, 'b', 'b', 'w', 'i', 'n', 'g', 5, 'b', 'b', 'w', 'i', 'j', 5, 'b', 'b', 'w', 'i', 'c', 5, 'b', 'b', 'w', 'i', 'k', 5, 'b', 'b', 'w', 'i', 't', 5, 'b', 'b', 'w', 'i', 'p', 5, 'b', 'b', 'w', 'i', 'h', 4, 'b', 'b', 'y', 'u', 5, 'b', 'b', 'y', 'u', 'g', 6, 'b', 'b', 'y', 'u', 'g', 'g', 6, 'b', 'b', 'y', 'u', 'g', 's', 5, 'b', 'b', 'y', 'u', 'n', 6, 'b', 'b', 'y', 'u', 'n', 'j', 6, 'b', 'b', 'y', 'u', 'n', 'h', 5, 'b', 'b', 'y', 'u', 'd', 5, 'b', 'b', 'y', 'u', 'l', 6, 'b', 'b', 'y', 'u', 'l', 'g', 6, 'b', 'b', 'y', 'u', 'l', 'm', 6, 'b', 'b', 'y', 'u', 'l', 'b', 6, 'b', 'b', 'y', 'u', 'l', 's', 6, 'b', 'b', 'y', 'u', 'l', 't', 6, 'b', 'b', 'y', 'u', 'l', 'p', 6, 'b', 'b', 'y', 'u', 'l', 'h', 5, 'b', 'b', 'y', 'u', 'm', 5, 'b', 'b', 'y', 'u', 'b', 6, 'b', 'b', 'y', 'u', 'b', 's', 5, 'b', 'b', 'y', 'u', 's', 6, 'b', 'b', 'y', 'u', 's', 's', 6, 'b', 'b', 'y', 'u', 'n', 'g', 5, 'b', 'b', 'y', 'u', 'j', 5, 'b', 'b', 'y', 'u', 'c', 5, 'b', 'b', 'y', 'u', 'k', 5, 'b', 'b', 'y', 'u', 't', 5, 'b', 'b', 'y', 'u', 'p', 5, 'b', 'b', 'y', 'u', 'h', 4, 'b', 'b', 'e', 'u', 5, 'b', 'b', 'e', 'u', 'g', 6, 'b', 'b', 'e', 'u', 'g', 'g', 6, 'b', 'b', 'e', 'u', 'g', 's', 5, 'b', 'b', 'e', 'u', 'n', 6, 'b', 'b', 'e', 'u', 'n', 'j', 6, 'b', 'b', 'e', 'u', 'n', 'h', 5, 'b', 'b', 'e', 'u', 'd', 5, 'b', 'b', 'e', 'u', 'l', 6, 'b', 'b', 'e', 'u', 'l', 'g', 6, 'b', 'b', 'e', 'u', 'l', 'm', 6, 'b', 'b', 'e', 'u', 'l', 'b', 6, 'b', 'b', 'e', 'u', 'l', 's', 6, 'b', 'b', 'e', 'u', 'l', 't', 6, 'b', 'b', 'e', 'u', 'l', 'p', 6, 'b', 'b', 'e', 'u', 'l', 'h', 5, 'b', 'b', 'e', 'u', 'm', 5, 'b', 'b', 'e', 'u', 'b', 6, 'b', 'b', 'e', 'u', 'b', 's', 5, 'b', 'b', 'e', 'u', 's', 6, 'b', 'b', 'e', 'u', 's', 's', 6, 'b', 'b', 'e', 'u', 'n', 'g', 5, 'b', 'b', 'e', 'u', 'j', 5, 'b', 'b', 'e', 'u', 'c', 5, 'b', 'b', 'e', 'u', 'k', 5, 'b', 'b', 'e', 'u', 't', 5, 'b', 'b', 'e', 'u', 'p', 5, 'b', 'b', 'e', 'u', 'h', 4, 'b', 'b', 'y', 'i', 5, 'b', 'b', 'y', 'i', 'g', 6, 'b', 'b', 'y', 'i', 'g', 'g', 6, 'b', 'b', 'y', 'i', 'g', 's', 5, 'b', 'b', 'y', 'i', 'n', 6, 'b', 'b', 'y', 'i', 'n', 'j', 6, 'b', 'b', 'y', 'i', 'n', 'h', 5, 'b', 'b', 'y', 'i', 'd', 5, 'b', 'b', 'y', 'i', 'l', 6, 'b', 'b', 'y', 'i', 'l', 'g', 6, 'b', 'b', 'y', 'i', 'l', 'm', 6, 'b', 'b', 'y', 'i', 'l', 'b', 6, 'b', 'b', 'y', 'i', 'l', 's', 6, 'b', 'b', 'y', 'i', 'l', 't', 6, 'b', 'b', 'y', 'i', 'l', 'p', 6, 'b', 'b', 'y', 'i', 'l', 'h', 5, 'b', 'b', 'y', 'i', 'm', 5, 'b', 'b', 'y', 'i', 'b', 6, 'b', 'b', 'y', 'i', 'b', 's', 5, 'b', 'b', 'y', 'i', 's', 6, 'b', 'b', 'y', 'i', 's', 's', 6, 'b', 'b', 'y', 'i', 'n', 'g', 5, 'b', 'b', 'y', 'i', 'j', 5, 'b', 'b', 'y', 'i', 'c', 5, 'b', 'b', 'y', 'i', 'k', 5, 'b', 'b', 'y', 'i', 't', 5, 'b', 'b', 'y', 'i', 'p', 5, 'b', 'b', 'y', 'i', 'h', 3, 'b', 'b', 'i', 4, 'b', 'b', 'i', 'g', 5, 'b', 'b', 'i', 'g', 'g', 5, 'b', 'b', 'i', 'g', 's', 4, 'b', 'b', 'i', 'n', 5, 'b', 'b', 'i', 'n', 'j', 5, 'b', 'b', 'i', 'n', 'h', 4, 'b', 'b', 'i', 'd', 4, 'b', 'b', 'i', 'l', 5, 'b', 'b', 'i', 'l', 'g', 5, 'b', 'b', 'i', 'l', 'm', 5, 'b', 'b', 'i', 'l', 'b', 5, 'b', 'b', 'i', 'l', 's', 5, 'b', 'b', 'i', 'l', 't', 5, 'b', 'b', 'i', 'l', 'p', 5, 'b', 'b', 'i', 'l', 'h', 4, 'b', 'b', 'i', 'm', 4, 'b', 'b', 'i', 'b', 5, 'b', 'b', 'i', 'b', 's', 4, 'b', 'b', 'i', 's', 5, 'b', 'b', 'i', 's', 's', 5, 'b', 'b', 'i', 'n', 'g', 4, 'b', 'b', 'i', 'j', 4, 'b', 'b', 'i', 'c', 4, 'b', 'b', 'i', 'k', 4, 'b', 'b', 'i', 't', 4, 'b', 'b', 'i', 'p', 4, 'b', 'b', 'i', 'h', 2, 's', 'a', 3, 's', 'a', 'g', 4, 's', 'a', 'g', 'g', 4, 's', 'a', 'g', 's', 3, 's', 'a', 'n', 4, 's', 'a', 'n', 'j', 4, 's', 'a', 'n', 'h', 3, 's', 'a', 'd', 3, 's', 'a', 'l', 4, 's', 'a', 'l', 'g', 4, 's', 'a', 'l', 'm', 4, 's', 'a', 'l', 'b', 4, 's', 'a', 'l', 's', 4, 's', 'a', 'l', 't', 4, 's', 'a', 'l', 'p', 4, 's', 'a', 'l', 'h', 3, 's', 'a', 'm', 3, 's', 'a', 'b', 4, 's', 'a', 'b', 's', 3, 's', 'a', 's', 4, 's', 'a', 's', 's', 4, 's', 'a', 'n', 'g', 3, 's', 'a', 'j', 3, 's', 'a', 'c', 3, 's', 'a', 'k', 3, 's', 'a', 't', 3, 's', 'a', 'p', 3, 's', 'a', 'h', 3, 's', 'a', 'e', 4, 's', 'a', 'e', 'g', 5, 's', 'a', 'e', 'g', 'g', 5, 's', 'a', 'e', 'g', 's', 4, 's', 'a', 'e', 'n', 5, 's', 'a', 'e', 'n', 'j', 5, 's', 'a', 'e', 'n', 'h', 4, 's', 'a', 'e', 'd', 4, 's', 'a', 'e', 'l', 5, 's', 'a', 'e', 'l', 'g', 5, 's', 'a', 'e', 'l', 'm', 5, 's', 'a', 'e', 'l', 'b', 5, 's', 'a', 'e', 'l', 's', 5, 's', 'a', 'e', 'l', 't', 5, 's', 'a', 'e', 'l', 'p', 5, 's', 'a', 'e', 'l', 'h', 4, 's', 'a', 'e', 'm', 4, 's', 'a', 'e', 'b', 5, 's', 'a', 'e', 'b', 's', 4, 's', 'a', 'e', 's', 5, 's', 'a', 'e', 's', 's', 5, 's', 'a', 'e', 'n', 'g', 4, 's', 'a', 'e', 'j', 4, 's', 'a', 'e', 'c', 4, 's', 'a', 'e', 'k', 4, 's', 'a', 'e', 't', 4, 's', 'a', 'e', 'p', 4, 's', 'a', 'e', 'h', 3, 's', 'y', 'a', 4, 's', 'y', 'a', 'g', 5, 's', 'y', 'a', 'g', 'g', 5, 's', 'y', 'a', 'g', 's', 4, 's', 'y', 'a', 'n', 5, 's', 'y', 'a', 'n', 'j', 5, 's', 'y', 'a', 'n', 'h', 4, 's', 'y', 'a', 'd', 4, 's', 'y', 'a', 'l', 5, 's', 'y', 'a', 'l', 'g', 5, 's', 'y', 'a', 'l', 'm', 5, 's', 'y', 'a', 'l', 'b', 5, 's', 'y', 'a', 'l', 's', 5, 's', 'y', 'a', 'l', 't', 5, 's', 'y', 'a', 'l', 'p', 5, 's', 'y', 'a', 'l', 'h', 4, 's', 'y', 'a', 'm', 4, 's', 'y', 'a', 'b', 5, 's', 'y', 'a', 'b', 's', 4, 's', 'y', 'a', 's', 5, 's', 'y', 'a', 's', 's', 5, 's', 'y', 'a', 'n', 'g', 4, 's', 'y', 'a', 'j', 4, 's', 'y', 'a', 'c', 4, 's', 'y', 'a', 'k', 4, 's', 'y', 'a', 't', 4, 's', 'y', 'a', 'p', 4, 's', 'y', 'a', 'h', 4, 's', 'y', 'a', 'e', 5, 's', 'y', 'a', 'e', 'g', 6, 's', 'y', 'a', 'e', 'g', 'g', 6, 's', 'y', 'a', 'e', 'g', 's', 5, 's', 'y', 'a', 'e', 'n', 6, 's', 'y', 'a', 'e', 'n', 'j', 6, 's', 'y', 'a', 'e', 'n', 'h', 5, 's', 'y', 'a', 'e', 'd', 5, 's', 'y', 'a', 'e', 'l', 6, 's', 'y', 'a', 'e', 'l', 'g', 6, 's', 'y', 'a', 'e', 'l', 'm', 6, 's', 'y', 'a', 'e', 'l', 'b', 6, 's', 'y', 'a', 'e', 'l', 's', 6, 's', 'y', 'a', 'e', 'l', 't', 6, 's', 'y', 'a', 'e', 'l', 'p', 6, 's', 'y', 'a', 'e', 'l', 'h', 5, 's', 'y', 'a', 'e', 'm', 5, 's', 'y', 'a', 'e', 'b', 6, 's', 'y', 'a', 'e', 'b', 's', 5, 's', 'y', 'a', 'e', 's', 6, 's', 'y', 'a', 'e', 's', 's', 6, 's', 'y', 'a', 'e', 'n', 'g', 5, 's', 'y', 'a', 'e', 'j', 5, 's', 'y', 'a', 'e', 'c', 5, 's', 'y', 'a', 'e', 'k', 5, 's', 'y', 'a', 'e', 't', 5, 's', 'y', 'a', 'e', 'p', 5, 's', 'y', 'a', 'e', 'h', 3, 's', 'e', 'o', 4, 's', 'e', 'o', 'g', 5, 's', 'e', 'o', 'g', 'g', 5, 's', 'e', 'o', 'g', 's', 4, 's', 'e', 'o', 'n', 5, 's', 'e', 'o', 'n', 'j', 5, 's', 'e', 'o', 'n', 'h', 4, 's', 'e', 'o', 'd', 4, 's', 'e', 'o', 'l', 5, 's', 'e', 'o', 'l', 'g', 5, 's', 'e', 'o', 'l', 'm', 5, 's', 'e', 'o', 'l', 'b', 5, 's', 'e', 'o', 'l', 's', 5, 's', 'e', 'o', 'l', 't', 5, 's', 'e', 'o', 'l', 'p', 5, 's', 'e', 'o', 'l', 'h', 4, 's', 'e', 'o', 'm', 4, 's', 'e', 'o', 'b', 5, 's', 'e', 'o', 'b', 's', 4, 's', 'e', 'o', 's', 5, 's', 'e', 'o', 's', 's', 5, 's', 'e', 'o', 'n', 'g', 4, 's', 'e', 'o', 'j', 4, 's', 'e', 'o', 'c', 4, 's', 'e', 'o', 'k', 4, 's', 'e', 'o', 't', 4, 's', 'e', 'o', 'p', 4, 's', 'e', 'o', 'h', 2, 's', 'e', 3, 's', 'e', 'g', 4, 's', 'e', 'g', 'g', 4, 's', 'e', 'g', 's', 3, 's', 'e', 'n', 4, 's', 'e', 'n', 'j', 4, 's', 'e', 'n', 'h', 3, 's', 'e', 'd', 3, 's', 'e', 'l', 4, 's', 'e', 'l', 'g', 4, 's', 'e', 'l', 'm', 4, 's', 'e', 'l', 'b', 4, 's', 'e', 'l', 's', 4, 's', 'e', 'l', 't', 4, 's', 'e', 'l', 'p', 4, 's', 'e', 'l', 'h', 3, 's', 'e', 'm', 3, 's', 'e', 'b', 4, 's', 'e', 'b', 's', 3, 's', 'e', 's', 4, 's', 'e', 's', 's', 4, 's', 'e', 'n', 'g', 3, 's', 'e', 'j', 3, 's', 'e', 'c', 3, 's', 'e', 'k', 3, 's', 'e', 't', 3, 's', 'e', 'p', 3, 's', 'e', 'h', 4, 's', 'y', 'e', 'o', 5, 's', 'y', 'e', 'o', 'g', 6, 's', 'y', 'e', 'o', 'g', 'g', 6, 's', 'y', 'e', 'o', 'g', 's', 5, 's', 'y', 'e', 'o', 'n', 6, 's', 'y', 'e', 'o', 'n', 'j', 6, 's', 'y', 'e', 'o', 'n', 'h', 5, 's', 'y', 'e', 'o', 'd', 5, 's', 'y', 'e', 'o', 'l', 6, 's', 'y', 'e', 'o', 'l', 'g', 6, 's', 'y', 'e', 'o', 'l', 'm', 6, 's', 'y', 'e', 'o', 'l', 'b', 6, 's', 'y', 'e', 'o', 'l', 's', 6, 's', 'y', 'e', 'o', 'l', 't', 6, 's', 'y', 'e', 'o', 'l', 'p', 6, 's', 'y', 'e', 'o', 'l', 'h', 5, 's', 'y', 'e', 'o', 'm', 5, 's', 'y', 'e', 'o', 'b', 6, 's', 'y', 'e', 'o', 'b', 's', 5, 's', 'y', 'e', 'o', 's', 6, 's', 'y', 'e', 'o', 's', 's', 6, 's', 'y', 'e', 'o', 'n', 'g', 5, 's', 'y', 'e', 'o', 'j', 5, 's', 'y', 'e', 'o', 'c', 5, 's', 'y', 'e', 'o', 'k', 5, 's', 'y', 'e', 'o', 't', 5, 's', 'y', 'e', 'o', 'p', 5, 's', 'y', 'e', 'o', 'h', 3, 's', 'y', 'e', 4, 's', 'y', 'e', 'g', 5, 's', 'y', 'e', 'g', 'g', 5, 's', 'y', 'e', 'g', 's', 4, 's', 'y', 'e', 'n', 5, 's', 'y', 'e', 'n', 'j', 5, 's', 'y', 'e', 'n', 'h', 4, 's', 'y', 'e', 'd', 4, 's', 'y', 'e', 'l', 5, 's', 'y', 'e', 'l', 'g', 5, 's', 'y', 'e', 'l', 'm', 5, 's', 'y', 'e', 'l', 'b', 5, 's', 'y', 'e', 'l', 's', 5, 's', 'y', 'e', 'l', 't', 5, 's', 'y', 'e', 'l', 'p', 5, 's', 'y', 'e', 'l', 'h', 4, 's', 'y', 'e', 'm', 4, 's', 'y', 'e', 'b', 5, 's', 'y', 'e', 'b', 's', 4, 's', 'y', 'e', 's', 5, 's', 'y', 'e', 's', 's', 5, 's', 'y', 'e', 'n', 'g', 4, 's', 'y', 'e', 'j', 4, 's', 'y', 'e', 'c', 4, 's', 'y', 'e', 'k', 4, 's', 'y', 'e', 't', 4, 's', 'y', 'e', 'p', 4, 's', 'y', 'e', 'h', 2, 's', 'o', 3, 's', 'o', 'g', 4, 's', 'o', 'g', 'g', 4, 's', 'o', 'g', 's', 3, 's', 'o', 'n', 4, 's', 'o', 'n', 'j', 4, 's', 'o', 'n', 'h', 3, 's', 'o', 'd', 3, 's', 'o', 'l', 4, 's', 'o', 'l', 'g', 4, 's', 'o', 'l', 'm', 4, 's', 'o', 'l', 'b', 4, 's', 'o', 'l', 's', 4, 's', 'o', 'l', 't', 4, 's', 'o', 'l', 'p', 4, 's', 'o', 'l', 'h', 3, 's', 'o', 'm', 3, 's', 'o', 'b', 4, 's', 'o', 'b', 's', 3, 's', 'o', 's', 4, 's', 'o', 's', 's', 4, 's', 'o', 'n', 'g', 3, 's', 'o', 'j', 3, 's', 'o', 'c', 3, 's', 'o', 'k', 3, 's', 'o', 't', 3, 's', 'o', 'p', 3, 's', 'o', 'h', 3, 's', 'w', 'a', 4, 's', 'w', 'a', 'g', 5, 's', 'w', 'a', 'g', 'g', 5, 's', 'w', 'a', 'g', 's', 4, 's', 'w', 'a', 'n', 5, 's', 'w', 'a', 'n', 'j', 5, 's', 'w', 'a', 'n', 'h', 4, 's', 'w', 'a', 'd', 4, 's', 'w', 'a', 'l', 5, 's', 'w', 'a', 'l', 'g', 5, 's', 'w', 'a', 'l', 'm', 5, 's', 'w', 'a', 'l', 'b', 5, 's', 'w', 'a', 'l', 's', 5, 's', 'w', 'a', 'l', 't', 5, 's', 'w', 'a', 'l', 'p', 5, 's', 'w', 'a', 'l', 'h', 4, 's', 'w', 'a', 'm', 4, 's', 'w', 'a', 'b', 5, 's', 'w', 'a', 'b', 's', 4, 's', 'w', 'a', 's', 5, 's', 'w', 'a', 's', 's', 5, 's', 'w', 'a', 'n', 'g', 4, 's', 'w', 'a', 'j', 4, 's', 'w', 'a', 'c', 4, 's', 'w', 'a', 'k', 4, 's', 'w', 'a', 't', 4, 's', 'w', 'a', 'p', 4, 's', 'w', 'a', 'h', 4, 's', 'w', 'a', 'e', 5, 's', 'w', 'a', 'e', 'g', 6, 's', 'w', 'a', 'e', 'g', 'g', 6, 's', 'w', 'a', 'e', 'g', 's', 5, 's', 'w', 'a', 'e', 'n', 6, 's', 'w', 'a', 'e', 'n', 'j', 6, 's', 'w', 'a', 'e', 'n', 'h', 5, 's', 'w', 'a', 'e', 'd', 5, 's', 'w', 'a', 'e', 'l', 6, 's', 'w', 'a', 'e', 'l', 'g', 6, 's', 'w', 'a', 'e', 'l', 'm', 6, 's', 'w', 'a', 'e', 'l', 'b', 6, 's', 'w', 'a', 'e', 'l', 's', 6, 's', 'w', 'a', 'e', 'l', 't', 6, 's', 'w', 'a', 'e', 'l', 'p', 6, 's', 'w', 'a', 'e', 'l', 'h', 5, 's', 'w', 'a', 'e', 'm', 5, 's', 'w', 'a', 'e', 'b', 6, 's', 'w', 'a', 'e', 'b', 's', 5, 's', 'w', 'a', 'e', 's', 6, 's', 'w', 'a', 'e', 's', 's', 6, 's', 'w', 'a', 'e', 'n', 'g', 5, 's', 'w', 'a', 'e', 'j', 5, 's', 'w', 'a', 'e', 'c', 5, 's', 'w', 'a', 'e', 'k', 5, 's', 'w', 'a', 'e', 't', 5, 's', 'w', 'a', 'e', 'p', 5, 's', 'w', 'a', 'e', 'h', 3, 's', 'o', 'e', 4, 's', 'o', 'e', 'g', 5, 's', 'o', 'e', 'g', 'g', 5, 's', 'o', 'e', 'g', 's', 4, 's', 'o', 'e', 'n', 5, 's', 'o', 'e', 'n', 'j', 5, 's', 'o', 'e', 'n', 'h', 4, 's', 'o', 'e', 'd', 4, 's', 'o', 'e', 'l', 5, 's', 'o', 'e', 'l', 'g', 5, 's', 'o', 'e', 'l', 'm', 5, 's', 'o', 'e', 'l', 'b', 5, 's', 'o', 'e', 'l', 's', 5, 's', 'o', 'e', 'l', 't', 5, 's', 'o', 'e', 'l', 'p', 5, 's', 'o', 'e', 'l', 'h', 4, 's', 'o', 'e', 'm', 4, 's', 'o', 'e', 'b', 5, 's', 'o', 'e', 'b', 's', 4, 's', 'o', 'e', 's', 5, 's', 'o', 'e', 's', 's', 5, 's', 'o', 'e', 'n', 'g', 4, 's', 'o', 'e', 'j', 4, 's', 'o', 'e', 'c', 4, 's', 'o', 'e', 'k', 4, 's', 'o', 'e', 't', 4, 's', 'o', 'e', 'p', 4, 's', 'o', 'e', 'h', 3, 's', 'y', 'o', 4, 's', 'y', 'o', 'g', 5, 's', 'y', 'o', 'g', 'g', 5, 's', 'y', 'o', 'g', 's', 4, 's', 'y', 'o', 'n', 5, 's', 'y', 'o', 'n', 'j', 5, 's', 'y', 'o', 'n', 'h', 4, 's', 'y', 'o', 'd', 4, 's', 'y', 'o', 'l', 5, 's', 'y', 'o', 'l', 'g', 5, 's', 'y', 'o', 'l', 'm', 5, 's', 'y', 'o', 'l', 'b', 5, 's', 'y', 'o', 'l', 's', 5, 's', 'y', 'o', 'l', 't', 5, 's', 'y', 'o', 'l', 'p', 5, 's', 'y', 'o', 'l', 'h', 4, 's', 'y', 'o', 'm', 4, 's', 'y', 'o', 'b', 5, 's', 'y', 'o', 'b', 's', 4, 's', 'y', 'o', 's', 5, 's', 'y', 'o', 's', 's', 5, 's', 'y', 'o', 'n', 'g', 4, 's', 'y', 'o', 'j', 4, 's', 'y', 'o', 'c', 4, 's', 'y', 'o', 'k', 4, 's', 'y', 'o', 't', 4, 's', 'y', 'o', 'p', 4, 's', 'y', 'o', 'h', 2, 's', 'u', 3, 's', 'u', 'g', 4, 's', 'u', 'g', 'g', 4, 's', 'u', 'g', 's', 3, 's', 'u', 'n', 4, 's', 'u', 'n', 'j', 4, 's', 'u', 'n', 'h', 3, 's', 'u', 'd', 3, 's', 'u', 'l', 4, 's', 'u', 'l', 'g', 4, 's', 'u', 'l', 'm', 4, 's', 'u', 'l', 'b', 4, 's', 'u', 'l', 's', 4, 's', 'u', 'l', 't', 4, 's', 'u', 'l', 'p', 4, 's', 'u', 'l', 'h', 3, 's', 'u', 'm', 3, 's', 'u', 'b', 4, 's', 'u', 'b', 's', 3, 's', 'u', 's', 4, 's', 'u', 's', 's', 4, 's', 'u', 'n', 'g', 3, 's', 'u', 'j', 3, 's', 'u', 'c', 3, 's', 'u', 'k', 3, 's', 'u', 't', 3, 's', 'u', 'p', 3, 's', 'u', 'h', 4, 's', 'w', 'e', 'o', 5, 's', 'w', 'e', 'o', 'g', 6, 's', 'w', 'e', 'o', 'g', 'g', 6, 's', 'w', 'e', 'o', 'g', 's', 5, 's', 'w', 'e', 'o', 'n', 6, 's', 'w', 'e', 'o', 'n', 'j', 6, 's', 'w', 'e', 'o', 'n', 'h', 5, 's', 'w', 'e', 'o', 'd', 5, 's', 'w', 'e', 'o', 'l', 6, 's', 'w', 'e', 'o', 'l', 'g', 6, 's', 'w', 'e', 'o', 'l', 'm', 6, 's', 'w', 'e', 'o', 'l', 'b', 6, 's', 'w', 'e', 'o', 'l', 's', 6, 's', 'w', 'e', 'o', 'l', 't', 6, 's', 'w', 'e', 'o', 'l', 'p', 6, 's', 'w', 'e', 'o', 'l', 'h', 5, 's', 'w', 'e', 'o', 'm', 5, 's', 'w', 'e', 'o', 'b', 6, 's', 'w', 'e', 'o', 'b', 's', 5, 's', 'w', 'e', 'o', 's', 6, 's', 'w', 'e', 'o', 's', 's', 6, 's', 'w', 'e', 'o', 'n', 'g', 5, 's', 'w', 'e', 'o', 'j', 5, 's', 'w', 'e', 'o', 'c', 5, 's', 'w', 'e', 'o', 'k', 5, 's', 'w', 'e', 'o', 't', 5, 's', 'w', 'e', 'o', 'p', 5, 's', 'w', 'e', 'o', 'h', 3, 's', 'w', 'e', 4, 's', 'w', 'e', 'g', 5, 's', 'w', 'e', 'g', 'g', 5, 's', 'w', 'e', 'g', 's', 4, 's', 'w', 'e', 'n', 5, 's', 'w', 'e', 'n', 'j', 5, 's', 'w', 'e', 'n', 'h', 4, 's', 'w', 'e', 'd', 4, 's', 'w', 'e', 'l', 5, 's', 'w', 'e', 'l', 'g', 5, 's', 'w', 'e', 'l', 'm', 5, 's', 'w', 'e', 'l', 'b', 5, 's', 'w', 'e', 'l', 's', 5, 's', 'w', 'e', 'l', 't', 5, 's', 'w', 'e', 'l', 'p', 5, 's', 'w', 'e', 'l', 'h', 4, 's', 'w', 'e', 'm', 4, 's', 'w', 'e', 'b', 5, 's', 'w', 'e', 'b', 's', 4, 's', 'w', 'e', 's', 5, 's', 'w', 'e', 's', 's', 5, 's', 'w', 'e', 'n', 'g', 4, 's', 'w', 'e', 'j', 4, 's', 'w', 'e', 'c', 4, 's', 'w', 'e', 'k', 4, 's', 'w', 'e', 't', 4, 's', 'w', 'e', 'p', 4, 's', 'w', 'e', 'h', 3, 's', 'w', 'i', 4, 's', 'w', 'i', 'g', 5, 's', 'w', 'i', 'g', 'g', 5, 's', 'w', 'i', 'g', 's', 4, 's', 'w', 'i', 'n', 5, 's', 'w', 'i', 'n', 'j', 5, 's', 'w', 'i', 'n', 'h', 4, 's', 'w', 'i', 'd', 4, 's', 'w', 'i', 'l', 5, 's', 'w', 'i', 'l', 'g', 5, 's', 'w', 'i', 'l', 'm', 5, 's', 'w', 'i', 'l', 'b', 5, 's', 'w', 'i', 'l', 's', 5, 's', 'w', 'i', 'l', 't', 5, 's', 'w', 'i', 'l', 'p', 5, 's', 'w', 'i', 'l', 'h', 4, 's', 'w', 'i', 'm', 4, 's', 'w', 'i', 'b', 5, 's', 'w', 'i', 'b', 's', 4, 's', 'w', 'i', 's', 5, 's', 'w', 'i', 's', 's', 5, 's', 'w', 'i', 'n', 'g', 4, 's', 'w', 'i', 'j', 4, 's', 'w', 'i', 'c', 4, 's', 'w', 'i', 'k', 4, 's', 'w', 'i', 't', 4, 's', 'w', 'i', 'p', 4, 's', 'w', 'i', 'h', 3, 's', 'y', 'u', 4, 's', 'y', 'u', 'g', 5, 's', 'y', 'u', 'g', 'g', 5, 's', 'y', 'u', 'g', 's', 4, 's', 'y', 'u', 'n', 5, 's', 'y', 'u', 'n', 'j', 5, 's', 'y', 'u', 'n', 'h', 4, 's', 'y', 'u', 'd', 4, 's', 'y', 'u', 'l', 5, 's', 'y', 'u', 'l', 'g', 5, 's', 'y', 'u', 'l', 'm', 5, 's', 'y', 'u', 'l', 'b', 5, 's', 'y', 'u', 'l', 's', 5, 's', 'y', 'u', 'l', 't', 5, 's', 'y', 'u', 'l', 'p', 5, 's', 'y', 'u', 'l', 'h', 4, 's', 'y', 'u', 'm', 4, 's', 'y', 'u', 'b', 5, 's', 'y', 'u', 'b', 's', 4, 's', 'y', 'u', 's', 5, 's', 'y', 'u', 's', 's', 5, 's', 'y', 'u', 'n', 'g', 4, 's', 'y', 'u', 'j', 4, 's', 'y', 'u', 'c', 4, 's', 'y', 'u', 'k', 4, 's', 'y', 'u', 't', 4, 's', 'y', 'u', 'p', 4, 's', 'y', 'u', 'h', 3, 's', 'e', 'u', 4, 's', 'e', 'u', 'g', 5, 's', 'e', 'u', 'g', 'g', 5, 's', 'e', 'u', 'g', 's', 4, 's', 'e', 'u', 'n', 5, 's', 'e', 'u', 'n', 'j', 5, 's', 'e', 'u', 'n', 'h', 4, 's', 'e', 'u', 'd', 4, 's', 'e', 'u', 'l', 5, 's', 'e', 'u', 'l', 'g', 5, 's', 'e', 'u', 'l', 'm', 5, 's', 'e', 'u', 'l', 'b', 5, 's', 'e', 'u', 'l', 's', 5, 's', 'e', 'u', 'l', 't', 5, 's', 'e', 'u', 'l', 'p', 5, 's', 'e', 'u', 'l', 'h', 4, 's', 'e', 'u', 'm', 4, 's', 'e', 'u', 'b', 5, 's', 'e', 'u', 'b', 's', 4, 's', 'e', 'u', 's', 5, 's', 'e', 'u', 's', 's', 5, 's', 'e', 'u', 'n', 'g', 4, 's', 'e', 'u', 'j', 4, 's', 'e', 'u', 'c', 4, 's', 'e', 'u', 'k', 4, 's', 'e', 'u', 't', 4, 's', 'e', 'u', 'p', 4, 's', 'e', 'u', 'h', 3, 's', 'y', 'i', 4, 's', 'y', 'i', 'g', 5, 's', 'y', 'i', 'g', 'g', 5, 's', 'y', 'i', 'g', 's', 4, 's', 'y', 'i', 'n', 5, 's', 'y', 'i', 'n', 'j', 5, 's', 'y', 'i', 'n', 'h', 4, 's', 'y', 'i', 'd', 4, 's', 'y', 'i', 'l', 5, 's', 'y', 'i', 'l', 'g', 5, 's', 'y', 'i', 'l', 'm', 5, 's', 'y', 'i', 'l', 'b', 5, 's', 'y', 'i', 'l', 's', 5, 's', 'y', 'i', 'l', 't', 5, 's', 'y', 'i', 'l', 'p', 5, 's', 'y', 'i', 'l', 'h', 4, 's', 'y', 'i', 'm', 4, 's', 'y', 'i', 'b', 5, 's', 'y', 'i', 'b', 's', 4, 's', 'y', 'i', 's', 5, 's', 'y', 'i', 's', 's', 5, 's', 'y', 'i', 'n', 'g', 4, 's', 'y', 'i', 'j', 4, 's', 'y', 'i', 'c', 4, 's', 'y', 'i', 'k', 4, 's', 'y', 'i', 't', 4, 's', 'y', 'i', 'p', 4, 's', 'y', 'i', 'h', 2, 's', 'i', 3, 's', 'i', 'g', 4, 's', 'i', 'g', 'g', 4, 's', 'i', 'g', 's', 3, 's', 'i', 'n', 4, 's', 'i', 'n', 'j', 4, 's', 'i', 'n', 'h', 3, 's', 'i', 'd', 3, 's', 'i', 'l', 4, 's', 'i', 'l', 'g', 4, 's', 'i', 'l', 'm', 4, 's', 'i', 'l', 'b', 4, 's', 'i', 'l', 's', 4, 's', 'i', 'l', 't', 4, 's', 'i', 'l', 'p', 4, 's', 'i', 'l', 'h', 3, 's', 'i', 'm', 3, 's', 'i', 'b', 4, 's', 'i', 'b', 's', 3, 's', 'i', 's', 4, 's', 'i', 's', 's', 4, 's', 'i', 'n', 'g', 3, 's', 'i', 'j', 3, 's', 'i', 'c', 3, 's', 'i', 'k', 3, 's', 'i', 't', 3, 's', 'i', 'p', 3, 's', 'i', 'h', 3, 's', 's', 'a', 4, 's', 's', 'a', 'g', 5, 's', 's', 'a', 'g', 'g', 5, 's', 's', 'a', 'g', 's', 4, 's', 's', 'a', 'n', 5, 's', 's', 'a', 'n', 'j', 5, 's', 's', 'a', 'n', 'h', 4, 's', 's', 'a', 'd', 4, 's', 's', 'a', 'l', 5, 's', 's', 'a', 'l', 'g', 5, 's', 's', 'a', 'l', 'm', 5, 's', 's', 'a', 'l', 'b', 5, 's', 's', 'a', 'l', 's', 5, 's', 's', 'a', 'l', 't', 5, 's', 's', 'a', 'l', 'p', 5, 's', 's', 'a', 'l', 'h', 4, 's', 's', 'a', 'm', 4, 's', 's', 'a', 'b', 5, 's', 's', 'a', 'b', 's', 4, 's', 's', 'a', 's', 5, 's', 's', 'a', 's', 's', 5, 's', 's', 'a', 'n', 'g', 4, 's', 's', 'a', 'j', 4, 's', 's', 'a', 'c', 4, 's', 's', 'a', 'k', 4, 's', 's', 'a', 't', 4, 's', 's', 'a', 'p', 4, 's', 's', 'a', 'h', 4, 's', 's', 'a', 'e', 5, 's', 's', 'a', 'e', 'g', 6, 's', 's', 'a', 'e', 'g', 'g', 6, 's', 's', 'a', 'e', 'g', 's', 5, 's', 's', 'a', 'e', 'n', 6, 's', 's', 'a', 'e', 'n', 'j', 6, 's', 's', 'a', 'e', 'n', 'h', 5, 's', 's', 'a', 'e', 'd', 5, 's', 's', 'a', 'e', 'l', 6, 's', 's', 'a', 'e', 'l', 'g', 6, 's', 's', 'a', 'e', 'l', 'm', 6, 's', 's', 'a', 'e', 'l', 'b', 6, 's', 's', 'a', 'e', 'l', 's', 6, 's', 's', 'a', 'e', 'l', 't', 6, 's', 's', 'a', 'e', 'l', 'p', 6, 's', 's', 'a', 'e', 'l', 'h', 5, 's', 's', 'a', 'e', 'm', 5, 's', 's', 'a', 'e', 'b', 6, 's', 's', 'a', 'e', 'b', 's', 5, 's', 's', 'a', 'e', 's', 6, 's', 's', 'a', 'e', 's', 's', 6, 's', 's', 'a', 'e', 'n', 'g', 5, 's', 's', 'a', 'e', 'j', 5, 's', 's', 'a', 'e', 'c', 5, 's', 's', 'a', 'e', 'k', 5, 's', 's', 'a', 'e', 't', 5, 's', 's', 'a', 'e', 'p', 5, 's', 's', 'a', 'e', 'h', 4, 's', 's', 'y', 'a', 5, 's', 's', 'y', 'a', 'g', 6, 's', 's', 'y', 'a', 'g', 'g', 6, 's', 's', 'y', 'a', 'g', 's', 5, 's', 's', 'y', 'a', 'n', 6, 's', 's', 'y', 'a', 'n', 'j', 6, 's', 's', 'y', 'a', 'n', 'h', 5, 's', 's', 'y', 'a', 'd', 5, 's', 's', 'y', 'a', 'l', 6, 's', 's', 'y', 'a', 'l', 'g', 6, 's', 's', 'y', 'a', 'l', 'm', 6, 's', 's', 'y', 'a', 'l', 'b', 6, 's', 's', 'y', 'a', 'l', 's', 6, 's', 's', 'y', 'a', 'l', 't', 6, 's', 's', 'y', 'a', 'l', 'p', 6, 's', 's', 'y', 'a', 'l', 'h', 5, 's', 's', 'y', 'a', 'm', 5, 's', 's', 'y', 'a', 'b', 6, 's', 's', 'y', 'a', 'b', 's', 5, 's', 's', 'y', 'a', 's', 6, 's', 's', 'y', 'a', 's', 's', 6, 's', 's', 'y', 'a', 'n', 'g', 5, 's', 's', 'y', 'a', 'j', 5, 's', 's', 'y', 'a', 'c', 5, 's', 's', 'y', 'a', 'k', 5, 's', 's', 'y', 'a', 't', 5, 's', 's', 'y', 'a', 'p', 5, 's', 's', 'y', 'a', 'h', 5, 's', 's', 'y', 'a', 'e', 6, 's', 's', 'y', 'a', 'e', 'g', 7, 's', 's', 'y', 'a', 'e', 'g', 'g', 7, 's', 's', 'y', 'a', 'e', 'g', 's', 6, 's', 's', 'y', 'a', 'e', 'n', 7, 's', 's', 'y', 'a', 'e', 'n', 'j', 7, 's', 's', 'y', 'a', 'e', 'n', 'h', 6, 's', 's', 'y', 'a', 'e', 'd', 6, 's', 's', 'y', 'a', 'e', 'l', 7, 's', 's', 'y', 'a', 'e', 'l', 'g', 7, 's', 's', 'y', 'a', 'e', 'l', 'm', 7, 's', 's', 'y', 'a', 'e', 'l', 'b', 7, 's', 's', 'y', 'a', 'e', 'l', 's', 7, 's', 's', 'y', 'a', 'e', 'l', 't', 7, 's', 's', 'y', 'a', 'e', 'l', 'p', 7, 's', 's', 'y', 'a', 'e', 'l', 'h', 6, 's', 's', 'y', 'a', 'e', 'm', 6, 's', 's', 'y', 'a', 'e', 'b', 7, 's', 's', 'y', 'a', 'e', 'b', 's', 6, 's', 's', 'y', 'a', 'e', 's', 7, 's', 's', 'y', 'a', 'e', 's', 's', 7, 's', 's', 'y', 'a', 'e', 'n', 'g', 6, 's', 's', 'y', 'a', 'e', 'j', 6, 's', 's', 'y', 'a', 'e', 'c', 6, 's', 's', 'y', 'a', 'e', 'k', 6, 's', 's', 'y', 'a', 'e', 't', 6, 's', 's', 'y', 'a', 'e', 'p', 6, 's', 's', 'y', 'a', 'e', 'h', 4, 's', 's', 'e', 'o', 5, 's', 's', 'e', 'o', 'g', 6, 's', 's', 'e', 'o', 'g', 'g', 6, 's', 's', 'e', 'o', 'g', 's', 5, 's', 's', 'e', 'o', 'n', 6, 's', 's', 'e', 'o', 'n', 'j', 6, 's', 's', 'e', 'o', 'n', 'h', 5, 's', 's', 'e', 'o', 'd', 5, 's', 's', 'e', 'o', 'l', 6, 's', 's', 'e', 'o', 'l', 'g', 6, 's', 's', 'e', 'o', 'l', 'm', 6, 's', 's', 'e', 'o', 'l', 'b', 6, 's', 's', 'e', 'o', 'l', 's', 6, 's', 's', 'e', 'o', 'l', 't', 6, 's', 's', 'e', 'o', 'l', 'p', 6, 's', 's', 'e', 'o', 'l', 'h', 5, 's', 's', 'e', 'o', 'm', 5, 's', 's', 'e', 'o', 'b', 6, 's', 's', 'e', 'o', 'b', 's', 5, 's', 's', 'e', 'o', 's', 6, 's', 's', 'e', 'o', 's', 's', 6, 's', 's', 'e', 'o', 'n', 'g', 5, 's', 's', 'e', 'o', 'j', 5, 's', 's', 'e', 'o', 'c', 5, 's', 's', 'e', 'o', 'k', 5, 's', 's', 'e', 'o', 't', 5, 's', 's', 'e', 'o', 'p', 5, 's', 's', 'e', 'o', 'h', 3, 's', 's', 'e', 4, 's', 's', 'e', 'g', 5, 's', 's', 'e', 'g', 'g', 5, 's', 's', 'e', 'g', 's', 4, 's', 's', 'e', 'n', 5, 's', 's', 'e', 'n', 'j', 5, 's', 's', 'e', 'n', 'h', 4, 's', 's', 'e', 'd', 4, 's', 's', 'e', 'l', 5, 's', 's', 'e', 'l', 'g', 5, 's', 's', 'e', 'l', 'm', 5, 's', 's', 'e', 'l', 'b', 5, 's', 's', 'e', 'l', 's', 5, 's', 's', 'e', 'l', 't', 5, 's', 's', 'e', 'l', 'p', 5, 's', 's', 'e', 'l', 'h', 4, 's', 's', 'e', 'm', 4, 's', 's', 'e', 'b', 5, 's', 's', 'e', 'b', 's', 4, 's', 's', 'e', 's', 5, 's', 's', 'e', 's', 's', 5, 's', 's', 'e', 'n', 'g', 4, 's', 's', 'e', 'j', 4, 's', 's', 'e', 'c', 4, 's', 's', 'e', 'k', 4, 's', 's', 'e', 't', 4, 's', 's', 'e', 'p', 4, 's', 's', 'e', 'h', 5, 's', 's', 'y', 'e', 'o', 6, 's', 's', 'y', 'e', 'o', 'g', 7, 's', 's', 'y', 'e', 'o', 'g', 'g', 7, 's', 's', 'y', 'e', 'o', 'g', 's', 6, 's', 's', 'y', 'e', 'o', 'n', 7, 's', 's', 'y', 'e', 'o', 'n', 'j', 7, 's', 's', 'y', 'e', 'o', 'n', 'h', 6, 's', 's', 'y', 'e', 'o', 'd', 6, 's', 's', 'y', 'e', 'o', 'l', 7, 's', 's', 'y', 'e', 'o', 'l', 'g', 7, 's', 's', 'y', 'e', 'o', 'l', 'm', 7, 's', 's', 'y', 'e', 'o', 'l', 'b', 7, 's', 's', 'y', 'e', 'o', 'l', 's', 7, 's', 's', 'y', 'e', 'o', 'l', 't', 7, 's', 's', 'y', 'e', 'o', 'l', 'p', 7, 's', 's', 'y', 'e', 'o', 'l', 'h', 6, 's', 's', 'y', 'e', 'o', 'm', 6, 's', 's', 'y', 'e', 'o', 'b', 7, 's', 's', 'y', 'e', 'o', 'b', 's', 6, 's', 's', 'y', 'e', 'o', 's', 7, 's', 's', 'y', 'e', 'o', 's', 's', 7, 's', 's', 'y', 'e', 'o', 'n', 'g', 6, 's', 's', 'y', 'e', 'o', 'j', 6, 's', 's', 'y', 'e', 'o', 'c', 6, 's', 's', 'y', 'e', 'o', 'k', 6, 's', 's', 'y', 'e', 'o', 't', 6, 's', 's', 'y', 'e', 'o', 'p', 6, 's', 's', 'y', 'e', 'o', 'h', 4, 's', 's', 'y', 'e', 5, 's', 's', 'y', 'e', 'g', 6, 's', 's', 'y', 'e', 'g', 'g', 6, 's', 's', 'y', 'e', 'g', 's', 5, 's', 's', 'y', 'e', 'n', 6, 's', 's', 'y', 'e', 'n', 'j', 6, 's', 's', 'y', 'e', 'n', 'h', 5, 's', 's', 'y', 'e', 'd', 5, 's', 's', 'y', 'e', 'l', 6, 's', 's', 'y', 'e', 'l', 'g', 6, 's', 's', 'y', 'e', 'l', 'm', 6, 's', 's', 'y', 'e', 'l', 'b', 6, 's', 's', 'y', 'e', 'l', 's', 6, 's', 's', 'y', 'e', 'l', 't', 6, 's', 's', 'y', 'e', 'l', 'p', 6, 's', 's', 'y', 'e', 'l', 'h', 5, 's', 's', 'y', 'e', 'm', 5, 's', 's', 'y', 'e', 'b', 6, 's', 's', 'y', 'e', 'b', 's', 5, 's', 's', 'y', 'e', 's', 6, 's', 's', 'y', 'e', 's', 's', 6, 's', 's', 'y', 'e', 'n', 'g', 5, 's', 's', 'y', 'e', 'j', 5, 's', 's', 'y', 'e', 'c', 5, 's', 's', 'y', 'e', 'k', 5, 's', 's', 'y', 'e', 't', 5, 's', 's', 'y', 'e', 'p', 5, 's', 's', 'y', 'e', 'h', 3, 's', 's', 'o', 4, 's', 's', 'o', 'g', 5, 's', 's', 'o', 'g', 'g', 5, 's', 's', 'o', 'g', 's', 4, 's', 's', 'o', 'n', 5, 's', 's', 'o', 'n', 'j', 5, 's', 's', 'o', 'n', 'h', 4, 's', 's', 'o', 'd', 4, 's', 's', 'o', 'l', 5, 's', 's', 'o', 'l', 'g', 5, 's', 's', 'o', 'l', 'm', 5, 's', 's', 'o', 'l', 'b', 5, 's', 's', 'o', 'l', 's', 5, 's', 's', 'o', 'l', 't', 5, 's', 's', 'o', 'l', 'p', 5, 's', 's', 'o', 'l', 'h', 4, 's', 's', 'o', 'm', 4, 's', 's', 'o', 'b', 5, 's', 's', 'o', 'b', 's', 4, 's', 's', 'o', 's', 5, 's', 's', 'o', 's', 's', 5, 's', 's', 'o', 'n', 'g', 4, 's', 's', 'o', 'j', 4, 's', 's', 'o', 'c', 4, 's', 's', 'o', 'k', 4, 's', 's', 'o', 't', 4, 's', 's', 'o', 'p', 4, 's', 's', 'o', 'h', 4, 's', 's', 'w', 'a', 5, 's', 's', 'w', 'a', 'g', 6, 's', 's', 'w', 'a', 'g', 'g', 6, 's', 's', 'w', 'a', 'g', 's', 5, 's', 's', 'w', 'a', 'n', 6, 's', 's', 'w', 'a', 'n', 'j', 6, 's', 's', 'w', 'a', 'n', 'h', 5, 's', 's', 'w', 'a', 'd', 5, 's', 's', 'w', 'a', 'l', 6, 's', 's', 'w', 'a', 'l', 'g', 6, 's', 's', 'w', 'a', 'l', 'm', 6, 's', 's', 'w', 'a', 'l', 'b', 6, 's', 's', 'w', 'a', 'l', 's', 6, 's', 's', 'w', 'a', 'l', 't', 6, 's', 's', 'w', 'a', 'l', 'p', 6, 's', 's', 'w', 'a', 'l', 'h', 5, 's', 's', 'w', 'a', 'm', 5, 's', 's', 'w', 'a', 'b', 6, 's', 's', 'w', 'a', 'b', 's', 5, 's', 's', 'w', 'a', 's', 6, 's', 's', 'w', 'a', 's', 's', 6, 's', 's', 'w', 'a', 'n', 'g', 5, 's', 's', 'w', 'a', 'j', 5, 's', 's', 'w', 'a', 'c', 5, 's', 's', 'w', 'a', 'k', 5, 's', 's', 'w', 'a', 't', 5, 's', 's', 'w', 'a', 'p', 5, 's', 's', 'w', 'a', 'h', 5, 's', 's', 'w', 'a', 'e', 6, 's', 's', 'w', 'a', 'e', 'g', 7, 's', 's', 'w', 'a', 'e', 'g', 'g', 7, 's', 's', 'w', 'a', 'e', 'g', 's', 6, 's', 's', 'w', 'a', 'e', 'n', 7, 's', 's', 'w', 'a', 'e', 'n', 'j', 7, 's', 's', 'w', 'a', 'e', 'n', 'h', 6, 's', 's', 'w', 'a', 'e', 'd', 6, 's', 's', 'w', 'a', 'e', 'l', 7, 's', 's', 'w', 'a', 'e', 'l', 'g', 7, 's', 's', 'w', 'a', 'e', 'l', 'm', 7, 's', 's', 'w', 'a', 'e', 'l', 'b', 7, 's', 's', 'w', 'a', 'e', 'l', 's', 7, 's', 's', 'w', 'a', 'e', 'l', 't', 7, 's', 's', 'w', 'a', 'e', 'l', 'p', 7, 's', 's', 'w', 'a', 'e', 'l', 'h', 6, 's', 's', 'w', 'a', 'e', 'm', 6, 's', 's', 'w', 'a', 'e', 'b', 7, 's', 's', 'w', 'a', 'e', 'b', 's', 6, 's', 's', 'w', 'a', 'e', 's', 7, 's', 's', 'w', 'a', 'e', 's', 's', 7, 's', 's', 'w', 'a', 'e', 'n', 'g', 6, 's', 's', 'w', 'a', 'e', 'j', 6, 's', 's', 'w', 'a', 'e', 'c', 6, 's', 's', 'w', 'a', 'e', 'k', 6, 's', 's', 'w', 'a', 'e', 't', 6, 's', 's', 'w', 'a', 'e', 'p', 6, 's', 's', 'w', 'a', 'e', 'h', 4, 's', 's', 'o', 'e', 5, 's', 's', 'o', 'e', 'g', 6, 's', 's', 'o', 'e', 'g', 'g', 6, 's', 's', 'o', 'e', 'g', 's', 5, 's', 's', 'o', 'e', 'n', 6, 's', 's', 'o', 'e', 'n', 'j', 6, 's', 's', 'o', 'e', 'n', 'h', 5, 's', 's', 'o', 'e', 'd', 5, 's', 's', 'o', 'e', 'l', 6, 's', 's', 'o', 'e', 'l', 'g', 6, 's', 's', 'o', 'e', 'l', 'm', 6, 's', 's', 'o', 'e', 'l', 'b', 6, 's', 's', 'o', 'e', 'l', 's', 6, 's', 's', 'o', 'e', 'l', 't', 6, 's', 's', 'o', 'e', 'l', 'p', 6, 's', 's', 'o', 'e', 'l', 'h', 5, 's', 's', 'o', 'e', 'm', 5, 's', 's', 'o', 'e', 'b', 6, 's', 's', 'o', 'e', 'b', 's', 5, 's', 's', 'o', 'e', 's', 6, 's', 's', 'o', 'e', 's', 's', 6, 's', 's', 'o', 'e', 'n', 'g', 5, 's', 's', 'o', 'e', 'j', 5, 's', 's', 'o', 'e', 'c', 5, 's', 's', 'o', 'e', 'k', 5, 's', 's', 'o', 'e', 't', 5, 's', 's', 'o', 'e', 'p', 5, 's', 's', 'o', 'e', 'h', 4, 's', 's', 'y', 'o', 5, 's', 's', 'y', 'o', 'g', 6, 's', 's', 'y', 'o', 'g', 'g', 6, 's', 's', 'y', 'o', 'g', 's', 5, 's', 's', 'y', 'o', 'n', 6, 's', 's', 'y', 'o', 'n', 'j', 6, 's', 's', 'y', 'o', 'n', 'h', 5, 's', 's', 'y', 'o', 'd', 5, 's', 's', 'y', 'o', 'l', 6, 's', 's', 'y', 'o', 'l', 'g', 6, 's', 's', 'y', 'o', 'l', 'm', 6, 's', 's', 'y', 'o', 'l', 'b', 6, 's', 's', 'y', 'o', 'l', 's', 6, 's', 's', 'y', 'o', 'l', 't', 6, 's', 's', 'y', 'o', 'l', 'p', 6, 's', 's', 'y', 'o', 'l', 'h', 5, 's', 's', 'y', 'o', 'm', 5, 's', 's', 'y', 'o', 'b', 6, 's', 's', 'y', 'o', 'b', 's', 5, 's', 's', 'y', 'o', 's', 6, 's', 's', 'y', 'o', 's', 's', 6, 's', 's', 'y', 'o', 'n', 'g', 5, 's', 's', 'y', 'o', 'j', 5, 's', 's', 'y', 'o', 'c', 5, 's', 's', 'y', 'o', 'k', 5, 's', 's', 'y', 'o', 't', 5, 's', 's', 'y', 'o', 'p', 5, 's', 's', 'y', 'o', 'h', 3, 's', 's', 'u', 4, 's', 's', 'u', 'g', 5, 's', 's', 'u', 'g', 'g', 5, 's', 's', 'u', 'g', 's', 4, 's', 's', 'u', 'n', 5, 's', 's', 'u', 'n', 'j', 5, 's', 's', 'u', 'n', 'h', 4, 's', 's', 'u', 'd', 4, 's', 's', 'u', 'l', 5, 's', 's', 'u', 'l', 'g', 5, 's', 's', 'u', 'l', 'm', 5, 's', 's', 'u', 'l', 'b', 5, 's', 's', 'u', 'l', 's', 5, 's', 's', 'u', 'l', 't', 5, 's', 's', 'u', 'l', 'p', 5, 's', 's', 'u', 'l', 'h', 4, 's', 's', 'u', 'm', 4, 's', 's', 'u', 'b', 5, 's', 's', 'u', 'b', 's', 4, 's', 's', 'u', 's', 5, 's', 's', 'u', 's', 's', 5, 's', 's', 'u', 'n', 'g', 4, 's', 's', 'u', 'j', 4, 's', 's', 'u', 'c', 4, 's', 's', 'u', 'k', 4, 's', 's', 'u', 't', 4, 's', 's', 'u', 'p', 4, 's', 's', 'u', 'h', 5, 's', 's', 'w', 'e', 'o', 6, 's', 's', 'w', 'e', 'o', 'g', 7, 's', 's', 'w', 'e', 'o', 'g', 'g', 7, 's', 's', 'w', 'e', 'o', 'g', 's', 6, 's', 's', 'w', 'e', 'o', 'n', 7, 's', 's', 'w', 'e', 'o', 'n', 'j', 7, 's', 's', 'w', 'e', 'o', 'n', 'h', 6, 's', 's', 'w', 'e', 'o', 'd', 6, 's', 's', 'w', 'e', 'o', 'l', 7, 's', 's', 'w', 'e', 'o', 'l', 'g', 7, 's', 's', 'w', 'e', 'o', 'l', 'm', 7, 's', 's', 'w', 'e', 'o', 'l', 'b', 7, 's', 's', 'w', 'e', 'o', 'l', 's', 7, 's', 's', 'w', 'e', 'o', 'l', 't', 7, 's', 's', 'w', 'e', 'o', 'l', 'p', 7, 's', 's', 'w', 'e', 'o', 'l', 'h', 6, 's', 's', 'w', 'e', 'o', 'm', 6, 's', 's', 'w', 'e', 'o', 'b', 7, 's', 's', 'w', 'e', 'o', 'b', 's', 6, 's', 's', 'w', 'e', 'o', 's', 7, 's', 's', 'w', 'e', 'o', 's', 's', 7, 's', 's', 'w', 'e', 'o', 'n', 'g', 6, 's', 's', 'w', 'e', 'o', 'j', 6, 's', 's', 'w', 'e', 'o', 'c', 6, 's', 's', 'w', 'e', 'o', 'k', 6, 's', 's', 'w', 'e', 'o', 't', 6, 's', 's', 'w', 'e', 'o', 'p', 6, 's', 's', 'w', 'e', 'o', 'h', 4, 's', 's', 'w', 'e', 5, 's', 's', 'w', 'e', 'g', 6, 's', 's', 'w', 'e', 'g', 'g', 6, 's', 's', 'w', 'e', 'g', 's', 5, 's', 's', 'w', 'e', 'n', 6, 's', 's', 'w', 'e', 'n', 'j', 6, 's', 's', 'w', 'e', 'n', 'h', 5, 's', 's', 'w', 'e', 'd', 5, 's', 's', 'w', 'e', 'l', 6, 's', 's', 'w', 'e', 'l', 'g', 6, 's', 's', 'w', 'e', 'l', 'm', 6, 's', 's', 'w', 'e', 'l', 'b', 6, 's', 's', 'w', 'e', 'l', 's', 6, 's', 's', 'w', 'e', 'l', 't', 6, 's', 's', 'w', 'e', 'l', 'p', 6, 's', 's', 'w', 'e', 'l', 'h', 5, 's', 's', 'w', 'e', 'm', 5, 's', 's', 'w', 'e', 'b', 6, 's', 's', 'w', 'e', 'b', 's', 5, 's', 's', 'w', 'e', 's', 6, 's', 's', 'w', 'e', 's', 's', 6, 's', 's', 'w', 'e', 'n', 'g', 5, 's', 's', 'w', 'e', 'j', 5, 's', 's', 'w', 'e', 'c', 5, 's', 's', 'w', 'e', 'k', 5, 's', 's', 'w', 'e', 't', 5, 's', 's', 'w', 'e', 'p', 5, 's', 's', 'w', 'e', 'h', 4, 's', 's', 'w', 'i', 5, 's', 's', 'w', 'i', 'g', 6, 's', 's', 'w', 'i', 'g', 'g', 6, 's', 's', 'w', 'i', 'g', 's', 5, 's', 's', 'w', 'i', 'n', 6, 's', 's', 'w', 'i', 'n', 'j', 6, 's', 's', 'w', 'i', 'n', 'h', 5, 's', 's', 'w', 'i', 'd', 5, 's', 's', 'w', 'i', 'l', 6, 's', 's', 'w', 'i', 'l', 'g', 6, 's', 's', 'w', 'i', 'l', 'm', 6, 's', 's', 'w', 'i', 'l', 'b', 6, 's', 's', 'w', 'i', 'l', 's', 6, 's', 's', 'w', 'i', 'l', 't', 6, 's', 's', 'w', 'i', 'l', 'p', 6, 's', 's', 'w', 'i', 'l', 'h', 5, 's', 's', 'w', 'i', 'm', 5, 's', 's', 'w', 'i', 'b', 6, 's', 's', 'w', 'i', 'b', 's', 5, 's', 's', 'w', 'i', 's', 6, 's', 's', 'w', 'i', 's', 's', 6, 's', 's', 'w', 'i', 'n', 'g', 5, 's', 's', 'w', 'i', 'j', 5, 's', 's', 'w', 'i', 'c', 5, 's', 's', 'w', 'i', 'k', 5, 's', 's', 'w', 'i', 't', 5, 's', 's', 'w', 'i', 'p', 5, 's', 's', 'w', 'i', 'h', 4, 's', 's', 'y', 'u', 5, 's', 's', 'y', 'u', 'g', 6, 's', 's', 'y', 'u', 'g', 'g', 6, 's', 's', 'y', 'u', 'g', 's', 5, 's', 's', 'y', 'u', 'n', 6, 's', 's', 'y', 'u', 'n', 'j', 6, 's', 's', 'y', 'u', 'n', 'h', 5, 's', 's', 'y', 'u', 'd', 5, 's', 's', 'y', 'u', 'l', 6, 's', 's', 'y', 'u', 'l', 'g', 6, 's', 's', 'y', 'u', 'l', 'm', 6, 's', 's', 'y', 'u', 'l', 'b', 6, 's', 's', 'y', 'u', 'l', 's', 6, 's', 's', 'y', 'u', 'l', 't', 6, 's', 's', 'y', 'u', 'l', 'p', 6, 's', 's', 'y', 'u', 'l', 'h', 5, 's', 's', 'y', 'u', 'm', 5, 's', 's', 'y', 'u', 'b', 6, 's', 's', 'y', 'u', 'b', 's', 5, 's', 's', 'y', 'u', 's', 6, 's', 's', 'y', 'u', 's', 's', 6, 's', 's', 'y', 'u', 'n', 'g', 5, 's', 's', 'y', 'u', 'j', 5, 's', 's', 'y', 'u', 'c', 5, 's', 's', 'y', 'u', 'k', 5, 's', 's', 'y', 'u', 't', 5, 's', 's', 'y', 'u', 'p', 5, 's', 's', 'y', 'u', 'h', 4, 's', 's', 'e', 'u', 5, 's', 's', 'e', 'u', 'g', 6, 's', 's', 'e', 'u', 'g', 'g', 6, 's', 's', 'e', 'u', 'g', 's', 5, 's', 's', 'e', 'u', 'n', 6, 's', 's', 'e', 'u', 'n', 'j', 6, 's', 's', 'e', 'u', 'n', 'h', 5, 's', 's', 'e', 'u', 'd', 5, 's', 's', 'e', 'u', 'l', 6, 's', 's', 'e', 'u', 'l', 'g', 6, 's', 's', 'e', 'u', 'l', 'm', 6, 's', 's', 'e', 'u', 'l', 'b', 6, 's', 's', 'e', 'u', 'l', 's', 6, 's', 's', 'e', 'u', 'l', 't', 6, 's', 's', 'e', 'u', 'l', 'p', 6, 's', 's', 'e', 'u', 'l', 'h', 5, 's', 's', 'e', 'u', 'm', 5, 's', 's', 'e', 'u', 'b', 6, 's', 's', 'e', 'u', 'b', 's', 5, 's', 's', 'e', 'u', 's', 6, 's', 's', 'e', 'u', 's', 's', 6, 's', 's', 'e', 'u', 'n', 'g', 5, 's', 's', 'e', 'u', 'j', 5, 's', 's', 'e', 'u', 'c', 5, 's', 's', 'e', 'u', 'k', 5, 's', 's', 'e', 'u', 't', 5, 's', 's', 'e', 'u', 'p', 5, 's', 's', 'e', 'u', 'h', 4, 's', 's', 'y', 'i', 5, 's', 's', 'y', 'i', 'g', 6, 's', 's', 'y', 'i', 'g', 'g', 6, 's', 's', 'y', 'i', 'g', 's', 5, 's', 's', 'y', 'i', 'n', 6, 's', 's', 'y', 'i', 'n', 'j', 6, 's', 's', 'y', 'i', 'n', 'h', 5, 's', 's', 'y', 'i', 'd', 5, 's', 's', 'y', 'i', 'l', 6, 's', 's', 'y', 'i', 'l', 'g', 6, 's', 's', 'y', 'i', 'l', 'm', 6, 's', 's', 'y', 'i', 'l', 'b', 6, 's', 's', 'y', 'i', 'l', 's', 6, 's', 's', 'y', 'i', 'l', 't', 6, 's', 's', 'y', 'i', 'l', 'p', 6, 's', 's', 'y', 'i', 'l', 'h', 5, 's', 's', 'y', 'i', 'm', 5, 's', 's', 'y', 'i', 'b', 6, 's', 's', 'y', 'i', 'b', 's', 5, 's', 's', 'y', 'i', 's', 6, 's', 's', 'y', 'i', 's', 's', 6, 's', 's', 'y', 'i', 'n', 'g', 5, 's', 's', 'y', 'i', 'j', 5, 's', 's', 'y', 'i', 'c', 5, 's', 's', 'y', 'i', 'k', 5, 's', 's', 'y', 'i', 't', 5, 's', 's', 'y', 'i', 'p', 5, 's', 's', 'y', 'i', 'h', 3, 's', 's', 'i', 4, 's', 's', 'i', 'g', 5, 's', 's', 'i', 'g', 'g', 5, 's', 's', 'i', 'g', 's', 4, 's', 's', 'i', 'n', 5, 's', 's', 'i', 'n', 'j', 5, 's', 's', 'i', 'n', 'h', 4, 's', 's', 'i', 'd', 4, 's', 's', 'i', 'l', 5, 's', 's', 'i', 'l', 'g', 5, 's', 's', 'i', 'l', 'm', 5, 's', 's', 'i', 'l', 'b', 5, 's', 's', 'i', 'l', 's', 5, 's', 's', 'i', 'l', 't', 5, 's', 's', 'i', 'l', 'p', 5, 's', 's', 'i', 'l', 'h', 4, 's', 's', 'i', 'm', 4, 's', 's', 'i', 'b', 5, 's', 's', 'i', 'b', 's', 4, 's', 's', 'i', 's', 5, 's', 's', 'i', 's', 's', 5, 's', 's', 'i', 'n', 'g', 4, 's', 's', 'i', 'j', 4, 's', 's', 'i', 'c', 4, 's', 's', 'i', 'k', 4, 's', 's', 'i', 't', 4, 's', 's', 'i', 'p', 4, 's', 's', 'i', 'h', 1, 'a', 2, 'a', 'g', 3, 'a', 'g', 'g', 3, 'a', 'g', 's', 2, 'a', 'n', 3, 'a', 'n', 'j', 3, 'a', 'n', 'h', 2, 'a', 'd', 2, 'a', 'l', 3, 'a', 'l', 'g', 3, 'a', 'l', 'm', 3, 'a', 'l', 'b', 3, 'a', 'l', 's', 3, 'a', 'l', 't', 3, 'a', 'l', 'p', 3, 'a', 'l', 'h', 2, 'a', 'm', 2, 'a', 'b', 3, 'a', 'b', 's', 2, 'a', 's', 3, 'a', 's', 's', 3, 'a', 'n', 'g', 2, 'a', 'j', 2, 'a', 'c', 2, 'a', 'k', 2, 'a', 't', 2, 'a', 'p', 2, 'a', 'h', 2, 'a', 'e', 3, 'a', 'e', 'g', 4, 'a', 'e', 'g', 'g', 4, 'a', 'e', 'g', 's', 3, 'a', 'e', 'n', 4, 'a', 'e', 'n', 'j', 4, 'a', 'e', 'n', 'h', 3, 'a', 'e', 'd', 3, 'a', 'e', 'l', 4, 'a', 'e', 'l', 'g', 4, 'a', 'e', 'l', 'm', 4, 'a', 'e', 'l', 'b', 4, 'a', 'e', 'l', 's', 4, 'a', 'e', 'l', 't', 4, 'a', 'e', 'l', 'p', 4, 'a', 'e', 'l', 'h', 3, 'a', 'e', 'm', 3, 'a', 'e', 'b', 4, 'a', 'e', 'b', 's', 3, 'a', 'e', 's', 4, 'a', 'e', 's', 's', 4, 'a', 'e', 'n', 'g', 3, 'a', 'e', 'j', 3, 'a', 'e', 'c', 3, 'a', 'e', 'k', 3, 'a', 'e', 't', 3, 'a', 'e', 'p', 3, 'a', 'e', 'h', 2, 'y', 'a', 3, 'y', 'a', 'g', 4, 'y', 'a', 'g', 'g', 4, 'y', 'a', 'g', 's', 3, 'y', 'a', 'n', 4, 'y', 'a', 'n', 'j', 4, 'y', 'a', 'n', 'h', 3, 'y', 'a', 'd', 3, 'y', 'a', 'l', 4, 'y', 'a', 'l', 'g', 4, 'y', 'a', 'l', 'm', 4, 'y', 'a', 'l', 'b', 4, 'y', 'a', 'l', 's', 4, 'y', 'a', 'l', 't', 4, 'y', 'a', 'l', 'p', 4, 'y', 'a', 'l', 'h', 3, 'y', 'a', 'm', 3, 'y', 'a', 'b', 4, 'y', 'a', 'b', 's', 3, 'y', 'a', 's', 4, 'y', 'a', 's', 's', 4, 'y', 'a', 'n', 'g', 3, 'y', 'a', 'j', 3, 'y', 'a', 'c', 3, 'y', 'a', 'k', 3, 'y', 'a', 't', 3, 'y', 'a', 'p', 3, 'y', 'a', 'h', 3, 'y', 'a', 'e', 4, 'y', 'a', 'e', 'g', 5, 'y', 'a', 'e', 'g', 'g', 5, 'y', 'a', 'e', 'g', 's', 4, 'y', 'a', 'e', 'n', 5, 'y', 'a', 'e', 'n', 'j', 5, 'y', 'a', 'e', 'n', 'h', 4, 'y', 'a', 'e', 'd', 4, 'y', 'a', 'e', 'l', 5, 'y', 'a', 'e', 'l', 'g', 5, 'y', 'a', 'e', 'l', 'm', 5, 'y', 'a', 'e', 'l', 'b', 5, 'y', 'a', 'e', 'l', 's', 5, 'y', 'a', 'e', 'l', 't', 5, 'y', 'a', 'e', 'l', 'p', 5, 'y', 'a', 'e', 'l', 'h', 4, 'y', 'a', 'e', 'm', 4, 'y', 'a', 'e', 'b', 5, 'y', 'a', 'e', 'b', 's', 4, 'y', 'a', 'e', 's', 5, 'y', 'a', 'e', 's', 's', 5, 'y', 'a', 'e', 'n', 'g', 4, 'y', 'a', 'e', 'j', 4, 'y', 'a', 'e', 'c', 4, 'y', 'a', 'e', 'k', 4, 'y', 'a', 'e', 't', 4, 'y', 'a', 'e', 'p', 4, 'y', 'a', 'e', 'h', 2, 'e', 'o', 3, 'e', 'o', 'g', 4, 'e', 'o', 'g', 'g', 4, 'e', 'o', 'g', 's', 3, 'e', 'o', 'n', 4, 'e', 'o', 'n', 'j', 4, 'e', 'o', 'n', 'h', 3, 'e', 'o', 'd', 3, 'e', 'o', 'l', 4, 'e', 'o', 'l', 'g', 4, 'e', 'o', 'l', 'm', 4, 'e', 'o', 'l', 'b', 4, 'e', 'o', 'l', 's', 4, 'e', 'o', 'l', 't', 4, 'e', 'o', 'l', 'p', 4, 'e', 'o', 'l', 'h', 3, 'e', 'o', 'm', 3, 'e', 'o', 'b', 4, 'e', 'o', 'b', 's', 3, 'e', 'o', 's', 4, 'e', 'o', 's', 's', 4, 'e', 'o', 'n', 'g', 3, 'e', 'o', 'j', 3, 'e', 'o', 'c', 3, 'e', 'o', 'k', 3, 'e', 'o', 't', 3, 'e', 'o', 'p', 3, 'e', 'o', 'h', 1, 'e', 2, 'e', 'g', 3, 'e', 'g', 'g', 3, 'e', 'g', 's', 2, 'e', 'n', 3, 'e', 'n', 'j', 3, 'e', 'n', 'h', 2, 'e', 'd', 2, 'e', 'l', 3, 'e', 'l', 'g', 3, 'e', 'l', 'm', 3, 'e', 'l', 'b', 3, 'e', 'l', 's', 3, 'e', 'l', 't', 3, 'e', 'l', 'p', 3, 'e', 'l', 'h', 2, 'e', 'm', 2, 'e', 'b', 3, 'e', 'b', 's', 2, 'e', 's', 3, 'e', 's', 's', 3, 'e', 'n', 'g', 2, 'e', 'j', 2, 'e', 'c', 2, 'e', 'k', 2, 'e', 't', 2, 'e', 'p', 2, 'e', 'h', 3, 'y', 'e', 'o', 4, 'y', 'e', 'o', 'g', 5, 'y', 'e', 'o', 'g', 'g', 5, 'y', 'e', 'o', 'g', 's', 4, 'y', 'e', 'o', 'n', 5, 'y', 'e', 'o', 'n', 'j', 5, 'y', 'e', 'o', 'n', 'h', 4, 'y', 'e', 'o', 'd', 4, 'y', 'e', 'o', 'l', 5, 'y', 'e', 'o', 'l', 'g', 5, 'y', 'e', 'o', 'l', 'm', 5, 'y', 'e', 'o', 'l', 'b', 5, 'y', 'e', 'o', 'l', 's', 5, 'y', 'e', 'o', 'l', 't', 5, 'y', 'e', 'o', 'l', 'p', 5, 'y', 'e', 'o', 'l', 'h', 4, 'y', 'e', 'o', 'm', 4, 'y', 'e', 'o', 'b', 5, 'y', 'e', 'o', 'b', 's', 4, 'y', 'e', 'o', 's', 5, 'y', 'e', 'o', 's', 's', 5, 'y', 'e', 'o', 'n', 'g', 4, 'y', 'e', 'o', 'j', 4, 'y', 'e', 'o', 'c', 4, 'y', 'e', 'o', 'k', 4, 'y', 'e', 'o', 't', 4, 'y', 'e', 'o', 'p', 4, 'y', 'e', 'o', 'h', 2, 'y', 'e', 3, 'y', 'e', 'g', 4, 'y', 'e', 'g', 'g', 4, 'y', 'e', 'g', 's', 3, 'y', 'e', 'n', 4, 'y', 'e', 'n', 'j', 4, 'y', 'e', 'n', 'h', 3, 'y', 'e', 'd', 3, 'y', 'e', 'l', 4, 'y', 'e', 'l', 'g', 4, 'y', 'e', 'l', 'm', 4, 'y', 'e', 'l', 'b', 4, 'y', 'e', 'l', 's', 4, 'y', 'e', 'l', 't', 4, 'y', 'e', 'l', 'p', 4, 'y', 'e', 'l', 'h', 3, 'y', 'e', 'm', 3, 'y', 'e', 'b', 4, 'y', 'e', 'b', 's', 3, 'y', 'e', 's', 4, 'y', 'e', 's', 's', 4, 'y', 'e', 'n', 'g', 3, 'y', 'e', 'j', 3, 'y', 'e', 'c', 3, 'y', 'e', 'k', 3, 'y', 'e', 't', 3, 'y', 'e', 'p', 3, 'y', 'e', 'h', 1, 'o', 2, 'o', 'g', 3, 'o', 'g', 'g', 3, 'o', 'g', 's', 2, 'o', 'n', 3, 'o', 'n', 'j', 3, 'o', 'n', 'h', 2, 'o', 'd', 2, 'o', 'l', 3, 'o', 'l', 'g', 3, 'o', 'l', 'm', 3, 'o', 'l', 'b', 3, 'o', 'l', 's', 3, 'o', 'l', 't', 3, 'o', 'l', 'p', 3, 'o', 'l', 'h', 2, 'o', 'm', 2, 'o', 'b', 3, 'o', 'b', 's', 2, 'o', 's', 3, 'o', 's', 's', 3, 'o', 'n', 'g', 2, 'o', 'j', 2, 'o', 'c', 2, 'o', 'k', 2, 'o', 't', 2, 'o', 'p', 2, 'o', 'h', 2, 'w', 'a', 3, 'w', 'a', 'g', 4, 'w', 'a', 'g', 'g', 4, 'w', 'a', 'g', 's', 3, 'w', 'a', 'n', 4, 'w', 'a', 'n', 'j', 4, 'w', 'a', 'n', 'h', 3, 'w', 'a', 'd', 3, 'w', 'a', 'l', 4, 'w', 'a', 'l', 'g', 4, 'w', 'a', 'l', 'm', 4, 'w', 'a', 'l', 'b', 4, 'w', 'a', 'l', 's', 4, 'w', 'a', 'l', 't', 4, 'w', 'a', 'l', 'p', 4, 'w', 'a', 'l', 'h', 3, 'w', 'a', 'm', 3, 'w', 'a', 'b', 4, 'w', 'a', 'b', 's', 3, 'w', 'a', 's', 4, 'w', 'a', 's', 's', 4, 'w', 'a', 'n', 'g', 3, 'w', 'a', 'j', 3, 'w', 'a', 'c', 3, 'w', 'a', 'k', 3, 'w', 'a', 't', 3, 'w', 'a', 'p', 3, 'w', 'a', 'h', 3, 'w', 'a', 'e', 4, 'w', 'a', 'e', 'g', 5, 'w', 'a', 'e', 'g', 'g', 5, 'w', 'a', 'e', 'g', 's', 4, 'w', 'a', 'e', 'n', 5, 'w', 'a', 'e', 'n', 'j', 5, 'w', 'a', 'e', 'n', 'h', 4, 'w', 'a', 'e', 'd', 4, 'w', 'a', 'e', 'l', 5, 'w', 'a', 'e', 'l', 'g', 5, 'w', 'a', 'e', 'l', 'm', 5, 'w', 'a', 'e', 'l', 'b', 5, 'w', 'a', 'e', 'l', 's', 5, 'w', 'a', 'e', 'l', 't', 5, 'w', 'a', 'e', 'l', 'p', 5, 'w', 'a', 'e', 'l', 'h', 4, 'w', 'a', 'e', 'm', 4, 'w', 'a', 'e', 'b', 5, 'w', 'a', 'e', 'b', 's', 4, 'w', 'a', 'e', 's', 5, 'w', 'a', 'e', 's', 's', 5, 'w', 'a', 'e', 'n', 'g', 4, 'w', 'a', 'e', 'j', 4, 'w', 'a', 'e', 'c', 4, 'w', 'a', 'e', 'k', 4, 'w', 'a', 'e', 't', 4, 'w', 'a', 'e', 'p', 4, 'w', 'a', 'e', 'h', 2, 'o', 'e', 3, 'o', 'e', 'g', 4, 'o', 'e', 'g', 'g', 4, 'o', 'e', 'g', 's', 3, 'o', 'e', 'n', 4, 'o', 'e', 'n', 'j', 4, 'o', 'e', 'n', 'h', 3, 'o', 'e', 'd', 3, 'o', 'e', 'l', 4, 'o', 'e', 'l', 'g', 4, 'o', 'e', 'l', 'm', 4, 'o', 'e', 'l', 'b', 4, 'o', 'e', 'l', 's', 4, 'o', 'e', 'l', 't', 4, 'o', 'e', 'l', 'p', 4, 'o', 'e', 'l', 'h', 3, 'o', 'e', 'm', 3, 'o', 'e', 'b', 4, 'o', 'e', 'b', 's', 3, 'o', 'e', 's', 4, 'o', 'e', 's', 's', 4, 'o', 'e', 'n', 'g', 3, 'o', 'e', 'j', 3, 'o', 'e', 'c', 3, 'o', 'e', 'k', 3, 'o', 'e', 't', 3, 'o', 'e', 'p', 3, 'o', 'e', 'h', 2, 'y', 'o', 3, 'y', 'o', 'g', 4, 'y', 'o', 'g', 'g', 4, 'y', 'o', 'g', 's', 3, 'y', 'o', 'n', 4, 'y', 'o', 'n', 'j', 4, 'y', 'o', 'n', 'h', 3, 'y', 'o', 'd', 3, 'y', 'o', 'l', 4, 'y', 'o', 'l', 'g', 4, 'y', 'o', 'l', 'm', 4, 'y', 'o', 'l', 'b', 4, 'y', 'o', 'l', 's', 4, 'y', 'o', 'l', 't', 4, 'y', 'o', 'l', 'p', 4, 'y', 'o', 'l', 'h', 3, 'y', 'o', 'm', 3, 'y', 'o', 'b', 4, 'y', 'o', 'b', 's', 3, 'y', 'o', 's', 4, 'y', 'o', 's', 's', 4, 'y', 'o', 'n', 'g', 3, 'y', 'o', 'j', 3, 'y', 'o', 'c', 3, 'y', 'o', 'k', 3, 'y', 'o', 't', 3, 'y', 'o', 'p', 3, 'y', 'o', 'h', 1, 'u', 2, 'u', 'g', 3, 'u', 'g', 'g', 3, 'u', 'g', 's', 2, 'u', 'n', 3, 'u', 'n', 'j', 3, 'u', 'n', 'h', 2, 'u', 'd', 2, 'u', 'l', 3, 'u', 'l', 'g', 3, 'u', 'l', 'm', 3, 'u', 'l', 'b', 3, 'u', 'l', 's', 3, 'u', 'l', 't', 3, 'u', 'l', 'p', 3, 'u', 'l', 'h', 2, 'u', 'm', 2, 'u', 'b', 3, 'u', 'b', 's', 2, 'u', 's', 3, 'u', 's', 's', 3, 'u', 'n', 'g', 2, 'u', 'j', 2, 'u', 'c', 2, 'u', 'k', 2, 'u', 't', 2, 'u', 'p', 2, 'u', 'h', 3, 'w', 'e', 'o', 4, 'w', 'e', 'o', 'g', 5, 'w', 'e', 'o', 'g', 'g', 5, 'w', 'e', 'o', 'g', 's', 4, 'w', 'e', 'o', 'n', 5, 'w', 'e', 'o', 'n', 'j', 5, 'w', 'e', 'o', 'n', 'h', 4, 'w', 'e', 'o', 'd', 4, 'w', 'e', 'o', 'l', 5, 'w', 'e', 'o', 'l', 'g', 5, 'w', 'e', 'o', 'l', 'm', 5, 'w', 'e', 'o', 'l', 'b', 5, 'w', 'e', 'o', 'l', 's', 5, 'w', 'e', 'o', 'l', 't', 5, 'w', 'e', 'o', 'l', 'p', 5, 'w', 'e', 'o', 'l', 'h', 4, 'w', 'e', 'o', 'm', 4, 'w', 'e', 'o', 'b', 5, 'w', 'e', 'o', 'b', 's', 4, 'w', 'e', 'o', 's', 5, 'w', 'e', 'o', 's', 's', 5, 'w', 'e', 'o', 'n', 'g', 4, 'w', 'e', 'o', 'j', 4, 'w', 'e', 'o', 'c', 4, 'w', 'e', 'o', 'k', 4, 'w', 'e', 'o', 't', 4, 'w', 'e', 'o', 'p', 4, 'w', 'e', 'o', 'h', 2, 'w', 'e', 3, 'w', 'e', 'g', 4, 'w', 'e', 'g', 'g', 4, 'w', 'e', 'g', 's', 3, 'w', 'e', 'n', 4, 'w', 'e', 'n', 'j', 4, 'w', 'e', 'n', 'h', 3, 'w', 'e', 'd', 3, 'w', 'e', 'l', 4, 'w', 'e', 'l', 'g', 4, 'w', 'e', 'l', 'm', 4, 'w', 'e', 'l', 'b', 4, 'w', 'e', 'l', 's', 4, 'w', 'e', 'l', 't', 4, 'w', 'e', 'l', 'p', 4, 'w', 'e', 'l', 'h', 3, 'w', 'e', 'm', 3, 'w', 'e', 'b', 4, 'w', 'e', 'b', 's', 3, 'w', 'e', 's', 4, 'w', 'e', 's', 's', 4, 'w', 'e', 'n', 'g', 3, 'w', 'e', 'j', 3, 'w', 'e', 'c', 3, 'w', 'e', 'k', 3, 'w', 'e', 't', 3, 'w', 'e', 'p', 3, 'w', 'e', 'h', 2, 'w', 'i', 3, 'w', 'i', 'g', 4, 'w', 'i', 'g', 'g', 4, 'w', 'i', 'g', 's', 3, 'w', 'i', 'n', 4, 'w', 'i', 'n', 'j', 4, 'w', 'i', 'n', 'h', 3, 'w', 'i', 'd', 3, 'w', 'i', 'l', 4, 'w', 'i', 'l', 'g', 4, 'w', 'i', 'l', 'm', 4, 'w', 'i', 'l', 'b', 4, 'w', 'i', 'l', 's', 4, 'w', 'i', 'l', 't', 4, 'w', 'i', 'l', 'p', 4, 'w', 'i', 'l', 'h', 3, 'w', 'i', 'm', 3, 'w', 'i', 'b', 4, 'w', 'i', 'b', 's', 3, 'w', 'i', 's', 4, 'w', 'i', 's', 's', 4, 'w', 'i', 'n', 'g', 3, 'w', 'i', 'j', 3, 'w', 'i', 'c', 3, 'w', 'i', 'k', 3, 'w', 'i', 't', 3, 'w', 'i', 'p', 3, 'w', 'i', 'h', 2, 'y', 'u', 3, 'y', 'u', 'g', 4, 'y', 'u', 'g', 'g', 4, 'y', 'u', 'g', 's', 3, 'y', 'u', 'n', 4, 'y', 'u', 'n', 'j', 4, 'y', 'u', 'n', 'h', 3, 'y', 'u', 'd', 3, 'y', 'u', 'l', 4, 'y', 'u', 'l', 'g', 4, 'y', 'u', 'l', 'm', 4, 'y', 'u', 'l', 'b', 4, 'y', 'u', 'l', 's', 4, 'y', 'u', 'l', 't', 4, 'y', 'u', 'l', 'p', 4, 'y', 'u', 'l', 'h', 3, 'y', 'u', 'm', 3, 'y', 'u', 'b', 4, 'y', 'u', 'b', 's', 3, 'y', 'u', 's', 4, 'y', 'u', 's', 's', 4, 'y', 'u', 'n', 'g', 3, 'y', 'u', 'j', 3, 'y', 'u', 'c', 3, 'y', 'u', 'k', 3, 'y', 'u', 't', 3, 'y', 'u', 'p', 3, 'y', 'u', 'h', 2, 'e', 'u', 3, 'e', 'u', 'g', 4, 'e', 'u', 'g', 'g', 4, 'e', 'u', 'g', 's', 3, 'e', 'u', 'n', 4, 'e', 'u', 'n', 'j', 4, 'e', 'u', 'n', 'h', 3, 'e', 'u', 'd', 3, 'e', 'u', 'l', 4, 'e', 'u', 'l', 'g', 4, 'e', 'u', 'l', 'm', 4, 'e', 'u', 'l', 'b', 4, 'e', 'u', 'l', 's', 4, 'e', 'u', 'l', 't', 4, 'e', 'u', 'l', 'p', 4, 'e', 'u', 'l', 'h', 3, 'e', 'u', 'm', 3, 'e', 'u', 'b', 4, 'e', 'u', 'b', 's', 3, 'e', 'u', 's', 4, 'e', 'u', 's', 's', 4, 'e', 'u', 'n', 'g', 3, 'e', 'u', 'j', 3, 'e', 'u', 'c', 3, 'e', 'u', 'k', 3, 'e', 'u', 't', 3, 'e', 'u', 'p', 3, 'e', 'u', 'h', 2, 'y', 'i', 3, 'y', 'i', 'g', 4, 'y', 'i', 'g', 'g', 4, 'y', 'i', 'g', 's', 3, 'y', 'i', 'n', 4, 'y', 'i', 'n', 'j', 4, 'y', 'i', 'n', 'h', 3, 'y', 'i', 'd', 3, 'y', 'i', 'l', 4, 'y', 'i', 'l', 'g', 4, 'y', 'i', 'l', 'm', 4, 'y', 'i', 'l', 'b', 4, 'y', 'i', 'l', 's', 4, 'y', 'i', 'l', 't', 4, 'y', 'i', 'l', 'p', 4, 'y', 'i', 'l', 'h', 3, 'y', 'i', 'm', 3, 'y', 'i', 'b', 4, 'y', 'i', 'b', 's', 3, 'y', 'i', 's', 4, 'y', 'i', 's', 's', 4, 'y', 'i', 'n', 'g', 3, 'y', 'i', 'j', 3, 'y', 'i', 'c', 3, 'y', 'i', 'k', 3, 'y', 'i', 't', 3, 'y', 'i', 'p', 3, 'y', 'i', 'h', 1, 'i', 2, 'i', 'g', 3, 'i', 'g', 'g', 3, 'i', 'g', 's', 2, 'i', 'n', 3, 'i', 'n', 'j', 3, 'i', 'n', 'h', 2, 'i', 'd', 2, 'i', 'l', 3, 'i', 'l', 'g', 3, 'i', 'l', 'm', 3, 'i', 'l', 'b', 3, 'i', 'l', 's', 3, 'i', 'l', 't', 3, 'i', 'l', 'p', 3, 'i', 'l', 'h', 2, 'i', 'm', 2, 'i', 'b', 3, 'i', 'b', 's', 2, 'i', 's', 3, 'i', 's', 's', 3, 'i', 'n', 'g', 2, 'i', 'j', 2, 'i', 'c', 2, 'i', 'k', 2, 'i', 't', 2, 'i', 'p', 2, 'i', 'h', 2, 'j', 'a', 3, 'j', 'a', 'g', 4, 'j', 'a', 'g', 'g', 4, 'j', 'a', 'g', 's', 3, 'j', 'a', 'n', 4, 'j', 'a', 'n', 'j', 4, 'j', 'a', 'n', 'h', 3, 'j', 'a', 'd', 3, 'j', 'a', 'l', 4, 'j', 'a', 'l', 'g', 4, 'j', 'a', 'l', 'm', 4, 'j', 'a', 'l', 'b', 4, 'j', 'a', 'l', 's', 4, 'j', 'a', 'l', 't', 4, 'j', 'a', 'l', 'p', 4, 'j', 'a', 'l', 'h', 3, 'j', 'a', 'm', 3, 'j', 'a', 'b', 4, 'j', 'a', 'b', 's', 3, 'j', 'a', 's', 4, 'j', 'a', 's', 's', 4, 'j', 'a', 'n', 'g', 3, 'j', 'a', 'j', 3, 'j', 'a', 'c', 3, 'j', 'a', 'k', 3, 'j', 'a', 't', 3, 'j', 'a', 'p', 3, 'j', 'a', 'h', 3, 'j', 'a', 'e', 4, 'j', 'a', 'e', 'g', 5, 'j', 'a', 'e', 'g', 'g', 5, 'j', 'a', 'e', 'g', 's', 4, 'j', 'a', 'e', 'n', 5, 'j', 'a', 'e', 'n', 'j', 5, 'j', 'a', 'e', 'n', 'h', 4, 'j', 'a', 'e', 'd', 4, 'j', 'a', 'e', 'l', 5, 'j', 'a', 'e', 'l', 'g', 5, 'j', 'a', 'e', 'l', 'm', 5, 'j', 'a', 'e', 'l', 'b', 5, 'j', 'a', 'e', 'l', 's', 5, 'j', 'a', 'e', 'l', 't', 5, 'j', 'a', 'e', 'l', 'p', 5, 'j', 'a', 'e', 'l', 'h', 4, 'j', 'a', 'e', 'm', 4, 'j', 'a', 'e', 'b', 5, 'j', 'a', 'e', 'b', 's', 4, 'j', 'a', 'e', 's', 5, 'j', 'a', 'e', 's', 's', 5, 'j', 'a', 'e', 'n', 'g', 4, 'j', 'a', 'e', 'j', 4, 'j', 'a', 'e', 'c', 4, 'j', 'a', 'e', 'k', 4, 'j', 'a', 'e', 't', 4, 'j', 'a', 'e', 'p', 4, 'j', 'a', 'e', 'h', 3, 'j', 'y', 'a', 4, 'j', 'y', 'a', 'g', 5, 'j', 'y', 'a', 'g', 'g', 5, 'j', 'y', 'a', 'g', 's', 4, 'j', 'y', 'a', 'n', 5, 'j', 'y', 'a', 'n', 'j', 5, 'j', 'y', 'a', 'n', 'h', 4, 'j', 'y', 'a', 'd', 4, 'j', 'y', 'a', 'l', 5, 'j', 'y', 'a', 'l', 'g', 5, 'j', 'y', 'a', 'l', 'm', 5, 'j', 'y', 'a', 'l', 'b', 5, 'j', 'y', 'a', 'l', 's', 5, 'j', 'y', 'a', 'l', 't', 5, 'j', 'y', 'a', 'l', 'p', 5, 'j', 'y', 'a', 'l', 'h', 4, 'j', 'y', 'a', 'm', 4, 'j', 'y', 'a', 'b', 5, 'j', 'y', 'a', 'b', 's', 4, 'j', 'y', 'a', 's', 5, 'j', 'y', 'a', 's', 's', 5, 'j', 'y', 'a', 'n', 'g', 4, 'j', 'y', 'a', 'j', 4, 'j', 'y', 'a', 'c', 4, 'j', 'y', 'a', 'k', 4, 'j', 'y', 'a', 't', 4, 'j', 'y', 'a', 'p', 4, 'j', 'y', 'a', 'h', 4, 'j', 'y', 'a', 'e', 5, 'j', 'y', 'a', 'e', 'g', 6, 'j', 'y', 'a', 'e', 'g', 'g', 6, 'j', 'y', 'a', 'e', 'g', 's', 5, 'j', 'y', 'a', 'e', 'n', 6, 'j', 'y', 'a', 'e', 'n', 'j', 6, 'j', 'y', 'a', 'e', 'n', 'h', 5, 'j', 'y', 'a', 'e', 'd', 5, 'j', 'y', 'a', 'e', 'l', 6, 'j', 'y', 'a', 'e', 'l', 'g', 6, 'j', 'y', 'a', 'e', 'l', 'm', 6, 'j', 'y', 'a', 'e', 'l', 'b', 6, 'j', 'y', 'a', 'e', 'l', 's', 6, 'j', 'y', 'a', 'e', 'l', 't', 6, 'j', 'y', 'a', 'e', 'l', 'p', 6, 'j', 'y', 'a', 'e', 'l', 'h', 5, 'j', 'y', 'a', 'e', 'm', 5, 'j', 'y', 'a', 'e', 'b', 6, 'j', 'y', 'a', 'e', 'b', 's', 5, 'j', 'y', 'a', 'e', 's', 6, 'j', 'y', 'a', 'e', 's', 's', 6, 'j', 'y', 'a', 'e', 'n', 'g', 5, 'j', 'y', 'a', 'e', 'j', 5, 'j', 'y', 'a', 'e', 'c', 5, 'j', 'y', 'a', 'e', 'k', 5, 'j', 'y', 'a', 'e', 't', 5, 'j', 'y', 'a', 'e', 'p', 5, 'j', 'y', 'a', 'e', 'h', 3, 'j', 'e', 'o', 4, 'j', 'e', 'o', 'g', 5, 'j', 'e', 'o', 'g', 'g', 5, 'j', 'e', 'o', 'g', 's', 4, 'j', 'e', 'o', 'n', 5, 'j', 'e', 'o', 'n', 'j', 5, 'j', 'e', 'o', 'n', 'h', 4, 'j', 'e', 'o', 'd', 4, 'j', 'e', 'o', 'l', 5, 'j', 'e', 'o', 'l', 'g', 5, 'j', 'e', 'o', 'l', 'm', 5, 'j', 'e', 'o', 'l', 'b', 5, 'j', 'e', 'o', 'l', 's', 5, 'j', 'e', 'o', 'l', 't', 5, 'j', 'e', 'o', 'l', 'p', 5, 'j', 'e', 'o', 'l', 'h', 4, 'j', 'e', 'o', 'm', 4, 'j', 'e', 'o', 'b', 5, 'j', 'e', 'o', 'b', 's', 4, 'j', 'e', 'o', 's', 5, 'j', 'e', 'o', 's', 's', 5, 'j', 'e', 'o', 'n', 'g', 4, 'j', 'e', 'o', 'j', 4, 'j', 'e', 'o', 'c', 4, 'j', 'e', 'o', 'k', 4, 'j', 'e', 'o', 't', 4, 'j', 'e', 'o', 'p', 4, 'j', 'e', 'o', 'h', 2, 'j', 'e', 3, 'j', 'e', 'g', 4, 'j', 'e', 'g', 'g', 4, 'j', 'e', 'g', 's', 3, 'j', 'e', 'n', 4, 'j', 'e', 'n', 'j', 4, 'j', 'e', 'n', 'h', 3, 'j', 'e', 'd', 3, 'j', 'e', 'l', 4, 'j', 'e', 'l', 'g', 4, 'j', 'e', 'l', 'm', 4, 'j', 'e', 'l', 'b', 4, 'j', 'e', 'l', 's', 4, 'j', 'e', 'l', 't', 4, 'j', 'e', 'l', 'p', 4, 'j', 'e', 'l', 'h', 3, 'j', 'e', 'm', 3, 'j', 'e', 'b', 4, 'j', 'e', 'b', 's', 3, 'j', 'e', 's', 4, 'j', 'e', 's', 's', 4, 'j', 'e', 'n', 'g', 3, 'j', 'e', 'j', 3, 'j', 'e', 'c', 3, 'j', 'e', 'k', 3, 'j', 'e', 't', 3, 'j', 'e', 'p', 3, 'j', 'e', 'h', 4, 'j', 'y', 'e', 'o', 5, 'j', 'y', 'e', 'o', 'g', 6, 'j', 'y', 'e', 'o', 'g', 'g', 6, 'j', 'y', 'e', 'o', 'g', 's', 5, 'j', 'y', 'e', 'o', 'n', 6, 'j', 'y', 'e', 'o', 'n', 'j', 6, 'j', 'y', 'e', 'o', 'n', 'h', 5, 'j', 'y', 'e', 'o', 'd', 5, 'j', 'y', 'e', 'o', 'l', 6, 'j', 'y', 'e', 'o', 'l', 'g', 6, 'j', 'y', 'e', 'o', 'l', 'm', 6, 'j', 'y', 'e', 'o', 'l', 'b', 6, 'j', 'y', 'e', 'o', 'l', 's', 6, 'j', 'y', 'e', 'o', 'l', 't', 6, 'j', 'y', 'e', 'o', 'l', 'p', 6, 'j', 'y', 'e', 'o', 'l', 'h', 5, 'j', 'y', 'e', 'o', 'm', 5, 'j', 'y', 'e', 'o', 'b', 6, 'j', 'y', 'e', 'o', 'b', 's', 5, 'j', 'y', 'e', 'o', 's', 6, 'j', 'y', 'e', 'o', 's', 's', 6, 'j', 'y', 'e', 'o', 'n', 'g', 5, 'j', 'y', 'e', 'o', 'j', 5, 'j', 'y', 'e', 'o', 'c', 5, 'j', 'y', 'e', 'o', 'k', 5, 'j', 'y', 'e', 'o', 't', 5, 'j', 'y', 'e', 'o', 'p', 5, 'j', 'y', 'e', 'o', 'h', 3, 'j', 'y', 'e', 4, 'j', 'y', 'e', 'g', 5, 'j', 'y', 'e', 'g', 'g', 5, 'j', 'y', 'e', 'g', 's', 4, 'j', 'y', 'e', 'n', 5, 'j', 'y', 'e', 'n', 'j', 5, 'j', 'y', 'e', 'n', 'h', 4, 'j', 'y', 'e', 'd', 4, 'j', 'y', 'e', 'l', 5, 'j', 'y', 'e', 'l', 'g', 5, 'j', 'y', 'e', 'l', 'm', 5, 'j', 'y', 'e', 'l', 'b', 5, 'j', 'y', 'e', 'l', 's', 5, 'j', 'y', 'e', 'l', 't', 5, 'j', 'y', 'e', 'l', 'p', 5, 'j', 'y', 'e', 'l', 'h', 4, 'j', 'y', 'e', 'm', 4, 'j', 'y', 'e', 'b', 5, 'j', 'y', 'e', 'b', 's', 4, 'j', 'y', 'e', 's', 5, 'j', 'y', 'e', 's', 's', 5, 'j', 'y', 'e', 'n', 'g', 4, 'j', 'y', 'e', 'j', 4, 'j', 'y', 'e', 'c', 4, 'j', 'y', 'e', 'k', 4, 'j', 'y', 'e', 't', 4, 'j', 'y', 'e', 'p', 4, 'j', 'y', 'e', 'h', 2, 'j', 'o', 3, 'j', 'o', 'g', 4, 'j', 'o', 'g', 'g', 4, 'j', 'o', 'g', 's', 3, 'j', 'o', 'n', 4, 'j', 'o', 'n', 'j', 4, 'j', 'o', 'n', 'h', 3, 'j', 'o', 'd', 3, 'j', 'o', 'l', 4, 'j', 'o', 'l', 'g', 4, 'j', 'o', 'l', 'm', 4, 'j', 'o', 'l', 'b', 4, 'j', 'o', 'l', 's', 4, 'j', 'o', 'l', 't', 4, 'j', 'o', 'l', 'p', 4, 'j', 'o', 'l', 'h', 3, 'j', 'o', 'm', 3, 'j', 'o', 'b', 4, 'j', 'o', 'b', 's', 3, 'j', 'o', 's', 4, 'j', 'o', 's', 's', 4, 'j', 'o', 'n', 'g', 3, 'j', 'o', 'j', 3, 'j', 'o', 'c', 3, 'j', 'o', 'k', 3, 'j', 'o', 't', 3, 'j', 'o', 'p', 3, 'j', 'o', 'h', 3, 'j', 'w', 'a', 4, 'j', 'w', 'a', 'g', 5, 'j', 'w', 'a', 'g', 'g', 5, 'j', 'w', 'a', 'g', 's', 4, 'j', 'w', 'a', 'n', 5, 'j', 'w', 'a', 'n', 'j', 5, 'j', 'w', 'a', 'n', 'h', 4, 'j', 'w', 'a', 'd', 4, 'j', 'w', 'a', 'l', 5, 'j', 'w', 'a', 'l', 'g', 5, 'j', 'w', 'a', 'l', 'm', 5, 'j', 'w', 'a', 'l', 'b', 5, 'j', 'w', 'a', 'l', 's', 5, 'j', 'w', 'a', 'l', 't', 5, 'j', 'w', 'a', 'l', 'p', 5, 'j', 'w', 'a', 'l', 'h', 4, 'j', 'w', 'a', 'm', 4, 'j', 'w', 'a', 'b', 5, 'j', 'w', 'a', 'b', 's', 4, 'j', 'w', 'a', 's', 5, 'j', 'w', 'a', 's', 's', 5, 'j', 'w', 'a', 'n', 'g', 4, 'j', 'w', 'a', 'j', 4, 'j', 'w', 'a', 'c', 4, 'j', 'w', 'a', 'k', 4, 'j', 'w', 'a', 't', 4, 'j', 'w', 'a', 'p', 4, 'j', 'w', 'a', 'h', 4, 'j', 'w', 'a', 'e', 5, 'j', 'w', 'a', 'e', 'g', 6, 'j', 'w', 'a', 'e', 'g', 'g', 6, 'j', 'w', 'a', 'e', 'g', 's', 5, 'j', 'w', 'a', 'e', 'n', 6, 'j', 'w', 'a', 'e', 'n', 'j', 6, 'j', 'w', 'a', 'e', 'n', 'h', 5, 'j', 'w', 'a', 'e', 'd', 5, 'j', 'w', 'a', 'e', 'l', 6, 'j', 'w', 'a', 'e', 'l', 'g', 6, 'j', 'w', 'a', 'e', 'l', 'm', 6, 'j', 'w', 'a', 'e', 'l', 'b', 6, 'j', 'w', 'a', 'e', 'l', 's', 6, 'j', 'w', 'a', 'e', 'l', 't', 6, 'j', 'w', 'a', 'e', 'l', 'p', 6, 'j', 'w', 'a', 'e', 'l', 'h', 5, 'j', 'w', 'a', 'e', 'm', 5, 'j', 'w', 'a', 'e', 'b', 6, 'j', 'w', 'a', 'e', 'b', 's', 5, 'j', 'w', 'a', 'e', 's', 6, 'j', 'w', 'a', 'e', 's', 's', 6, 'j', 'w', 'a', 'e', 'n', 'g', 5, 'j', 'w', 'a', 'e', 'j', 5, 'j', 'w', 'a', 'e', 'c', 5, 'j', 'w', 'a', 'e', 'k', 5, 'j', 'w', 'a', 'e', 't', 5, 'j', 'w', 'a', 'e', 'p', 5, 'j', 'w', 'a', 'e', 'h', 3, 'j', 'o', 'e', 4, 'j', 'o', 'e', 'g', 5, 'j', 'o', 'e', 'g', 'g', 5, 'j', 'o', 'e', 'g', 's', 4, 'j', 'o', 'e', 'n', 5, 'j', 'o', 'e', 'n', 'j', 5, 'j', 'o', 'e', 'n', 'h', 4, 'j', 'o', 'e', 'd', 4, 'j', 'o', 'e', 'l', 5, 'j', 'o', 'e', 'l', 'g', 5, 'j', 'o', 'e', 'l', 'm', 5, 'j', 'o', 'e', 'l', 'b', 5, 'j', 'o', 'e', 'l', 's', 5, 'j', 'o', 'e', 'l', 't', 5, 'j', 'o', 'e', 'l', 'p', 5, 'j', 'o', 'e', 'l', 'h', 4, 'j', 'o', 'e', 'm', 4, 'j', 'o', 'e', 'b', 5, 'j', 'o', 'e', 'b', 's', 4, 'j', 'o', 'e', 's', 5, 'j', 'o', 'e', 's', 's', 5, 'j', 'o', 'e', 'n', 'g', 4, 'j', 'o', 'e', 'j', 4, 'j', 'o', 'e', 'c', 4, 'j', 'o', 'e', 'k', 4, 'j', 'o', 'e', 't', 4, 'j', 'o', 'e', 'p', 4, 'j', 'o', 'e', 'h', 3, 'j', 'y', 'o', 4, 'j', 'y', 'o', 'g', 5, 'j', 'y', 'o', 'g', 'g', 5, 'j', 'y', 'o', 'g', 's', 4, 'j', 'y', 'o', 'n', 5, 'j', 'y', 'o', 'n', 'j', 5, 'j', 'y', 'o', 'n', 'h', 4, 'j', 'y', 'o', 'd', 4, 'j', 'y', 'o', 'l', 5, 'j', 'y', 'o', 'l', 'g', 5, 'j', 'y', 'o', 'l', 'm', 5, 'j', 'y', 'o', 'l', 'b', 5, 'j', 'y', 'o', 'l', 's', 5, 'j', 'y', 'o', 'l', 't', 5, 'j', 'y', 'o', 'l', 'p', 5, 'j', 'y', 'o', 'l', 'h', 4, 'j', 'y', 'o', 'm', 4, 'j', 'y', 'o', 'b', 5, 'j', 'y', 'o', 'b', 's', 4, 'j', 'y', 'o', 's', 5, 'j', 'y', 'o', 's', 's', 5, 'j', 'y', 'o', 'n', 'g', 4, 'j', 'y', 'o', 'j', 4, 'j', 'y', 'o', 'c', 4, 'j', 'y', 'o', 'k', 4, 'j', 'y', 'o', 't', 4, 'j', 'y', 'o', 'p', 4, 'j', 'y', 'o', 'h', 2, 'j', 'u', 3, 'j', 'u', 'g', 4, 'j', 'u', 'g', 'g', 4, 'j', 'u', 'g', 's', 3, 'j', 'u', 'n', 4, 'j', 'u', 'n', 'j', 4, 'j', 'u', 'n', 'h', 3, 'j', 'u', 'd', 3, 'j', 'u', 'l', 4, 'j', 'u', 'l', 'g', 4, 'j', 'u', 'l', 'm', 4, 'j', 'u', 'l', 'b', 4, 'j', 'u', 'l', 's', 4, 'j', 'u', 'l', 't', 4, 'j', 'u', 'l', 'p', 4, 'j', 'u', 'l', 'h', 3, 'j', 'u', 'm', 3, 'j', 'u', 'b', 4, 'j', 'u', 'b', 's', 3, 'j', 'u', 's', 4, 'j', 'u', 's', 's', 4, 'j', 'u', 'n', 'g', 3, 'j', 'u', 'j', 3, 'j', 'u', 'c', 3, 'j', 'u', 'k', 3, 'j', 'u', 't', 3, 'j', 'u', 'p', 3, 'j', 'u', 'h', 4, 'j', 'w', 'e', 'o', 5, 'j', 'w', 'e', 'o', 'g', 6, 'j', 'w', 'e', 'o', 'g', 'g', 6, 'j', 'w', 'e', 'o', 'g', 's', 5, 'j', 'w', 'e', 'o', 'n', 6, 'j', 'w', 'e', 'o', 'n', 'j', 6, 'j', 'w', 'e', 'o', 'n', 'h', 5, 'j', 'w', 'e', 'o', 'd', 5, 'j', 'w', 'e', 'o', 'l', 6, 'j', 'w', 'e', 'o', 'l', 'g', 6, 'j', 'w', 'e', 'o', 'l', 'm', 6, 'j', 'w', 'e', 'o', 'l', 'b', 6, 'j', 'w', 'e', 'o', 'l', 's', 6, 'j', 'w', 'e', 'o', 'l', 't', 6, 'j', 'w', 'e', 'o', 'l', 'p', 6, 'j', 'w', 'e', 'o', 'l', 'h', 5, 'j', 'w', 'e', 'o', 'm', 5, 'j', 'w', 'e', 'o', 'b', 6, 'j', 'w', 'e', 'o', 'b', 's', 5, 'j', 'w', 'e', 'o', 's', 6, 'j', 'w', 'e', 'o', 's', 's', 6, 'j', 'w', 'e', 'o', 'n', 'g', 5, 'j', 'w', 'e', 'o', 'j', 5, 'j', 'w', 'e', 'o', 'c', 5, 'j', 'w', 'e', 'o', 'k', 5, 'j', 'w', 'e', 'o', 't', 5, 'j', 'w', 'e', 'o', 'p', 5, 'j', 'w', 'e', 'o', 'h', 3, 'j', 'w', 'e', 4, 'j', 'w', 'e', 'g', 5, 'j', 'w', 'e', 'g', 'g', 5, 'j', 'w', 'e', 'g', 's', 4, 'j', 'w', 'e', 'n', 5, 'j', 'w', 'e', 'n', 'j', 5, 'j', 'w', 'e', 'n', 'h', 4, 'j', 'w', 'e', 'd', 4, 'j', 'w', 'e', 'l', 5, 'j', 'w', 'e', 'l', 'g', 5, 'j', 'w', 'e', 'l', 'm', 5, 'j', 'w', 'e', 'l', 'b', 5, 'j', 'w', 'e', 'l', 's', 5, 'j', 'w', 'e', 'l', 't', 5, 'j', 'w', 'e', 'l', 'p', 5, 'j', 'w', 'e', 'l', 'h', 4, 'j', 'w', 'e', 'm', 4, 'j', 'w', 'e', 'b', 5, 'j', 'w', 'e', 'b', 's', 4, 'j', 'w', 'e', 's', 5, 'j', 'w', 'e', 's', 's', 5, 'j', 'w', 'e', 'n', 'g', 4, 'j', 'w', 'e', 'j', 4, 'j', 'w', 'e', 'c', 4, 'j', 'w', 'e', 'k', 4, 'j', 'w', 'e', 't', 4, 'j', 'w', 'e', 'p', 4, 'j', 'w', 'e', 'h', 3, 'j', 'w', 'i', 4, 'j', 'w', 'i', 'g', 5, 'j', 'w', 'i', 'g', 'g', 5, 'j', 'w', 'i', 'g', 's', 4, 'j', 'w', 'i', 'n', 5, 'j', 'w', 'i', 'n', 'j', 5, 'j', 'w', 'i', 'n', 'h', 4, 'j', 'w', 'i', 'd', 4, 'j', 'w', 'i', 'l', 5, 'j', 'w', 'i', 'l', 'g', 5, 'j', 'w', 'i', 'l', 'm', 5, 'j', 'w', 'i', 'l', 'b', 5, 'j', 'w', 'i', 'l', 's', 5, 'j', 'w', 'i', 'l', 't', 5, 'j', 'w', 'i', 'l', 'p', 5, 'j', 'w', 'i', 'l', 'h', 4, 'j', 'w', 'i', 'm', 4, 'j', 'w', 'i', 'b', 5, 'j', 'w', 'i', 'b', 's', 4, 'j', 'w', 'i', 's', 5, 'j', 'w', 'i', 's', 's', 5, 'j', 'w', 'i', 'n', 'g', 4, 'j', 'w', 'i', 'j', 4, 'j', 'w', 'i', 'c', 4, 'j', 'w', 'i', 'k', 4, 'j', 'w', 'i', 't', 4, 'j', 'w', 'i', 'p', 4, 'j', 'w', 'i', 'h', 3, 'j', 'y', 'u', 4, 'j', 'y', 'u', 'g', 5, 'j', 'y', 'u', 'g', 'g', 5, 'j', 'y', 'u', 'g', 's', 4, 'j', 'y', 'u', 'n', 5, 'j', 'y', 'u', 'n', 'j', 5, 'j', 'y', 'u', 'n', 'h', 4, 'j', 'y', 'u', 'd', 4, 'j', 'y', 'u', 'l', 5, 'j', 'y', 'u', 'l', 'g', 5, 'j', 'y', 'u', 'l', 'm', 5, 'j', 'y', 'u', 'l', 'b', 5, 'j', 'y', 'u', 'l', 's', 5, 'j', 'y', 'u', 'l', 't', 5, 'j', 'y', 'u', 'l', 'p', 5, 'j', 'y', 'u', 'l', 'h', 4, 'j', 'y', 'u', 'm', 4, 'j', 'y', 'u', 'b', 5, 'j', 'y', 'u', 'b', 's', 4, 'j', 'y', 'u', 's', 5, 'j', 'y', 'u', 's', 's', 5, 'j', 'y', 'u', 'n', 'g', 4, 'j', 'y', 'u', 'j', 4, 'j', 'y', 'u', 'c', 4, 'j', 'y', 'u', 'k', 4, 'j', 'y', 'u', 't', 4, 'j', 'y', 'u', 'p', 4, 'j', 'y', 'u', 'h', 3, 'j', 'e', 'u', 4, 'j', 'e', 'u', 'g', 5, 'j', 'e', 'u', 'g', 'g', 5, 'j', 'e', 'u', 'g', 's', 4, 'j', 'e', 'u', 'n', 5, 'j', 'e', 'u', 'n', 'j', 5, 'j', 'e', 'u', 'n', 'h', 4, 'j', 'e', 'u', 'd', 4, 'j', 'e', 'u', 'l', 5, 'j', 'e', 'u', 'l', 'g', 5, 'j', 'e', 'u', 'l', 'm', 5, 'j', 'e', 'u', 'l', 'b', 5, 'j', 'e', 'u', 'l', 's', 5, 'j', 'e', 'u', 'l', 't', 5, 'j', 'e', 'u', 'l', 'p', 5, 'j', 'e', 'u', 'l', 'h', 4, 'j', 'e', 'u', 'm', 4, 'j', 'e', 'u', 'b', 5, 'j', 'e', 'u', 'b', 's', 4, 'j', 'e', 'u', 's', 5, 'j', 'e', 'u', 's', 's', 5, 'j', 'e', 'u', 'n', 'g', 4, 'j', 'e', 'u', 'j', 4, 'j', 'e', 'u', 'c', 4, 'j', 'e', 'u', 'k', 4, 'j', 'e', 'u', 't', 4, 'j', 'e', 'u', 'p', 4, 'j', 'e', 'u', 'h', 3, 'j', 'y', 'i', 4, 'j', 'y', 'i', 'g', 5, 'j', 'y', 'i', 'g', 'g', 5, 'j', 'y', 'i', 'g', 's', 4, 'j', 'y', 'i', 'n', 5, 'j', 'y', 'i', 'n', 'j', 5, 'j', 'y', 'i', 'n', 'h', 4, 'j', 'y', 'i', 'd', 4, 'j', 'y', 'i', 'l', 5, 'j', 'y', 'i', 'l', 'g', 5, 'j', 'y', 'i', 'l', 'm', 5, 'j', 'y', 'i', 'l', 'b', 5, 'j', 'y', 'i', 'l', 's', 5, 'j', 'y', 'i', 'l', 't', 5, 'j', 'y', 'i', 'l', 'p', 5, 'j', 'y', 'i', 'l', 'h', 4, 'j', 'y', 'i', 'm', 4, 'j', 'y', 'i', 'b', 5, 'j', 'y', 'i', 'b', 's', 4, 'j', 'y', 'i', 's', 5, 'j', 'y', 'i', 's', 's', 5, 'j', 'y', 'i', 'n', 'g', 4, 'j', 'y', 'i', 'j', 4, 'j', 'y', 'i', 'c', 4, 'j', 'y', 'i', 'k', 4, 'j', 'y', 'i', 't', 4, 'j', 'y', 'i', 'p', 4, 'j', 'y', 'i', 'h', 2, 'j', 'i', 3, 'j', 'i', 'g', 4, 'j', 'i', 'g', 'g', 4, 'j', 'i', 'g', 's', 3, 'j', 'i', 'n', 4, 'j', 'i', 'n', 'j', 4, 'j', 'i', 'n', 'h', 3, 'j', 'i', 'd', 3, 'j', 'i', 'l', 4, 'j', 'i', 'l', 'g', 4, 'j', 'i', 'l', 'm', 4, 'j', 'i', 'l', 'b', 4, 'j', 'i', 'l', 's', 4, 'j', 'i', 'l', 't', 4, 'j', 'i', 'l', 'p', 4, 'j', 'i', 'l', 'h', 3, 'j', 'i', 'm', 3, 'j', 'i', 'b', 4, 'j', 'i', 'b', 's', 3, 'j', 'i', 's', 4, 'j', 'i', 's', 's', 4, 'j', 'i', 'n', 'g', 3, 'j', 'i', 'j', 3, 'j', 'i', 'c', 3, 'j', 'i', 'k', 3, 'j', 'i', 't', 3, 'j', 'i', 'p', 3, 'j', 'i', 'h', 3, 'j', 'j', 'a', 4, 'j', 'j', 'a', 'g', 5, 'j', 'j', 'a', 'g', 'g', 5, 'j', 'j', 'a', 'g', 's', 4, 'j', 'j', 'a', 'n', 5, 'j', 'j', 'a', 'n', 'j', 5, 'j', 'j', 'a', 'n', 'h', 4, 'j', 'j', 'a', 'd', 4, 'j', 'j', 'a', 'l', 5, 'j', 'j', 'a', 'l', 'g', 5, 'j', 'j', 'a', 'l', 'm', 5, 'j', 'j', 'a', 'l', 'b', 5, 'j', 'j', 'a', 'l', 's', 5, 'j', 'j', 'a', 'l', 't', 5, 'j', 'j', 'a', 'l', 'p', 5, 'j', 'j', 'a', 'l', 'h', 4, 'j', 'j', 'a', 'm', 4, 'j', 'j', 'a', 'b', 5, 'j', 'j', 'a', 'b', 's', 4, 'j', 'j', 'a', 's', 5, 'j', 'j', 'a', 's', 's', 5, 'j', 'j', 'a', 'n', 'g', 4, 'j', 'j', 'a', 'j', 4, 'j', 'j', 'a', 'c', 4, 'j', 'j', 'a', 'k', 4, 'j', 'j', 'a', 't', 4, 'j', 'j', 'a', 'p', 4, 'j', 'j', 'a', 'h', 4, 'j', 'j', 'a', 'e', 5, 'j', 'j', 'a', 'e', 'g', 6, 'j', 'j', 'a', 'e', 'g', 'g', 6, 'j', 'j', 'a', 'e', 'g', 's', 5, 'j', 'j', 'a', 'e', 'n', 6, 'j', 'j', 'a', 'e', 'n', 'j', 6, 'j', 'j', 'a', 'e', 'n', 'h', 5, 'j', 'j', 'a', 'e', 'd', 5, 'j', 'j', 'a', 'e', 'l', 6, 'j', 'j', 'a', 'e', 'l', 'g', 6, 'j', 'j', 'a', 'e', 'l', 'm', 6, 'j', 'j', 'a', 'e', 'l', 'b', 6, 'j', 'j', 'a', 'e', 'l', 's', 6, 'j', 'j', 'a', 'e', 'l', 't', 6, 'j', 'j', 'a', 'e', 'l', 'p', 6, 'j', 'j', 'a', 'e', 'l', 'h', 5, 'j', 'j', 'a', 'e', 'm', 5, 'j', 'j', 'a', 'e', 'b', 6, 'j', 'j', 'a', 'e', 'b', 's', 5, 'j', 'j', 'a', 'e', 's', 6, 'j', 'j', 'a', 'e', 's', 's', 6, 'j', 'j', 'a', 'e', 'n', 'g', 5, 'j', 'j', 'a', 'e', 'j', 5, 'j', 'j', 'a', 'e', 'c', 5, 'j', 'j', 'a', 'e', 'k', 5, 'j', 'j', 'a', 'e', 't', 5, 'j', 'j', 'a', 'e', 'p', 5, 'j', 'j', 'a', 'e', 'h', 4, 'j', 'j', 'y', 'a', 5, 'j', 'j', 'y', 'a', 'g', 6, 'j', 'j', 'y', 'a', 'g', 'g', 6, 'j', 'j', 'y', 'a', 'g', 's', 5, 'j', 'j', 'y', 'a', 'n', 6, 'j', 'j', 'y', 'a', 'n', 'j', 6, 'j', 'j', 'y', 'a', 'n', 'h', 5, 'j', 'j', 'y', 'a', 'd', 5, 'j', 'j', 'y', 'a', 'l', 6, 'j', 'j', 'y', 'a', 'l', 'g', 6, 'j', 'j', 'y', 'a', 'l', 'm', 6, 'j', 'j', 'y', 'a', 'l', 'b', 6, 'j', 'j', 'y', 'a', 'l', 's', 6, 'j', 'j', 'y', 'a', 'l', 't', 6, 'j', 'j', 'y', 'a', 'l', 'p', 6, 'j', 'j', 'y', 'a', 'l', 'h', 5, 'j', 'j', 'y', 'a', 'm', 5, 'j', 'j', 'y', 'a', 'b', 6, 'j', 'j', 'y', 'a', 'b', 's', 5, 'j', 'j', 'y', 'a', 's', 6, 'j', 'j', 'y', 'a', 's', 's', 6, 'j', 'j', 'y', 'a', 'n', 'g', 5, 'j', 'j', 'y', 'a', 'j', 5, 'j', 'j', 'y', 'a', 'c', 5, 'j', 'j', 'y', 'a', 'k', 5, 'j', 'j', 'y', 'a', 't', 5, 'j', 'j', 'y', 'a', 'p', 5, 'j', 'j', 'y', 'a', 'h', 5, 'j', 'j', 'y', 'a', 'e', 6, 'j', 'j', 'y', 'a', 'e', 'g', 7, 'j', 'j', 'y', 'a', 'e', 'g', 'g', 7, 'j', 'j', 'y', 'a', 'e', 'g', 's', 6, 'j', 'j', 'y', 'a', 'e', 'n', 7, 'j', 'j', 'y', 'a', 'e', 'n', 'j', 7, 'j', 'j', 'y', 'a', 'e', 'n', 'h', 6, 'j', 'j', 'y', 'a', 'e', 'd', 6, 'j', 'j', 'y', 'a', 'e', 'l', 7, 'j', 'j', 'y', 'a', 'e', 'l', 'g', 7, 'j', 'j', 'y', 'a', 'e', 'l', 'm', 7, 'j', 'j', 'y', 'a', 'e', 'l', 'b', 7, 'j', 'j', 'y', 'a', 'e', 'l', 's', 7, 'j', 'j', 'y', 'a', 'e', 'l', 't', 7, 'j', 'j', 'y', 'a', 'e', 'l', 'p', 7, 'j', 'j', 'y', 'a', 'e', 'l', 'h', 6, 'j', 'j', 'y', 'a', 'e', 'm', 6, 'j', 'j', 'y', 'a', 'e', 'b', 7, 'j', 'j', 'y', 'a', 'e', 'b', 's', 6, 'j', 'j', 'y', 'a', 'e', 's', 7, 'j', 'j', 'y', 'a', 'e', 's', 's', 7, 'j', 'j', 'y', 'a', 'e', 'n', 'g', 6, 'j', 'j', 'y', 'a', 'e', 'j', 6, 'j', 'j', 'y', 'a', 'e', 'c', 6, 'j', 'j', 'y', 'a', 'e', 'k', 6, 'j', 'j', 'y', 'a', 'e', 't', 6, 'j', 'j', 'y', 'a', 'e', 'p', 6, 'j', 'j', 'y', 'a', 'e', 'h', 4, 'j', 'j', 'e', 'o', 5, 'j', 'j', 'e', 'o', 'g', 6, 'j', 'j', 'e', 'o', 'g', 'g', 6, 'j', 'j', 'e', 'o', 'g', 's', 5, 'j', 'j', 'e', 'o', 'n', 6, 'j', 'j', 'e', 'o', 'n', 'j', 6, 'j', 'j', 'e', 'o', 'n', 'h', 5, 'j', 'j', 'e', 'o', 'd', 5, 'j', 'j', 'e', 'o', 'l', 6, 'j', 'j', 'e', 'o', 'l', 'g', 6, 'j', 'j', 'e', 'o', 'l', 'm', 6, 'j', 'j', 'e', 'o', 'l', 'b', 6, 'j', 'j', 'e', 'o', 'l', 's', 6, 'j', 'j', 'e', 'o', 'l', 't', 6, 'j', 'j', 'e', 'o', 'l', 'p', 6, 'j', 'j', 'e', 'o', 'l', 'h', 5, 'j', 'j', 'e', 'o', 'm', 5, 'j', 'j', 'e', 'o', 'b', 6, 'j', 'j', 'e', 'o', 'b', 's', 5, 'j', 'j', 'e', 'o', 's', 6, 'j', 'j', 'e', 'o', 's', 's', 6, 'j', 'j', 'e', 'o', 'n', 'g', 5, 'j', 'j', 'e', 'o', 'j', 5, 'j', 'j', 'e', 'o', 'c', 5, 'j', 'j', 'e', 'o', 'k', 5, 'j', 'j', 'e', 'o', 't', 5, 'j', 'j', 'e', 'o', 'p', 5, 'j', 'j', 'e', 'o', 'h', 3, 'j', 'j', 'e', 4, 'j', 'j', 'e', 'g', 5, 'j', 'j', 'e', 'g', 'g', 5, 'j', 'j', 'e', 'g', 's', 4, 'j', 'j', 'e', 'n', 5, 'j', 'j', 'e', 'n', 'j', 5, 'j', 'j', 'e', 'n', 'h', 4, 'j', 'j', 'e', 'd', 4, 'j', 'j', 'e', 'l', 5, 'j', 'j', 'e', 'l', 'g', 5, 'j', 'j', 'e', 'l', 'm', 5, 'j', 'j', 'e', 'l', 'b', 5, 'j', 'j', 'e', 'l', 's', 5, 'j', 'j', 'e', 'l', 't', 5, 'j', 'j', 'e', 'l', 'p', 5, 'j', 'j', 'e', 'l', 'h', 4, 'j', 'j', 'e', 'm', 4, 'j', 'j', 'e', 'b', 5, 'j', 'j', 'e', 'b', 's', 4, 'j', 'j', 'e', 's', 5, 'j', 'j', 'e', 's', 's', 5, 'j', 'j', 'e', 'n', 'g', 4, 'j', 'j', 'e', 'j', 4, 'j', 'j', 'e', 'c', 4, 'j', 'j', 'e', 'k', 4, 'j', 'j', 'e', 't', 4, 'j', 'j', 'e', 'p', 4, 'j', 'j', 'e', 'h', 5, 'j', 'j', 'y', 'e', 'o', 6, 'j', 'j', 'y', 'e', 'o', 'g', 7, 'j', 'j', 'y', 'e', 'o', 'g', 'g', 7, 'j', 'j', 'y', 'e', 'o', 'g', 's', 6, 'j', 'j', 'y', 'e', 'o', 'n', 7, 'j', 'j', 'y', 'e', 'o', 'n', 'j', 7, 'j', 'j', 'y', 'e', 'o', 'n', 'h', 6, 'j', 'j', 'y', 'e', 'o', 'd', 6, 'j', 'j', 'y', 'e', 'o', 'l', 7, 'j', 'j', 'y', 'e', 'o', 'l', 'g', 7, 'j', 'j', 'y', 'e', 'o', 'l', 'm', 7, 'j', 'j', 'y', 'e', 'o', 'l', 'b', 7, 'j', 'j', 'y', 'e', 'o', 'l', 's', 7, 'j', 'j', 'y', 'e', 'o', 'l', 't', 7, 'j', 'j', 'y', 'e', 'o', 'l', 'p', 7, 'j', 'j', 'y', 'e', 'o', 'l', 'h', 6, 'j', 'j', 'y', 'e', 'o', 'm', 6, 'j', 'j', 'y', 'e', 'o', 'b', 7, 'j', 'j', 'y', 'e', 'o', 'b', 's', 6, 'j', 'j', 'y', 'e', 'o', 's', 7, 'j', 'j', 'y', 'e', 'o', 's', 's', 7, 'j', 'j', 'y', 'e', 'o', 'n', 'g', 6, 'j', 'j', 'y', 'e', 'o', 'j', 6, 'j', 'j', 'y', 'e', 'o', 'c', 6, 'j', 'j', 'y', 'e', 'o', 'k', 6, 'j', 'j', 'y', 'e', 'o', 't', 6, 'j', 'j', 'y', 'e', 'o', 'p', 6, 'j', 'j', 'y', 'e', 'o', 'h', 4, 'j', 'j', 'y', 'e', 5, 'j', 'j', 'y', 'e', 'g', 6, 'j', 'j', 'y', 'e', 'g', 'g', 6, 'j', 'j', 'y', 'e', 'g', 's', 5, 'j', 'j', 'y', 'e', 'n', 6, 'j', 'j', 'y', 'e', 'n', 'j', 6, 'j', 'j', 'y', 'e', 'n', 'h', 5, 'j', 'j', 'y', 'e', 'd', 5, 'j', 'j', 'y', 'e', 'l', 6, 'j', 'j', 'y', 'e', 'l', 'g', 6, 'j', 'j', 'y', 'e', 'l', 'm', 6, 'j', 'j', 'y', 'e', 'l', 'b', 6, 'j', 'j', 'y', 'e', 'l', 's', 6, 'j', 'j', 'y', 'e', 'l', 't', 6, 'j', 'j', 'y', 'e', 'l', 'p', 6, 'j', 'j', 'y', 'e', 'l', 'h', 5, 'j', 'j', 'y', 'e', 'm', 5, 'j', 'j', 'y', 'e', 'b', 6, 'j', 'j', 'y', 'e', 'b', 's', 5, 'j', 'j', 'y', 'e', 's', 6, 'j', 'j', 'y', 'e', 's', 's', 6, 'j', 'j', 'y', 'e', 'n', 'g', 5, 'j', 'j', 'y', 'e', 'j', 5, 'j', 'j', 'y', 'e', 'c', 5, 'j', 'j', 'y', 'e', 'k', 5, 'j', 'j', 'y', 'e', 't', 5, 'j', 'j', 'y', 'e', 'p', 5, 'j', 'j', 'y', 'e', 'h', 3, 'j', 'j', 'o', 4, 'j', 'j', 'o', 'g', 5, 'j', 'j', 'o', 'g', 'g', 5, 'j', 'j', 'o', 'g', 's', 4, 'j', 'j', 'o', 'n', 5, 'j', 'j', 'o', 'n', 'j', 5, 'j', 'j', 'o', 'n', 'h', 4, 'j', 'j', 'o', 'd', 4, 'j', 'j', 'o', 'l', 5, 'j', 'j', 'o', 'l', 'g', 5, 'j', 'j', 'o', 'l', 'm', 5, 'j', 'j', 'o', 'l', 'b', 5, 'j', 'j', 'o', 'l', 's', 5, 'j', 'j', 'o', 'l', 't', 5, 'j', 'j', 'o', 'l', 'p', 5, 'j', 'j', 'o', 'l', 'h', 4, 'j', 'j', 'o', 'm', 4, 'j', 'j', 'o', 'b', 5, 'j', 'j', 'o', 'b', 's', 4, 'j', 'j', 'o', 's', 5, 'j', 'j', 'o', 's', 's', 5, 'j', 'j', 'o', 'n', 'g', 4, 'j', 'j', 'o', 'j', 4, 'j', 'j', 'o', 'c', 4, 'j', 'j', 'o', 'k', 4, 'j', 'j', 'o', 't', 4, 'j', 'j', 'o', 'p', 4, 'j', 'j', 'o', 'h', 4, 'j', 'j', 'w', 'a', 5, 'j', 'j', 'w', 'a', 'g', 6, 'j', 'j', 'w', 'a', 'g', 'g', 6, 'j', 'j', 'w', 'a', 'g', 's', 5, 'j', 'j', 'w', 'a', 'n', 6, 'j', 'j', 'w', 'a', 'n', 'j', 6, 'j', 'j', 'w', 'a', 'n', 'h', 5, 'j', 'j', 'w', 'a', 'd', 5, 'j', 'j', 'w', 'a', 'l', 6, 'j', 'j', 'w', 'a', 'l', 'g', 6, 'j', 'j', 'w', 'a', 'l', 'm', 6, 'j', 'j', 'w', 'a', 'l', 'b', 6, 'j', 'j', 'w', 'a', 'l', 's', 6, 'j', 'j', 'w', 'a', 'l', 't', 6, 'j', 'j', 'w', 'a', 'l', 'p', 6, 'j', 'j', 'w', 'a', 'l', 'h', 5, 'j', 'j', 'w', 'a', 'm', 5, 'j', 'j', 'w', 'a', 'b', 6, 'j', 'j', 'w', 'a', 'b', 's', 5, 'j', 'j', 'w', 'a', 's', 6, 'j', 'j', 'w', 'a', 's', 's', 6, 'j', 'j', 'w', 'a', 'n', 'g', 5, 'j', 'j', 'w', 'a', 'j', 5, 'j', 'j', 'w', 'a', 'c', 5, 'j', 'j', 'w', 'a', 'k', 5, 'j', 'j', 'w', 'a', 't', 5, 'j', 'j', 'w', 'a', 'p', 5, 'j', 'j', 'w', 'a', 'h', 5, 'j', 'j', 'w', 'a', 'e', 6, 'j', 'j', 'w', 'a', 'e', 'g', 7, 'j', 'j', 'w', 'a', 'e', 'g', 'g', 7, 'j', 'j', 'w', 'a', 'e', 'g', 's', 6, 'j', 'j', 'w', 'a', 'e', 'n', 7, 'j', 'j', 'w', 'a', 'e', 'n', 'j', 7, 'j', 'j', 'w', 'a', 'e', 'n', 'h', 6, 'j', 'j', 'w', 'a', 'e', 'd', 6, 'j', 'j', 'w', 'a', 'e', 'l', 7, 'j', 'j', 'w', 'a', 'e', 'l', 'g', 7, 'j', 'j', 'w', 'a', 'e', 'l', 'm', 7, 'j', 'j', 'w', 'a', 'e', 'l', 'b', 7, 'j', 'j', 'w', 'a', 'e', 'l', 's', 7, 'j', 'j', 'w', 'a', 'e', 'l', 't', 7, 'j', 'j', 'w', 'a', 'e', 'l', 'p', 7, 'j', 'j', 'w', 'a', 'e', 'l', 'h', 6, 'j', 'j', 'w', 'a', 'e', 'm', 6, 'j', 'j', 'w', 'a', 'e', 'b', 7, 'j', 'j', 'w', 'a', 'e', 'b', 's', 6, 'j', 'j', 'w', 'a', 'e', 's', 7, 'j', 'j', 'w', 'a', 'e', 's', 's', 7, 'j', 'j', 'w', 'a', 'e', 'n', 'g', 6, 'j', 'j', 'w', 'a', 'e', 'j', 6, 'j', 'j', 'w', 'a', 'e', 'c', 6, 'j', 'j', 'w', 'a', 'e', 'k', 6, 'j', 'j', 'w', 'a', 'e', 't', 6, 'j', 'j', 'w', 'a', 'e', 'p', 6, 'j', 'j', 'w', 'a', 'e', 'h', 4, 'j', 'j', 'o', 'e', 5, 'j', 'j', 'o', 'e', 'g', 6, 'j', 'j', 'o', 'e', 'g', 'g', 6, 'j', 'j', 'o', 'e', 'g', 's', 5, 'j', 'j', 'o', 'e', 'n', 6, 'j', 'j', 'o', 'e', 'n', 'j', 6, 'j', 'j', 'o', 'e', 'n', 'h', 5, 'j', 'j', 'o', 'e', 'd', 5, 'j', 'j', 'o', 'e', 'l', 6, 'j', 'j', 'o', 'e', 'l', 'g', 6, 'j', 'j', 'o', 'e', 'l', 'm', 6, 'j', 'j', 'o', 'e', 'l', 'b', 6, 'j', 'j', 'o', 'e', 'l', 's', 6, 'j', 'j', 'o', 'e', 'l', 't', 6, 'j', 'j', 'o', 'e', 'l', 'p', 6, 'j', 'j', 'o', 'e', 'l', 'h', 5, 'j', 'j', 'o', 'e', 'm', 5, 'j', 'j', 'o', 'e', 'b', 6, 'j', 'j', 'o', 'e', 'b', 's', 5, 'j', 'j', 'o', 'e', 's', 6, 'j', 'j', 'o', 'e', 's', 's', 6, 'j', 'j', 'o', 'e', 'n', 'g', 5, 'j', 'j', 'o', 'e', 'j', 5, 'j', 'j', 'o', 'e', 'c', 5, 'j', 'j', 'o', 'e', 'k', 5, 'j', 'j', 'o', 'e', 't', 5, 'j', 'j', 'o', 'e', 'p', 5, 'j', 'j', 'o', 'e', 'h', 4, 'j', 'j', 'y', 'o', 5, 'j', 'j', 'y', 'o', 'g', 6, 'j', 'j', 'y', 'o', 'g', 'g', 6, 'j', 'j', 'y', 'o', 'g', 's', 5, 'j', 'j', 'y', 'o', 'n', 6, 'j', 'j', 'y', 'o', 'n', 'j', 6, 'j', 'j', 'y', 'o', 'n', 'h', 5, 'j', 'j', 'y', 'o', 'd', 5, 'j', 'j', 'y', 'o', 'l', 6, 'j', 'j', 'y', 'o', 'l', 'g', 6, 'j', 'j', 'y', 'o', 'l', 'm', 6, 'j', 'j', 'y', 'o', 'l', 'b', 6, 'j', 'j', 'y', 'o', 'l', 's', 6, 'j', 'j', 'y', 'o', 'l', 't', 6, 'j', 'j', 'y', 'o', 'l', 'p', 6, 'j', 'j', 'y', 'o', 'l', 'h', 5, 'j', 'j', 'y', 'o', 'm', 5, 'j', 'j', 'y', 'o', 'b', 6, 'j', 'j', 'y', 'o', 'b', 's', 5, 'j', 'j', 'y', 'o', 's', 6, 'j', 'j', 'y', 'o', 's', 's', 6, 'j', 'j', 'y', 'o', 'n', 'g', 5, 'j', 'j', 'y', 'o', 'j', 5, 'j', 'j', 'y', 'o', 'c', 5, 'j', 'j', 'y', 'o', 'k', 5, 'j', 'j', 'y', 'o', 't', 5, 'j', 'j', 'y', 'o', 'p', 5, 'j', 'j', 'y', 'o', 'h', 3, 'j', 'j', 'u', 4, 'j', 'j', 'u', 'g', 5, 'j', 'j', 'u', 'g', 'g', 5, 'j', 'j', 'u', 'g', 's', 4, 'j', 'j', 'u', 'n', 5, 'j', 'j', 'u', 'n', 'j', 5, 'j', 'j', 'u', 'n', 'h', 4, 'j', 'j', 'u', 'd', 4, 'j', 'j', 'u', 'l', 5, 'j', 'j', 'u', 'l', 'g', 5, 'j', 'j', 'u', 'l', 'm', 5, 'j', 'j', 'u', 'l', 'b', 5, 'j', 'j', 'u', 'l', 's', 5, 'j', 'j', 'u', 'l', 't', 5, 'j', 'j', 'u', 'l', 'p', 5, 'j', 'j', 'u', 'l', 'h', 4, 'j', 'j', 'u', 'm', 4, 'j', 'j', 'u', 'b', 5, 'j', 'j', 'u', 'b', 's', 4, 'j', 'j', 'u', 's', 5, 'j', 'j', 'u', 's', 's', 5, 'j', 'j', 'u', 'n', 'g', 4, 'j', 'j', 'u', 'j', 4, 'j', 'j', 'u', 'c', 4, 'j', 'j', 'u', 'k', 4, 'j', 'j', 'u', 't', 4, 'j', 'j', 'u', 'p', 4, 'j', 'j', 'u', 'h', 5, 'j', 'j', 'w', 'e', 'o', 6, 'j', 'j', 'w', 'e', 'o', 'g', 7, 'j', 'j', 'w', 'e', 'o', 'g', 'g', 7, 'j', 'j', 'w', 'e', 'o', 'g', 's', 6, 'j', 'j', 'w', 'e', 'o', 'n', 7, 'j', 'j', 'w', 'e', 'o', 'n', 'j', 7, 'j', 'j', 'w', 'e', 'o', 'n', 'h', 6, 'j', 'j', 'w', 'e', 'o', 'd', 6, 'j', 'j', 'w', 'e', 'o', 'l', 7, 'j', 'j', 'w', 'e', 'o', 'l', 'g', 7, 'j', 'j', 'w', 'e', 'o', 'l', 'm', 7, 'j', 'j', 'w', 'e', 'o', 'l', 'b', 7, 'j', 'j', 'w', 'e', 'o', 'l', 's', 7, 'j', 'j', 'w', 'e', 'o', 'l', 't', 7, 'j', 'j', 'w', 'e', 'o', 'l', 'p', 7, 'j', 'j', 'w', 'e', 'o', 'l', 'h', 6, 'j', 'j', 'w', 'e', 'o', 'm', 6, 'j', 'j', 'w', 'e', 'o', 'b', 7, 'j', 'j', 'w', 'e', 'o', 'b', 's', 6, 'j', 'j', 'w', 'e', 'o', 's', 7, 'j', 'j', 'w', 'e', 'o', 's', 's', 7, 'j', 'j', 'w', 'e', 'o', 'n', 'g', 6, 'j', 'j', 'w', 'e', 'o', 'j', 6, 'j', 'j', 'w', 'e', 'o', 'c', 6, 'j', 'j', 'w', 'e', 'o', 'k', 6, 'j', 'j', 'w', 'e', 'o', 't', 6, 'j', 'j', 'w', 'e', 'o', 'p', 6, 'j', 'j', 'w', 'e', 'o', 'h', 4, 'j', 'j', 'w', 'e', 5, 'j', 'j', 'w', 'e', 'g', 6, 'j', 'j', 'w', 'e', 'g', 'g', 6, 'j', 'j', 'w', 'e', 'g', 's', 5, 'j', 'j', 'w', 'e', 'n', 6, 'j', 'j', 'w', 'e', 'n', 'j', 6, 'j', 'j', 'w', 'e', 'n', 'h', 5, 'j', 'j', 'w', 'e', 'd', 5, 'j', 'j', 'w', 'e', 'l', 6, 'j', 'j', 'w', 'e', 'l', 'g', 6, 'j', 'j', 'w', 'e', 'l', 'm', 6, 'j', 'j', 'w', 'e', 'l', 'b', 6, 'j', 'j', 'w', 'e', 'l', 's', 6, 'j', 'j', 'w', 'e', 'l', 't', 6, 'j', 'j', 'w', 'e', 'l', 'p', 6, 'j', 'j', 'w', 'e', 'l', 'h', 5, 'j', 'j', 'w', 'e', 'm', 5, 'j', 'j', 'w', 'e', 'b', 6, 'j', 'j', 'w', 'e', 'b', 's', 5, 'j', 'j', 'w', 'e', 's', 6, 'j', 'j', 'w', 'e', 's', 's', 6, 'j', 'j', 'w', 'e', 'n', 'g', 5, 'j', 'j', 'w', 'e', 'j', 5, 'j', 'j', 'w', 'e', 'c', 5, 'j', 'j', 'w', 'e', 'k', 5, 'j', 'j', 'w', 'e', 't', 5, 'j', 'j', 'w', 'e', 'p', 5, 'j', 'j', 'w', 'e', 'h', 4, 'j', 'j', 'w', 'i', 5, 'j', 'j', 'w', 'i', 'g', 6, 'j', 'j', 'w', 'i', 'g', 'g', 6, 'j', 'j', 'w', 'i', 'g', 's', 5, 'j', 'j', 'w', 'i', 'n', 6, 'j', 'j', 'w', 'i', 'n', 'j', 6, 'j', 'j', 'w', 'i', 'n', 'h', 5, 'j', 'j', 'w', 'i', 'd', 5, 'j', 'j', 'w', 'i', 'l', 6, 'j', 'j', 'w', 'i', 'l', 'g', 6, 'j', 'j', 'w', 'i', 'l', 'm', 6, 'j', 'j', 'w', 'i', 'l', 'b', 6, 'j', 'j', 'w', 'i', 'l', 's', 6, 'j', 'j', 'w', 'i', 'l', 't', 6, 'j', 'j', 'w', 'i', 'l', 'p', 6, 'j', 'j', 'w', 'i', 'l', 'h', 5, 'j', 'j', 'w', 'i', 'm', 5, 'j', 'j', 'w', 'i', 'b', 6, 'j', 'j', 'w', 'i', 'b', 's', 5, 'j', 'j', 'w', 'i', 's', 6, 'j', 'j', 'w', 'i', 's', 's', 6, 'j', 'j', 'w', 'i', 'n', 'g', 5, 'j', 'j', 'w', 'i', 'j', 5, 'j', 'j', 'w', 'i', 'c', 5, 'j', 'j', 'w', 'i', 'k', 5, 'j', 'j', 'w', 'i', 't', 5, 'j', 'j', 'w', 'i', 'p', 5, 'j', 'j', 'w', 'i', 'h', 4, 'j', 'j', 'y', 'u', 5, 'j', 'j', 'y', 'u', 'g', 6, 'j', 'j', 'y', 'u', 'g', 'g', 6, 'j', 'j', 'y', 'u', 'g', 's', 5, 'j', 'j', 'y', 'u', 'n', 6, 'j', 'j', 'y', 'u', 'n', 'j', 6, 'j', 'j', 'y', 'u', 'n', 'h', 5, 'j', 'j', 'y', 'u', 'd', 5, 'j', 'j', 'y', 'u', 'l', 6, 'j', 'j', 'y', 'u', 'l', 'g', 6, 'j', 'j', 'y', 'u', 'l', 'm', 6, 'j', 'j', 'y', 'u', 'l', 'b', 6, 'j', 'j', 'y', 'u', 'l', 's', 6, 'j', 'j', 'y', 'u', 'l', 't', 6, 'j', 'j', 'y', 'u', 'l', 'p', 6, 'j', 'j', 'y', 'u', 'l', 'h', 5, 'j', 'j', 'y', 'u', 'm', 5, 'j', 'j', 'y', 'u', 'b', 6, 'j', 'j', 'y', 'u', 'b', 's', 5, 'j', 'j', 'y', 'u', 's', 6, 'j', 'j', 'y', 'u', 's', 's', 6, 'j', 'j', 'y', 'u', 'n', 'g', 5, 'j', 'j', 'y', 'u', 'j', 5, 'j', 'j', 'y', 'u', 'c', 5, 'j', 'j', 'y', 'u', 'k', 5, 'j', 'j', 'y', 'u', 't', 5, 'j', 'j', 'y', 'u', 'p', 5, 'j', 'j', 'y', 'u', 'h', 4, 'j', 'j', 'e', 'u', 5, 'j', 'j', 'e', 'u', 'g', 6, 'j', 'j', 'e', 'u', 'g', 'g', 6, 'j', 'j', 'e', 'u', 'g', 's', 5, 'j', 'j', 'e', 'u', 'n', 6, 'j', 'j', 'e', 'u', 'n', 'j', 6, 'j', 'j', 'e', 'u', 'n', 'h', 5, 'j', 'j', 'e', 'u', 'd', 5, 'j', 'j', 'e', 'u', 'l', 6, 'j', 'j', 'e', 'u', 'l', 'g', 6, 'j', 'j', 'e', 'u', 'l', 'm', 6, 'j', 'j', 'e', 'u', 'l', 'b', 6, 'j', 'j', 'e', 'u', 'l', 's', 6, 'j', 'j', 'e', 'u', 'l', 't', 6, 'j', 'j', 'e', 'u', 'l', 'p', 6, 'j', 'j', 'e', 'u', 'l', 'h', 5, 'j', 'j', 'e', 'u', 'm', 5, 'j', 'j', 'e', 'u', 'b', 6, 'j', 'j', 'e', 'u', 'b', 's', 5, 'j', 'j', 'e', 'u', 's', 6, 'j', 'j', 'e', 'u', 's', 's', 6, 'j', 'j', 'e', 'u', 'n', 'g', 5, 'j', 'j', 'e', 'u', 'j', 5, 'j', 'j', 'e', 'u', 'c', 5, 'j', 'j', 'e', 'u', 'k', 5, 'j', 'j', 'e', 'u', 't', 5, 'j', 'j', 'e', 'u', 'p', 5, 'j', 'j', 'e', 'u', 'h', 4, 'j', 'j', 'y', 'i', 5, 'j', 'j', 'y', 'i', 'g', 6, 'j', 'j', 'y', 'i', 'g', 'g', 6, 'j', 'j', 'y', 'i', 'g', 's', 5, 'j', 'j', 'y', 'i', 'n', 6, 'j', 'j', 'y', 'i', 'n', 'j', 6, 'j', 'j', 'y', 'i', 'n', 'h', 5, 'j', 'j', 'y', 'i', 'd', 5, 'j', 'j', 'y', 'i', 'l', 6, 'j', 'j', 'y', 'i', 'l', 'g', 6, 'j', 'j', 'y', 'i', 'l', 'm', 6, 'j', 'j', 'y', 'i', 'l', 'b', 6, 'j', 'j', 'y', 'i', 'l', 's', 6, 'j', 'j', 'y', 'i', 'l', 't', 6, 'j', 'j', 'y', 'i', 'l', 'p', 6, 'j', 'j', 'y', 'i', 'l', 'h', 5, 'j', 'j', 'y', 'i', 'm', 5, 'j', 'j', 'y', 'i', 'b', 6, 'j', 'j', 'y', 'i', 'b', 's', 5, 'j', 'j', 'y', 'i', 's', 6, 'j', 'j', 'y', 'i', 's', 's', 6, 'j', 'j', 'y', 'i', 'n', 'g', 5, 'j', 'j', 'y', 'i', 'j', 5, 'j', 'j', 'y', 'i', 'c', 5, 'j', 'j', 'y', 'i', 'k', 5, 'j', 'j', 'y', 'i', 't', 5, 'j', 'j', 'y', 'i', 'p', 5, 'j', 'j', 'y', 'i', 'h', 3, 'j', 'j', 'i', 4, 'j', 'j', 'i', 'g', 5, 'j', 'j', 'i', 'g', 'g', 5, 'j', 'j', 'i', 'g', 's', 4, 'j', 'j', 'i', 'n', 5, 'j', 'j', 'i', 'n', 'j', 5, 'j', 'j', 'i', 'n', 'h', 4, 'j', 'j', 'i', 'd', 4, 'j', 'j', 'i', 'l', 5, 'j', 'j', 'i', 'l', 'g', 5, 'j', 'j', 'i', 'l', 'm', 5, 'j', 'j', 'i', 'l', 'b', 5, 'j', 'j', 'i', 'l', 's', 5, 'j', 'j', 'i', 'l', 't', 5, 'j', 'j', 'i', 'l', 'p', 5, 'j', 'j', 'i', 'l', 'h', 4, 'j', 'j', 'i', 'm', 4, 'j', 'j', 'i', 'b', 5, 'j', 'j', 'i', 'b', 's', 4, 'j', 'j', 'i', 's', 5, 'j', 'j', 'i', 's', 's', 5, 'j', 'j', 'i', 'n', 'g', 4, 'j', 'j', 'i', 'j', 4, 'j', 'j', 'i', 'c', 4, 'j', 'j', 'i', 'k', 4, 'j', 'j', 'i', 't', 4, 'j', 'j', 'i', 'p', 4, 'j', 'j', 'i', 'h', 2, 'c', 'a', 3, 'c', 'a', 'g', 4, 'c', 'a', 'g', 'g', 4, 'c', 'a', 'g', 's', 3, 'c', 'a', 'n', 4, 'c', 'a', 'n', 'j', 4, 'c', 'a', 'n', 'h', 3, 'c', 'a', 'd', 3, 'c', 'a', 'l', 4, 'c', 'a', 'l', 'g', 4, 'c', 'a', 'l', 'm', 4, 'c', 'a', 'l', 'b', 4, 'c', 'a', 'l', 's', 4, 'c', 'a', 'l', 't', 4, 'c', 'a', 'l', 'p', 4, 'c', 'a', 'l', 'h', 3, 'c', 'a', 'm', 3, 'c', 'a', 'b', 4, 'c', 'a', 'b', 's', 3, 'c', 'a', 's', 4, 'c', 'a', 's', 's', 4, 'c', 'a', 'n', 'g', 3, 'c', 'a', 'j', 3, 'c', 'a', 'c', 3, 'c', 'a', 'k', 3, 'c', 'a', 't', 3, 'c', 'a', 'p', 3, 'c', 'a', 'h', 3, 'c', 'a', 'e', 4, 'c', 'a', 'e', 'g', 5, 'c', 'a', 'e', 'g', 'g', 5, 'c', 'a', 'e', 'g', 's', 4, 'c', 'a', 'e', 'n', 5, 'c', 'a', 'e', 'n', 'j', 5, 'c', 'a', 'e', 'n', 'h', 4, 'c', 'a', 'e', 'd', 4, 'c', 'a', 'e', 'l', 5, 'c', 'a', 'e', 'l', 'g', 5, 'c', 'a', 'e', 'l', 'm', 5, 'c', 'a', 'e', 'l', 'b', 5, 'c', 'a', 'e', 'l', 's', 5, 'c', 'a', 'e', 'l', 't', 5, 'c', 'a', 'e', 'l', 'p', 5, 'c', 'a', 'e', 'l', 'h', 4, 'c', 'a', 'e', 'm', 4, 'c', 'a', 'e', 'b', 5, 'c', 'a', 'e', 'b', 's', 4, 'c', 'a', 'e', 's', 5, 'c', 'a', 'e', 's', 's', 5, 'c', 'a', 'e', 'n', 'g', 4, 'c', 'a', 'e', 'j', 4, 'c', 'a', 'e', 'c', 4, 'c', 'a', 'e', 'k', 4, 'c', 'a', 'e', 't', 4, 'c', 'a', 'e', 'p', 4, 'c', 'a', 'e', 'h', 3, 'c', 'y', 'a', 4, 'c', 'y', 'a', 'g', 5, 'c', 'y', 'a', 'g', 'g', 5, 'c', 'y', 'a', 'g', 's', 4, 'c', 'y', 'a', 'n', 5, 'c', 'y', 'a', 'n', 'j', 5, 'c', 'y', 'a', 'n', 'h', 4, 'c', 'y', 'a', 'd', 4, 'c', 'y', 'a', 'l', 5, 'c', 'y', 'a', 'l', 'g', 5, 'c', 'y', 'a', 'l', 'm', 5, 'c', 'y', 'a', 'l', 'b', 5, 'c', 'y', 'a', 'l', 's', 5, 'c', 'y', 'a', 'l', 't', 5, 'c', 'y', 'a', 'l', 'p', 5, 'c', 'y', 'a', 'l', 'h', 4, 'c', 'y', 'a', 'm', 4, 'c', 'y', 'a', 'b', 5, 'c', 'y', 'a', 'b', 's', 4, 'c', 'y', 'a', 's', 5, 'c', 'y', 'a', 's', 's', 5, 'c', 'y', 'a', 'n', 'g', 4, 'c', 'y', 'a', 'j', 4, 'c', 'y', 'a', 'c', 4, 'c', 'y', 'a', 'k', 4, 'c', 'y', 'a', 't', 4, 'c', 'y', 'a', 'p', 4, 'c', 'y', 'a', 'h', 4, 'c', 'y', 'a', 'e', 5, 'c', 'y', 'a', 'e', 'g', 6, 'c', 'y', 'a', 'e', 'g', 'g', 6, 'c', 'y', 'a', 'e', 'g', 's', 5, 'c', 'y', 'a', 'e', 'n', 6, 'c', 'y', 'a', 'e', 'n', 'j', 6, 'c', 'y', 'a', 'e', 'n', 'h', 5, 'c', 'y', 'a', 'e', 'd', 5, 'c', 'y', 'a', 'e', 'l', 6, 'c', 'y', 'a', 'e', 'l', 'g', 6, 'c', 'y', 'a', 'e', 'l', 'm', 6, 'c', 'y', 'a', 'e', 'l', 'b', 6, 'c', 'y', 'a', 'e', 'l', 's', 6, 'c', 'y', 'a', 'e', 'l', 't', 6, 'c', 'y', 'a', 'e', 'l', 'p', 6, 'c', 'y', 'a', 'e', 'l', 'h', 5, 'c', 'y', 'a', 'e', 'm', 5, 'c', 'y', 'a', 'e', 'b', 6, 'c', 'y', 'a', 'e', 'b', 's', 5, 'c', 'y', 'a', 'e', 's', 6, 'c', 'y', 'a', 'e', 's', 's', 6, 'c', 'y', 'a', 'e', 'n', 'g', 5, 'c', 'y', 'a', 'e', 'j', 5, 'c', 'y', 'a', 'e', 'c', 5, 'c', 'y', 'a', 'e', 'k', 5, 'c', 'y', 'a', 'e', 't', 5, 'c', 'y', 'a', 'e', 'p', 5, 'c', 'y', 'a', 'e', 'h', 3, 'c', 'e', 'o', 4, 'c', 'e', 'o', 'g', 5, 'c', 'e', 'o', 'g', 'g', 5, 'c', 'e', 'o', 'g', 's', 4, 'c', 'e', 'o', 'n', 5, 'c', 'e', 'o', 'n', 'j', 5, 'c', 'e', 'o', 'n', 'h', 4, 'c', 'e', 'o', 'd', 4, 'c', 'e', 'o', 'l', 5, 'c', 'e', 'o', 'l', 'g', 5, 'c', 'e', 'o', 'l', 'm', 5, 'c', 'e', 'o', 'l', 'b', 5, 'c', 'e', 'o', 'l', 's', 5, 'c', 'e', 'o', 'l', 't', 5, 'c', 'e', 'o', 'l', 'p', 5, 'c', 'e', 'o', 'l', 'h', 4, 'c', 'e', 'o', 'm', 4, 'c', 'e', 'o', 'b', 5, 'c', 'e', 'o', 'b', 's', 4, 'c', 'e', 'o', 's', 5, 'c', 'e', 'o', 's', 's', 5, 'c', 'e', 'o', 'n', 'g', 4, 'c', 'e', 'o', 'j', 4, 'c', 'e', 'o', 'c', 4, 'c', 'e', 'o', 'k', 4, 'c', 'e', 'o', 't', 4, 'c', 'e', 'o', 'p', 4, 'c', 'e', 'o', 'h', 2, 'c', 'e', 3, 'c', 'e', 'g', 4, 'c', 'e', 'g', 'g', 4, 'c', 'e', 'g', 's', 3, 'c', 'e', 'n', 4, 'c', 'e', 'n', 'j', 4, 'c', 'e', 'n', 'h', 3, 'c', 'e', 'd', 3, 'c', 'e', 'l', 4, 'c', 'e', 'l', 'g', 4, 'c', 'e', 'l', 'm', 4, 'c', 'e', 'l', 'b', 4, 'c', 'e', 'l', 's', 4, 'c', 'e', 'l', 't', 4, 'c', 'e', 'l', 'p', 4, 'c', 'e', 'l', 'h', 3, 'c', 'e', 'm', 3, 'c', 'e', 'b', 4, 'c', 'e', 'b', 's', 3, 'c', 'e', 's', 4, 'c', 'e', 's', 's', 4, 'c', 'e', 'n', 'g', 3, 'c', 'e', 'j', 3, 'c', 'e', 'c', 3, 'c', 'e', 'k', 3, 'c', 'e', 't', 3, 'c', 'e', 'p', 3, 'c', 'e', 'h', 4, 'c', 'y', 'e', 'o', 5, 'c', 'y', 'e', 'o', 'g', 6, 'c', 'y', 'e', 'o', 'g', 'g', 6, 'c', 'y', 'e', 'o', 'g', 's', 5, 'c', 'y', 'e', 'o', 'n', 6, 'c', 'y', 'e', 'o', 'n', 'j', 6, 'c', 'y', 'e', 'o', 'n', 'h', 5, 'c', 'y', 'e', 'o', 'd', 5, 'c', 'y', 'e', 'o', 'l', 6, 'c', 'y', 'e', 'o', 'l', 'g', 6, 'c', 'y', 'e', 'o', 'l', 'm', 6, 'c', 'y', 'e', 'o', 'l', 'b', 6, 'c', 'y', 'e', 'o', 'l', 's', 6, 'c', 'y', 'e', 'o', 'l', 't', 6, 'c', 'y', 'e', 'o', 'l', 'p', 6, 'c', 'y', 'e', 'o', 'l', 'h', 5, 'c', 'y', 'e', 'o', 'm', 5, 'c', 'y', 'e', 'o', 'b', 6, 'c', 'y', 'e', 'o', 'b', 's', 5, 'c', 'y', 'e', 'o', 's', 6, 'c', 'y', 'e', 'o', 's', 's', 6, 'c', 'y', 'e', 'o', 'n', 'g', 5, 'c', 'y', 'e', 'o', 'j', 5, 'c', 'y', 'e', 'o', 'c', 5, 'c', 'y', 'e', 'o', 'k', 5, 'c', 'y', 'e', 'o', 't', 5, 'c', 'y', 'e', 'o', 'p', 5, 'c', 'y', 'e', 'o', 'h', 3, 'c', 'y', 'e', 4, 'c', 'y', 'e', 'g', 5, 'c', 'y', 'e', 'g', 'g', 5, 'c', 'y', 'e', 'g', 's', 4, 'c', 'y', 'e', 'n', 5, 'c', 'y', 'e', 'n', 'j', 5, 'c', 'y', 'e', 'n', 'h', 4, 'c', 'y', 'e', 'd', 4, 'c', 'y', 'e', 'l', 5, 'c', 'y', 'e', 'l', 'g', 5, 'c', 'y', 'e', 'l', 'm', 5, 'c', 'y', 'e', 'l', 'b', 5, 'c', 'y', 'e', 'l', 's', 5, 'c', 'y', 'e', 'l', 't', 5, 'c', 'y', 'e', 'l', 'p', 5, 'c', 'y', 'e', 'l', 'h', 4, 'c', 'y', 'e', 'm', 4, 'c', 'y', 'e', 'b', 5, 'c', 'y', 'e', 'b', 's', 4, 'c', 'y', 'e', 's', 5, 'c', 'y', 'e', 's', 's', 5, 'c', 'y', 'e', 'n', 'g', 4, 'c', 'y', 'e', 'j', 4, 'c', 'y', 'e', 'c', 4, 'c', 'y', 'e', 'k', 4, 'c', 'y', 'e', 't', 4, 'c', 'y', 'e', 'p', 4, 'c', 'y', 'e', 'h', 2, 'c', 'o', 3, 'c', 'o', 'g', 4, 'c', 'o', 'g', 'g', 4, 'c', 'o', 'g', 's', 3, 'c', 'o', 'n', 4, 'c', 'o', 'n', 'j', 4, 'c', 'o', 'n', 'h', 3, 'c', 'o', 'd', 3, 'c', 'o', 'l', 4, 'c', 'o', 'l', 'g', 4, 'c', 'o', 'l', 'm', 4, 'c', 'o', 'l', 'b', 4, 'c', 'o', 'l', 's', 4, 'c', 'o', 'l', 't', 4, 'c', 'o', 'l', 'p', 4, 'c', 'o', 'l', 'h', 3, 'c', 'o', 'm', 3, 'c', 'o', 'b', 4, 'c', 'o', 'b', 's', 3, 'c', 'o', 's', 4, 'c', 'o', 's', 's', 4, 'c', 'o', 'n', 'g', 3, 'c', 'o', 'j', 3, 'c', 'o', 'c', 3, 'c', 'o', 'k', 3, 'c', 'o', 't', 3, 'c', 'o', 'p', 3, 'c', 'o', 'h', 3, 'c', 'w', 'a', 4, 'c', 'w', 'a', 'g', 5, 'c', 'w', 'a', 'g', 'g', 5, 'c', 'w', 'a', 'g', 's', 4, 'c', 'w', 'a', 'n', 5, 'c', 'w', 'a', 'n', 'j', 5, 'c', 'w', 'a', 'n', 'h', 4, 'c', 'w', 'a', 'd', 4, 'c', 'w', 'a', 'l', 5, 'c', 'w', 'a', 'l', 'g', 5, 'c', 'w', 'a', 'l', 'm', 5, 'c', 'w', 'a', 'l', 'b', 5, 'c', 'w', 'a', 'l', 's', 5, 'c', 'w', 'a', 'l', 't', 5, 'c', 'w', 'a', 'l', 'p', 5, 'c', 'w', 'a', 'l', 'h', 4, 'c', 'w', 'a', 'm', 4, 'c', 'w', 'a', 'b', 5, 'c', 'w', 'a', 'b', 's', 4, 'c', 'w', 'a', 's', 5, 'c', 'w', 'a', 's', 's', 5, 'c', 'w', 'a', 'n', 'g', 4, 'c', 'w', 'a', 'j', 4, 'c', 'w', 'a', 'c', 4, 'c', 'w', 'a', 'k', 4, 'c', 'w', 'a', 't', 4, 'c', 'w', 'a', 'p', 4, 'c', 'w', 'a', 'h', 4, 'c', 'w', 'a', 'e', 5, 'c', 'w', 'a', 'e', 'g', 6, 'c', 'w', 'a', 'e', 'g', 'g', 6, 'c', 'w', 'a', 'e', 'g', 's', 5, 'c', 'w', 'a', 'e', 'n', 6, 'c', 'w', 'a', 'e', 'n', 'j', 6, 'c', 'w', 'a', 'e', 'n', 'h', 5, 'c', 'w', 'a', 'e', 'd', 5, 'c', 'w', 'a', 'e', 'l', 6, 'c', 'w', 'a', 'e', 'l', 'g', 6, 'c', 'w', 'a', 'e', 'l', 'm', 6, 'c', 'w', 'a', 'e', 'l', 'b', 6, 'c', 'w', 'a', 'e', 'l', 's', 6, 'c', 'w', 'a', 'e', 'l', 't', 6, 'c', 'w', 'a', 'e', 'l', 'p', 6, 'c', 'w', 'a', 'e', 'l', 'h', 5, 'c', 'w', 'a', 'e', 'm', 5, 'c', 'w', 'a', 'e', 'b', 6, 'c', 'w', 'a', 'e', 'b', 's', 5, 'c', 'w', 'a', 'e', 's', 6, 'c', 'w', 'a', 'e', 's', 's', 6, 'c', 'w', 'a', 'e', 'n', 'g', 5, 'c', 'w', 'a', 'e', 'j', 5, 'c', 'w', 'a', 'e', 'c', 5, 'c', 'w', 'a', 'e', 'k', 5, 'c', 'w', 'a', 'e', 't', 5, 'c', 'w', 'a', 'e', 'p', 5, 'c', 'w', 'a', 'e', 'h', 3, 'c', 'o', 'e', 4, 'c', 'o', 'e', 'g', 5, 'c', 'o', 'e', 'g', 'g', 5, 'c', 'o', 'e', 'g', 's', 4, 'c', 'o', 'e', 'n', 5, 'c', 'o', 'e', 'n', 'j', 5, 'c', 'o', 'e', 'n', 'h', 4, 'c', 'o', 'e', 'd', 4, 'c', 'o', 'e', 'l', 5, 'c', 'o', 'e', 'l', 'g', 5, 'c', 'o', 'e', 'l', 'm', 5, 'c', 'o', 'e', 'l', 'b', 5, 'c', 'o', 'e', 'l', 's', 5, 'c', 'o', 'e', 'l', 't', 5, 'c', 'o', 'e', 'l', 'p', 5, 'c', 'o', 'e', 'l', 'h', 4, 'c', 'o', 'e', 'm', 4, 'c', 'o', 'e', 'b', 5, 'c', 'o', 'e', 'b', 's', 4, 'c', 'o', 'e', 's', 5, 'c', 'o', 'e', 's', 's', 5, 'c', 'o', 'e', 'n', 'g', 4, 'c', 'o', 'e', 'j', 4, 'c', 'o', 'e', 'c', 4, 'c', 'o', 'e', 'k', 4, 'c', 'o', 'e', 't', 4, 'c', 'o', 'e', 'p', 4, 'c', 'o', 'e', 'h', 3, 'c', 'y', 'o', 4, 'c', 'y', 'o', 'g', 5, 'c', 'y', 'o', 'g', 'g', 5, 'c', 'y', 'o', 'g', 's', 4, 'c', 'y', 'o', 'n', 5, 'c', 'y', 'o', 'n', 'j', 5, 'c', 'y', 'o', 'n', 'h', 4, 'c', 'y', 'o', 'd', 4, 'c', 'y', 'o', 'l', 5, 'c', 'y', 'o', 'l', 'g', 5, 'c', 'y', 'o', 'l', 'm', 5, 'c', 'y', 'o', 'l', 'b', 5, 'c', 'y', 'o', 'l', 's', 5, 'c', 'y', 'o', 'l', 't', 5, 'c', 'y', 'o', 'l', 'p', 5, 'c', 'y', 'o', 'l', 'h', 4, 'c', 'y', 'o', 'm', 4, 'c', 'y', 'o', 'b', 5, 'c', 'y', 'o', 'b', 's', 4, 'c', 'y', 'o', 's', 5, 'c', 'y', 'o', 's', 's', 5, 'c', 'y', 'o', 'n', 'g', 4, 'c', 'y', 'o', 'j', 4, 'c', 'y', 'o', 'c', 4, 'c', 'y', 'o', 'k', 4, 'c', 'y', 'o', 't', 4, 'c', 'y', 'o', 'p', 4, 'c', 'y', 'o', 'h', 2, 'c', 'u', 3, 'c', 'u', 'g', 4, 'c', 'u', 'g', 'g', 4, 'c', 'u', 'g', 's', 3, 'c', 'u', 'n', 4, 'c', 'u', 'n', 'j', 4, 'c', 'u', 'n', 'h', 3, 'c', 'u', 'd', 3, 'c', 'u', 'l', 4, 'c', 'u', 'l', 'g', 4, 'c', 'u', 'l', 'm', 4, 'c', 'u', 'l', 'b', 4, 'c', 'u', 'l', 's', 4, 'c', 'u', 'l', 't', 4, 'c', 'u', 'l', 'p', 4, 'c', 'u', 'l', 'h', 3, 'c', 'u', 'm', 3, 'c', 'u', 'b', 4, 'c', 'u', 'b', 's', 3, 'c', 'u', 's', 4, 'c', 'u', 's', 's', 4, 'c', 'u', 'n', 'g', 3, 'c', 'u', 'j', 3, 'c', 'u', 'c', 3, 'c', 'u', 'k', 3, 'c', 'u', 't', 3, 'c', 'u', 'p', 3, 'c', 'u', 'h', 4, 'c', 'w', 'e', 'o', 5, 'c', 'w', 'e', 'o', 'g', 6, 'c', 'w', 'e', 'o', 'g', 'g', 6, 'c', 'w', 'e', 'o', 'g', 's', 5, 'c', 'w', 'e', 'o', 'n', 6, 'c', 'w', 'e', 'o', 'n', 'j', 6, 'c', 'w', 'e', 'o', 'n', 'h', 5, 'c', 'w', 'e', 'o', 'd', 5, 'c', 'w', 'e', 'o', 'l', 6, 'c', 'w', 'e', 'o', 'l', 'g', 6, 'c', 'w', 'e', 'o', 'l', 'm', 6, 'c', 'w', 'e', 'o', 'l', 'b', 6, 'c', 'w', 'e', 'o', 'l', 's', 6, 'c', 'w', 'e', 'o', 'l', 't', 6, 'c', 'w', 'e', 'o', 'l', 'p', 6, 'c', 'w', 'e', 'o', 'l', 'h', 5, 'c', 'w', 'e', 'o', 'm', 5, 'c', 'w', 'e', 'o', 'b', 6, 'c', 'w', 'e', 'o', 'b', 's', 5, 'c', 'w', 'e', 'o', 's', 6, 'c', 'w', 'e', 'o', 's', 's', 6, 'c', 'w', 'e', 'o', 'n', 'g', 5, 'c', 'w', 'e', 'o', 'j', 5, 'c', 'w', 'e', 'o', 'c', 5, 'c', 'w', 'e', 'o', 'k', 5, 'c', 'w', 'e', 'o', 't', 5, 'c', 'w', 'e', 'o', 'p', 5, 'c', 'w', 'e', 'o', 'h', 3, 'c', 'w', 'e', 4, 'c', 'w', 'e', 'g', 5, 'c', 'w', 'e', 'g', 'g', 5, 'c', 'w', 'e', 'g', 's', 4, 'c', 'w', 'e', 'n', 5, 'c', 'w', 'e', 'n', 'j', 5, 'c', 'w', 'e', 'n', 'h', 4, 'c', 'w', 'e', 'd', 4, 'c', 'w', 'e', 'l', 5, 'c', 'w', 'e', 'l', 'g', 5, 'c', 'w', 'e', 'l', 'm', 5, 'c', 'w', 'e', 'l', 'b', 5, 'c', 'w', 'e', 'l', 's', 5, 'c', 'w', 'e', 'l', 't', 5, 'c', 'w', 'e', 'l', 'p', 5, 'c', 'w', 'e', 'l', 'h', 4, 'c', 'w', 'e', 'm', 4, 'c', 'w', 'e', 'b', 5, 'c', 'w', 'e', 'b', 's', 4, 'c', 'w', 'e', 's', 5, 'c', 'w', 'e', 's', 's', 5, 'c', 'w', 'e', 'n', 'g', 4, 'c', 'w', 'e', 'j', 4, 'c', 'w', 'e', 'c', 4, 'c', 'w', 'e', 'k', 4, 'c', 'w', 'e', 't', 4, 'c', 'w', 'e', 'p', 4, 'c', 'w', 'e', 'h', 3, 'c', 'w', 'i', 4, 'c', 'w', 'i', 'g', 5, 'c', 'w', 'i', 'g', 'g', 5, 'c', 'w', 'i', 'g', 's', 4, 'c', 'w', 'i', 'n', 5, 'c', 'w', 'i', 'n', 'j', 5, 'c', 'w', 'i', 'n', 'h', 4, 'c', 'w', 'i', 'd', 4, 'c', 'w', 'i', 'l', 5, 'c', 'w', 'i', 'l', 'g', 5, 'c', 'w', 'i', 'l', 'm', 5, 'c', 'w', 'i', 'l', 'b', 5, 'c', 'w', 'i', 'l', 's', 5, 'c', 'w', 'i', 'l', 't', 5, 'c', 'w', 'i', 'l', 'p', 5, 'c', 'w', 'i', 'l', 'h', 4, 'c', 'w', 'i', 'm', 4, 'c', 'w', 'i', 'b', 5, 'c', 'w', 'i', 'b', 's', 4, 'c', 'w', 'i', 's', 5, 'c', 'w', 'i', 's', 's', 5, 'c', 'w', 'i', 'n', 'g', 4, 'c', 'w', 'i', 'j', 4, 'c', 'w', 'i', 'c', 4, 'c', 'w', 'i', 'k', 4, 'c', 'w', 'i', 't', 4, 'c', 'w', 'i', 'p', 4, 'c', 'w', 'i', 'h', 3, 'c', 'y', 'u', 4, 'c', 'y', 'u', 'g', 5, 'c', 'y', 'u', 'g', 'g', 5, 'c', 'y', 'u', 'g', 's', 4, 'c', 'y', 'u', 'n', 5, 'c', 'y', 'u', 'n', 'j', 5, 'c', 'y', 'u', 'n', 'h', 4, 'c', 'y', 'u', 'd', 4, 'c', 'y', 'u', 'l', 5, 'c', 'y', 'u', 'l', 'g', 5, 'c', 'y', 'u', 'l', 'm', 5, 'c', 'y', 'u', 'l', 'b', 5, 'c', 'y', 'u', 'l', 's', 5, 'c', 'y', 'u', 'l', 't', 5, 'c', 'y', 'u', 'l', 'p', 5, 'c', 'y', 'u', 'l', 'h', 4, 'c', 'y', 'u', 'm', 4, 'c', 'y', 'u', 'b', 5, 'c', 'y', 'u', 'b', 's', 4, 'c', 'y', 'u', 's', 5, 'c', 'y', 'u', 's', 's', 5, 'c', 'y', 'u', 'n', 'g', 4, 'c', 'y', 'u', 'j', 4, 'c', 'y', 'u', 'c', 4, 'c', 'y', 'u', 'k', 4, 'c', 'y', 'u', 't', 4, 'c', 'y', 'u', 'p', 4, 'c', 'y', 'u', 'h', 3, 'c', 'e', 'u', 4, 'c', 'e', 'u', 'g', 5, 'c', 'e', 'u', 'g', 'g', 5, 'c', 'e', 'u', 'g', 's', 4, 'c', 'e', 'u', 'n', 5, 'c', 'e', 'u', 'n', 'j', 5, 'c', 'e', 'u', 'n', 'h', 4, 'c', 'e', 'u', 'd', 4, 'c', 'e', 'u', 'l', 5, 'c', 'e', 'u', 'l', 'g', 5, 'c', 'e', 'u', 'l', 'm', 5, 'c', 'e', 'u', 'l', 'b', 5, 'c', 'e', 'u', 'l', 's', 5, 'c', 'e', 'u', 'l', 't', 5, 'c', 'e', 'u', 'l', 'p', 5, 'c', 'e', 'u', 'l', 'h', 4, 'c', 'e', 'u', 'm', 4, 'c', 'e', 'u', 'b', 5, 'c', 'e', 'u', 'b', 's', 4, 'c', 'e', 'u', 's', 5, 'c', 'e', 'u', 's', 's', 5, 'c', 'e', 'u', 'n', 'g', 4, 'c', 'e', 'u', 'j', 4, 'c', 'e', 'u', 'c', 4, 'c', 'e', 'u', 'k', 4, 'c', 'e', 'u', 't', 4, 'c', 'e', 'u', 'p', 4, 'c', 'e', 'u', 'h', 3, 'c', 'y', 'i', 4, 'c', 'y', 'i', 'g', 5, 'c', 'y', 'i', 'g', 'g', 5, 'c', 'y', 'i', 'g', 's', 4, 'c', 'y', 'i', 'n', 5, 'c', 'y', 'i', 'n', 'j', 5, 'c', 'y', 'i', 'n', 'h', 4, 'c', 'y', 'i', 'd', 4, 'c', 'y', 'i', 'l', 5, 'c', 'y', 'i', 'l', 'g', 5, 'c', 'y', 'i', 'l', 'm', 5, 'c', 'y', 'i', 'l', 'b', 5, 'c', 'y', 'i', 'l', 's', 5, 'c', 'y', 'i', 'l', 't', 5, 'c', 'y', 'i', 'l', 'p', 5, 'c', 'y', 'i', 'l', 'h', 4, 'c', 'y', 'i', 'm', 4, 'c', 'y', 'i', 'b', 5, 'c', 'y', 'i', 'b', 's', 4, 'c', 'y', 'i', 's', 5, 'c', 'y', 'i', 's', 's', 5, 'c', 'y', 'i', 'n', 'g', 4, 'c', 'y', 'i', 'j', 4, 'c', 'y', 'i', 'c', 4, 'c', 'y', 'i', 'k', 4, 'c', 'y', 'i', 't', 4, 'c', 'y', 'i', 'p', 4, 'c', 'y', 'i', 'h', 2, 'c', 'i', 3, 'c', 'i', 'g', 4, 'c', 'i', 'g', 'g', 4, 'c', 'i', 'g', 's', 3, 'c', 'i', 'n', 4, 'c', 'i', 'n', 'j', 4, 'c', 'i', 'n', 'h', 3, 'c', 'i', 'd', 3, 'c', 'i', 'l', 4, 'c', 'i', 'l', 'g', 4, 'c', 'i', 'l', 'm', 4, 'c', 'i', 'l', 'b', 4, 'c', 'i', 'l', 's', 4, 'c', 'i', 'l', 't', 4, 'c', 'i', 'l', 'p', 4, 'c', 'i', 'l', 'h', 3, 'c', 'i', 'm', 3, 'c', 'i', 'b', 4, 'c', 'i', 'b', 's', 3, 'c', 'i', 's', 4, 'c', 'i', 's', 's', 4, 'c', 'i', 'n', 'g', 3, 'c', 'i', 'j', 3, 'c', 'i', 'c', 3, 'c', 'i', 'k', 3, 'c', 'i', 't', 3, 'c', 'i', 'p', 3, 'c', 'i', 'h', 2, 'k', 'a', 3, 'k', 'a', 'g', 4, 'k', 'a', 'g', 'g', 4, 'k', 'a', 'g', 's', 3, 'k', 'a', 'n', 4, 'k', 'a', 'n', 'j', 4, 'k', 'a', 'n', 'h', 3, 'k', 'a', 'd', 3, 'k', 'a', 'l', 4, 'k', 'a', 'l', 'g', 4, 'k', 'a', 'l', 'm', 4, 'k', 'a', 'l', 'b', 4, 'k', 'a', 'l', 's', 4, 'k', 'a', 'l', 't', 4, 'k', 'a', 'l', 'p', 4, 'k', 'a', 'l', 'h', 3, 'k', 'a', 'm', 3, 'k', 'a', 'b', 4, 'k', 'a', 'b', 's', 3, 'k', 'a', 's', 4, 'k', 'a', 's', 's', 4, 'k', 'a', 'n', 'g', 3, 'k', 'a', 'j', 3, 'k', 'a', 'c', 3, 'k', 'a', 'k', 3, 'k', 'a', 't', 3, 'k', 'a', 'p', 3, 'k', 'a', 'h', 3, 'k', 'a', 'e', 4, 'k', 'a', 'e', 'g', 5, 'k', 'a', 'e', 'g', 'g', 5, 'k', 'a', 'e', 'g', 's', 4, 'k', 'a', 'e', 'n', 5, 'k', 'a', 'e', 'n', 'j', 5, 'k', 'a', 'e', 'n', 'h', 4, 'k', 'a', 'e', 'd', 4, 'k', 'a', 'e', 'l', 5, 'k', 'a', 'e', 'l', 'g', 5, 'k', 'a', 'e', 'l', 'm', 5, 'k', 'a', 'e', 'l', 'b', 5, 'k', 'a', 'e', 'l', 's', 5, 'k', 'a', 'e', 'l', 't', 5, 'k', 'a', 'e', 'l', 'p', 5, 'k', 'a', 'e', 'l', 'h', 4, 'k', 'a', 'e', 'm', 4, 'k', 'a', 'e', 'b', 5, 'k', 'a', 'e', 'b', 's', 4, 'k', 'a', 'e', 's', 5, 'k', 'a', 'e', 's', 's', 5, 'k', 'a', 'e', 'n', 'g', 4, 'k', 'a', 'e', 'j', 4, 'k', 'a', 'e', 'c', 4, 'k', 'a', 'e', 'k', 4, 'k', 'a', 'e', 't', 4, 'k', 'a', 'e', 'p', 4, 'k', 'a', 'e', 'h', 3, 'k', 'y', 'a', 4, 'k', 'y', 'a', 'g', 5, 'k', 'y', 'a', 'g', 'g', 5, 'k', 'y', 'a', 'g', 's', 4, 'k', 'y', 'a', 'n', 5, 'k', 'y', 'a', 'n', 'j', 5, 'k', 'y', 'a', 'n', 'h', 4, 'k', 'y', 'a', 'd', 4, 'k', 'y', 'a', 'l', 5, 'k', 'y', 'a', 'l', 'g', 5, 'k', 'y', 'a', 'l', 'm', 5, 'k', 'y', 'a', 'l', 'b', 5, 'k', 'y', 'a', 'l', 's', 5, 'k', 'y', 'a', 'l', 't', 5, 'k', 'y', 'a', 'l', 'p', 5, 'k', 'y', 'a', 'l', 'h', 4, 'k', 'y', 'a', 'm', 4, 'k', 'y', 'a', 'b', 5, 'k', 'y', 'a', 'b', 's', 4, 'k', 'y', 'a', 's', 5, 'k', 'y', 'a', 's', 's', 5, 'k', 'y', 'a', 'n', 'g', 4, 'k', 'y', 'a', 'j', 4, 'k', 'y', 'a', 'c', 4, 'k', 'y', 'a', 'k', 4, 'k', 'y', 'a', 't', 4, 'k', 'y', 'a', 'p', 4, 'k', 'y', 'a', 'h', 4, 'k', 'y', 'a', 'e', 5, 'k', 'y', 'a', 'e', 'g', 6, 'k', 'y', 'a', 'e', 'g', 'g', 6, 'k', 'y', 'a', 'e', 'g', 's', 5, 'k', 'y', 'a', 'e', 'n', 6, 'k', 'y', 'a', 'e', 'n', 'j', 6, 'k', 'y', 'a', 'e', 'n', 'h', 5, 'k', 'y', 'a', 'e', 'd', 5, 'k', 'y', 'a', 'e', 'l', 6, 'k', 'y', 'a', 'e', 'l', 'g', 6, 'k', 'y', 'a', 'e', 'l', 'm', 6, 'k', 'y', 'a', 'e', 'l', 'b', 6, 'k', 'y', 'a', 'e', 'l', 's', 6, 'k', 'y', 'a', 'e', 'l', 't', 6, 'k', 'y', 'a', 'e', 'l', 'p', 6, 'k', 'y', 'a', 'e', 'l', 'h', 5, 'k', 'y', 'a', 'e', 'm', 5, 'k', 'y', 'a', 'e', 'b', 6, 'k', 'y', 'a', 'e', 'b', 's', 5, 'k', 'y', 'a', 'e', 's', 6, 'k', 'y', 'a', 'e', 's', 's', 6, 'k', 'y', 'a', 'e', 'n', 'g', 5, 'k', 'y', 'a', 'e', 'j', 5, 'k', 'y', 'a', 'e', 'c', 5, 'k', 'y', 'a', 'e', 'k', 5, 'k', 'y', 'a', 'e', 't', 5, 'k', 'y', 'a', 'e', 'p', 5, 'k', 'y', 'a', 'e', 'h', 3, 'k', 'e', 'o', 4, 'k', 'e', 'o', 'g', 5, 'k', 'e', 'o', 'g', 'g', 5, 'k', 'e', 'o', 'g', 's', 4, 'k', 'e', 'o', 'n', 5, 'k', 'e', 'o', 'n', 'j', 5, 'k', 'e', 'o', 'n', 'h', 4, 'k', 'e', 'o', 'd', 4, 'k', 'e', 'o', 'l', 5, 'k', 'e', 'o', 'l', 'g', 5, 'k', 'e', 'o', 'l', 'm', 5, 'k', 'e', 'o', 'l', 'b', 5, 'k', 'e', 'o', 'l', 's', 5, 'k', 'e', 'o', 'l', 't', 5, 'k', 'e', 'o', 'l', 'p', 5, 'k', 'e', 'o', 'l', 'h', 4, 'k', 'e', 'o', 'm', 4, 'k', 'e', 'o', 'b', 5, 'k', 'e', 'o', 'b', 's', 4, 'k', 'e', 'o', 's', 5, 'k', 'e', 'o', 's', 's', 5, 'k', 'e', 'o', 'n', 'g', 4, 'k', 'e', 'o', 'j', 4, 'k', 'e', 'o', 'c', 4, 'k', 'e', 'o', 'k', 4, 'k', 'e', 'o', 't', 4, 'k', 'e', 'o', 'p', 4, 'k', 'e', 'o', 'h', 2, 'k', 'e', 3, 'k', 'e', 'g', 4, 'k', 'e', 'g', 'g', 4, 'k', 'e', 'g', 's', 3, 'k', 'e', 'n', 4, 'k', 'e', 'n', 'j', 4, 'k', 'e', 'n', 'h', 3, 'k', 'e', 'd', 3, 'k', 'e', 'l', 4, 'k', 'e', 'l', 'g', 4, 'k', 'e', 'l', 'm', 4, 'k', 'e', 'l', 'b', 4, 'k', 'e', 'l', 's', 4, 'k', 'e', 'l', 't', 4, 'k', 'e', 'l', 'p', 4, 'k', 'e', 'l', 'h', 3, 'k', 'e', 'm', 3, 'k', 'e', 'b', 4, 'k', 'e', 'b', 's', 3, 'k', 'e', 's', 4, 'k', 'e', 's', 's', 4, 'k', 'e', 'n', 'g', 3, 'k', 'e', 'j', 3, 'k', 'e', 'c', 3, 'k', 'e', 'k', 3, 'k', 'e', 't', 3, 'k', 'e', 'p', 3, 'k', 'e', 'h', 4, 'k', 'y', 'e', 'o', 5, 'k', 'y', 'e', 'o', 'g', 6, 'k', 'y', 'e', 'o', 'g', 'g', 6, 'k', 'y', 'e', 'o', 'g', 's', 5, 'k', 'y', 'e', 'o', 'n', 6, 'k', 'y', 'e', 'o', 'n', 'j', 6, 'k', 'y', 'e', 'o', 'n', 'h', 5, 'k', 'y', 'e', 'o', 'd', 5, 'k', 'y', 'e', 'o', 'l', 6, 'k', 'y', 'e', 'o', 'l', 'g', 6, 'k', 'y', 'e', 'o', 'l', 'm', 6, 'k', 'y', 'e', 'o', 'l', 'b', 6, 'k', 'y', 'e', 'o', 'l', 's', 6, 'k', 'y', 'e', 'o', 'l', 't', 6, 'k', 'y', 'e', 'o', 'l', 'p', 6, 'k', 'y', 'e', 'o', 'l', 'h', 5, 'k', 'y', 'e', 'o', 'm', 5, 'k', 'y', 'e', 'o', 'b', 6, 'k', 'y', 'e', 'o', 'b', 's', 5, 'k', 'y', 'e', 'o', 's', 6, 'k', 'y', 'e', 'o', 's', 's', 6, 'k', 'y', 'e', 'o', 'n', 'g', 5, 'k', 'y', 'e', 'o', 'j', 5, 'k', 'y', 'e', 'o', 'c', 5, 'k', 'y', 'e', 'o', 'k', 5, 'k', 'y', 'e', 'o', 't', 5, 'k', 'y', 'e', 'o', 'p', 5, 'k', 'y', 'e', 'o', 'h', 3, 'k', 'y', 'e', 4, 'k', 'y', 'e', 'g', 5, 'k', 'y', 'e', 'g', 'g', 5, 'k', 'y', 'e', 'g', 's', 4, 'k', 'y', 'e', 'n', 5, 'k', 'y', 'e', 'n', 'j', 5, 'k', 'y', 'e', 'n', 'h', 4, 'k', 'y', 'e', 'd', 4, 'k', 'y', 'e', 'l', 5, 'k', 'y', 'e', 'l', 'g', 5, 'k', 'y', 'e', 'l', 'm', 5, 'k', 'y', 'e', 'l', 'b', 5, 'k', 'y', 'e', 'l', 's', 5, 'k', 'y', 'e', 'l', 't', 5, 'k', 'y', 'e', 'l', 'p', 5, 'k', 'y', 'e', 'l', 'h', 4, 'k', 'y', 'e', 'm', 4, 'k', 'y', 'e', 'b', 5, 'k', 'y', 'e', 'b', 's', 4, 'k', 'y', 'e', 's', 5, 'k', 'y', 'e', 's', 's', 5, 'k', 'y', 'e', 'n', 'g', 4, 'k', 'y', 'e', 'j', 4, 'k', 'y', 'e', 'c', 4, 'k', 'y', 'e', 'k', 4, 'k', 'y', 'e', 't', 4, 'k', 'y', 'e', 'p', 4, 'k', 'y', 'e', 'h', 2, 'k', 'o', 3, 'k', 'o', 'g', 4, 'k', 'o', 'g', 'g', 4, 'k', 'o', 'g', 's', 3, 'k', 'o', 'n', 4, 'k', 'o', 'n', 'j', 4, 'k', 'o', 'n', 'h', 3, 'k', 'o', 'd', 3, 'k', 'o', 'l', 4, 'k', 'o', 'l', 'g', 4, 'k', 'o', 'l', 'm', 4, 'k', 'o', 'l', 'b', 4, 'k', 'o', 'l', 's', 4, 'k', 'o', 'l', 't', 4, 'k', 'o', 'l', 'p', 4, 'k', 'o', 'l', 'h', 3, 'k', 'o', 'm', 3, 'k', 'o', 'b', 4, 'k', 'o', 'b', 's', 3, 'k', 'o', 's', 4, 'k', 'o', 's', 's', 4, 'k', 'o', 'n', 'g', 3, 'k', 'o', 'j', 3, 'k', 'o', 'c', 3, 'k', 'o', 'k', 3, 'k', 'o', 't', 3, 'k', 'o', 'p', 3, 'k', 'o', 'h', 3, 'k', 'w', 'a', 4, 'k', 'w', 'a', 'g', 5, 'k', 'w', 'a', 'g', 'g', 5, 'k', 'w', 'a', 'g', 's', 4, 'k', 'w', 'a', 'n', 5, 'k', 'w', 'a', 'n', 'j', 5, 'k', 'w', 'a', 'n', 'h', 4, 'k', 'w', 'a', 'd', 4, 'k', 'w', 'a', 'l', 5, 'k', 'w', 'a', 'l', 'g', 5, 'k', 'w', 'a', 'l', 'm', 5, 'k', 'w', 'a', 'l', 'b', 5, 'k', 'w', 'a', 'l', 's', 5, 'k', 'w', 'a', 'l', 't', 5, 'k', 'w', 'a', 'l', 'p', 5, 'k', 'w', 'a', 'l', 'h', 4, 'k', 'w', 'a', 'm', 4, 'k', 'w', 'a', 'b', 5, 'k', 'w', 'a', 'b', 's', 4, 'k', 'w', 'a', 's', 5, 'k', 'w', 'a', 's', 's', 5, 'k', 'w', 'a', 'n', 'g', 4, 'k', 'w', 'a', 'j', 4, 'k', 'w', 'a', 'c', 4, 'k', 'w', 'a', 'k', 4, 'k', 'w', 'a', 't', 4, 'k', 'w', 'a', 'p', 4, 'k', 'w', 'a', 'h', 4, 'k', 'w', 'a', 'e', 5, 'k', 'w', 'a', 'e', 'g', 6, 'k', 'w', 'a', 'e', 'g', 'g', 6, 'k', 'w', 'a', 'e', 'g', 's', 5, 'k', 'w', 'a', 'e', 'n', 6, 'k', 'w', 'a', 'e', 'n', 'j', 6, 'k', 'w', 'a', 'e', 'n', 'h', 5, 'k', 'w', 'a', 'e', 'd', 5, 'k', 'w', 'a', 'e', 'l', 6, 'k', 'w', 'a', 'e', 'l', 'g', 6, 'k', 'w', 'a', 'e', 'l', 'm', 6, 'k', 'w', 'a', 'e', 'l', 'b', 6, 'k', 'w', 'a', 'e', 'l', 's', 6, 'k', 'w', 'a', 'e', 'l', 't', 6, 'k', 'w', 'a', 'e', 'l', 'p', 6, 'k', 'w', 'a', 'e', 'l', 'h', 5, 'k', 'w', 'a', 'e', 'm', 5, 'k', 'w', 'a', 'e', 'b', 6, 'k', 'w', 'a', 'e', 'b', 's', 5, 'k', 'w', 'a', 'e', 's', 6, 'k', 'w', 'a', 'e', 's', 's', 6, 'k', 'w', 'a', 'e', 'n', 'g', 5, 'k', 'w', 'a', 'e', 'j', 5, 'k', 'w', 'a', 'e', 'c', 5, 'k', 'w', 'a', 'e', 'k', 5, 'k', 'w', 'a', 'e', 't', 5, 'k', 'w', 'a', 'e', 'p', 5, 'k', 'w', 'a', 'e', 'h', 3, 'k', 'o', 'e', 4, 'k', 'o', 'e', 'g', 5, 'k', 'o', 'e', 'g', 'g', 5, 'k', 'o', 'e', 'g', 's', 4, 'k', 'o', 'e', 'n', 5, 'k', 'o', 'e', 'n', 'j', 5, 'k', 'o', 'e', 'n', 'h', 4, 'k', 'o', 'e', 'd', 4, 'k', 'o', 'e', 'l', 5, 'k', 'o', 'e', 'l', 'g', 5, 'k', 'o', 'e', 'l', 'm', 5, 'k', 'o', 'e', 'l', 'b', 5, 'k', 'o', 'e', 'l', 's', 5, 'k', 'o', 'e', 'l', 't', 5, 'k', 'o', 'e', 'l', 'p', 5, 'k', 'o', 'e', 'l', 'h', 4, 'k', 'o', 'e', 'm', 4, 'k', 'o', 'e', 'b', 5, 'k', 'o', 'e', 'b', 's', 4, 'k', 'o', 'e', 's', 5, 'k', 'o', 'e', 's', 's', 5, 'k', 'o', 'e', 'n', 'g', 4, 'k', 'o', 'e', 'j', 4, 'k', 'o', 'e', 'c', 4, 'k', 'o', 'e', 'k', 4, 'k', 'o', 'e', 't', 4, 'k', 'o', 'e', 'p', 4, 'k', 'o', 'e', 'h', 3, 'k', 'y', 'o', 4, 'k', 'y', 'o', 'g', 5, 'k', 'y', 'o', 'g', 'g', 5, 'k', 'y', 'o', 'g', 's', 4, 'k', 'y', 'o', 'n', 5, 'k', 'y', 'o', 'n', 'j', 5, 'k', 'y', 'o', 'n', 'h', 4, 'k', 'y', 'o', 'd', 4, 'k', 'y', 'o', 'l', 5, 'k', 'y', 'o', 'l', 'g', 5, 'k', 'y', 'o', 'l', 'm', 5, 'k', 'y', 'o', 'l', 'b', 5, 'k', 'y', 'o', 'l', 's', 5, 'k', 'y', 'o', 'l', 't', 5, 'k', 'y', 'o', 'l', 'p', 5, 'k', 'y', 'o', 'l', 'h', 4, 'k', 'y', 'o', 'm', 4, 'k', 'y', 'o', 'b', 5, 'k', 'y', 'o', 'b', 's', 4, 'k', 'y', 'o', 's', 5, 'k', 'y', 'o', 's', 's', 5, 'k', 'y', 'o', 'n', 'g', 4, 'k', 'y', 'o', 'j', 4, 'k', 'y', 'o', 'c', 4, 'k', 'y', 'o', 'k', 4, 'k', 'y', 'o', 't', 4, 'k', 'y', 'o', 'p', 4, 'k', 'y', 'o', 'h', 2, 'k', 'u', 3, 'k', 'u', 'g', 4, 'k', 'u', 'g', 'g', 4, 'k', 'u', 'g', 's', 3, 'k', 'u', 'n', 4, 'k', 'u', 'n', 'j', 4, 'k', 'u', 'n', 'h', 3, 'k', 'u', 'd', 3, 'k', 'u', 'l', 4, 'k', 'u', 'l', 'g', 4, 'k', 'u', 'l', 'm', 4, 'k', 'u', 'l', 'b', 4, 'k', 'u', 'l', 's', 4, 'k', 'u', 'l', 't', 4, 'k', 'u', 'l', 'p', 4, 'k', 'u', 'l', 'h', 3, 'k', 'u', 'm', 3, 'k', 'u', 'b', 4, 'k', 'u', 'b', 's', 3, 'k', 'u', 's', 4, 'k', 'u', 's', 's', 4, 'k', 'u', 'n', 'g', 3, 'k', 'u', 'j', 3, 'k', 'u', 'c', 3, 'k', 'u', 'k', 3, 'k', 'u', 't', 3, 'k', 'u', 'p', 3, 'k', 'u', 'h', 4, 'k', 'w', 'e', 'o', 5, 'k', 'w', 'e', 'o', 'g', 6, 'k', 'w', 'e', 'o', 'g', 'g', 6, 'k', 'w', 'e', 'o', 'g', 's', 5, 'k', 'w', 'e', 'o', 'n', 6, 'k', 'w', 'e', 'o', 'n', 'j', 6, 'k', 'w', 'e', 'o', 'n', 'h', 5, 'k', 'w', 'e', 'o', 'd', 5, 'k', 'w', 'e', 'o', 'l', 6, 'k', 'w', 'e', 'o', 'l', 'g', 6, 'k', 'w', 'e', 'o', 'l', 'm', 6, 'k', 'w', 'e', 'o', 'l', 'b', 6, 'k', 'w', 'e', 'o', 'l', 's', 6, 'k', 'w', 'e', 'o', 'l', 't', 6, 'k', 'w', 'e', 'o', 'l', 'p', 6, 'k', 'w', 'e', 'o', 'l', 'h', 5, 'k', 'w', 'e', 'o', 'm', 5, 'k', 'w', 'e', 'o', 'b', 6, 'k', 'w', 'e', 'o', 'b', 's', 5, 'k', 'w', 'e', 'o', 's', 6, 'k', 'w', 'e', 'o', 's', 's', 6, 'k', 'w', 'e', 'o', 'n', 'g', 5, 'k', 'w', 'e', 'o', 'j', 5, 'k', 'w', 'e', 'o', 'c', 5, 'k', 'w', 'e', 'o', 'k', 5, 'k', 'w', 'e', 'o', 't', 5, 'k', 'w', 'e', 'o', 'p', 5, 'k', 'w', 'e', 'o', 'h', 3, 'k', 'w', 'e', 4, 'k', 'w', 'e', 'g', 5, 'k', 'w', 'e', 'g', 'g', 5, 'k', 'w', 'e', 'g', 's', 4, 'k', 'w', 'e', 'n', 5, 'k', 'w', 'e', 'n', 'j', 5, 'k', 'w', 'e', 'n', 'h', 4, 'k', 'w', 'e', 'd', 4, 'k', 'w', 'e', 'l', 5, 'k', 'w', 'e', 'l', 'g', 5, 'k', 'w', 'e', 'l', 'm', 5, 'k', 'w', 'e', 'l', 'b', 5, 'k', 'w', 'e', 'l', 's', 5, 'k', 'w', 'e', 'l', 't', 5, 'k', 'w', 'e', 'l', 'p', 5, 'k', 'w', 'e', 'l', 'h', 4, 'k', 'w', 'e', 'm', 4, 'k', 'w', 'e', 'b', 5, 'k', 'w', 'e', 'b', 's', 4, 'k', 'w', 'e', 's', 5, 'k', 'w', 'e', 's', 's', 5, 'k', 'w', 'e', 'n', 'g', 4, 'k', 'w', 'e', 'j', 4, 'k', 'w', 'e', 'c', 4, 'k', 'w', 'e', 'k', 4, 'k', 'w', 'e', 't', 4, 'k', 'w', 'e', 'p', 4, 'k', 'w', 'e', 'h', 3, 'k', 'w', 'i', 4, 'k', 'w', 'i', 'g', 5, 'k', 'w', 'i', 'g', 'g', 5, 'k', 'w', 'i', 'g', 's', 4, 'k', 'w', 'i', 'n', 5, 'k', 'w', 'i', 'n', 'j', 5, 'k', 'w', 'i', 'n', 'h', 4, 'k', 'w', 'i', 'd', 4, 'k', 'w', 'i', 'l', 5, 'k', 'w', 'i', 'l', 'g', 5, 'k', 'w', 'i', 'l', 'm', 5, 'k', 'w', 'i', 'l', 'b', 5, 'k', 'w', 'i', 'l', 's', 5, 'k', 'w', 'i', 'l', 't', 5, 'k', 'w', 'i', 'l', 'p', 5, 'k', 'w', 'i', 'l', 'h', 4, 'k', 'w', 'i', 'm', 4, 'k', 'w', 'i', 'b', 5, 'k', 'w', 'i', 'b', 's', 4, 'k', 'w', 'i', 's', 5, 'k', 'w', 'i', 's', 's', 5, 'k', 'w', 'i', 'n', 'g', 4, 'k', 'w', 'i', 'j', 4, 'k', 'w', 'i', 'c', 4, 'k', 'w', 'i', 'k', 4, 'k', 'w', 'i', 't', 4, 'k', 'w', 'i', 'p', 4, 'k', 'w', 'i', 'h', 3, 'k', 'y', 'u', 4, 'k', 'y', 'u', 'g', 5, 'k', 'y', 'u', 'g', 'g', 5, 'k', 'y', 'u', 'g', 's', 4, 'k', 'y', 'u', 'n', 5, 'k', 'y', 'u', 'n', 'j', 5, 'k', 'y', 'u', 'n', 'h', 4, 'k', 'y', 'u', 'd', 4, 'k', 'y', 'u', 'l', 5, 'k', 'y', 'u', 'l', 'g', 5, 'k', 'y', 'u', 'l', 'm', 5, 'k', 'y', 'u', 'l', 'b', 5, 'k', 'y', 'u', 'l', 's', 5, 'k', 'y', 'u', 'l', 't', 5, 'k', 'y', 'u', 'l', 'p', 5, 'k', 'y', 'u', 'l', 'h', 4, 'k', 'y', 'u', 'm', 4, 'k', 'y', 'u', 'b', 5, 'k', 'y', 'u', 'b', 's', 4, 'k', 'y', 'u', 's', 5, 'k', 'y', 'u', 's', 's', 5, 'k', 'y', 'u', 'n', 'g', 4, 'k', 'y', 'u', 'j', 4, 'k', 'y', 'u', 'c', 4, 'k', 'y', 'u', 'k', 4, 'k', 'y', 'u', 't', 4, 'k', 'y', 'u', 'p', 4, 'k', 'y', 'u', 'h', 3, 'k', 'e', 'u', 4, 'k', 'e', 'u', 'g', 5, 'k', 'e', 'u', 'g', 'g', 5, 'k', 'e', 'u', 'g', 's', 4, 'k', 'e', 'u', 'n', 5, 'k', 'e', 'u', 'n', 'j', 5, 'k', 'e', 'u', 'n', 'h', 4, 'k', 'e', 'u', 'd', 4, 'k', 'e', 'u', 'l', 5, 'k', 'e', 'u', 'l', 'g', 5, 'k', 'e', 'u', 'l', 'm', 5, 'k', 'e', 'u', 'l', 'b', 5, 'k', 'e', 'u', 'l', 's', 5, 'k', 'e', 'u', 'l', 't', 5, 'k', 'e', 'u', 'l', 'p', 5, 'k', 'e', 'u', 'l', 'h', 4, 'k', 'e', 'u', 'm', 4, 'k', 'e', 'u', 'b', 5, 'k', 'e', 'u', 'b', 's', 4, 'k', 'e', 'u', 's', 5, 'k', 'e', 'u', 's', 's', 5, 'k', 'e', 'u', 'n', 'g', 4, 'k', 'e', 'u', 'j', 4, 'k', 'e', 'u', 'c', 4, 'k', 'e', 'u', 'k', 4, 'k', 'e', 'u', 't', 4, 'k', 'e', 'u', 'p', 4, 'k', 'e', 'u', 'h', 3, 'k', 'y', 'i', 4, 'k', 'y', 'i', 'g', 5, 'k', 'y', 'i', 'g', 'g', 5, 'k', 'y', 'i', 'g', 's', 4, 'k', 'y', 'i', 'n', 5, 'k', 'y', 'i', 'n', 'j', 5, 'k', 'y', 'i', 'n', 'h', 4, 'k', 'y', 'i', 'd', 4, 'k', 'y', 'i', 'l', 5, 'k', 'y', 'i', 'l', 'g', 5, 'k', 'y', 'i', 'l', 'm', 5, 'k', 'y', 'i', 'l', 'b', 5, 'k', 'y', 'i', 'l', 's', 5, 'k', 'y', 'i', 'l', 't', 5, 'k', 'y', 'i', 'l', 'p', 5, 'k', 'y', 'i', 'l', 'h', 4, 'k', 'y', 'i', 'm', 4, 'k', 'y', 'i', 'b', 5, 'k', 'y', 'i', 'b', 's', 4, 'k', 'y', 'i', 's', 5, 'k', 'y', 'i', 's', 's', 5, 'k', 'y', 'i', 'n', 'g', 4, 'k', 'y', 'i', 'j', 4, 'k', 'y', 'i', 'c', 4, 'k', 'y', 'i', 'k', 4, 'k', 'y', 'i', 't', 4, 'k', 'y', 'i', 'p', 4, 'k', 'y', 'i', 'h', 2, 'k', 'i', 3, 'k', 'i', 'g', 4, 'k', 'i', 'g', 'g', 4, 'k', 'i', 'g', 's', 3, 'k', 'i', 'n', 4, 'k', 'i', 'n', 'j', 4, 'k', 'i', 'n', 'h', 3, 'k', 'i', 'd', 3, 'k', 'i', 'l', 4, 'k', 'i', 'l', 'g', 4, 'k', 'i', 'l', 'm', 4, 'k', 'i', 'l', 'b', 4, 'k', 'i', 'l', 's', 4, 'k', 'i', 'l', 't', 4, 'k', 'i', 'l', 'p', 4, 'k', 'i', 'l', 'h', 3, 'k', 'i', 'm', 3, 'k', 'i', 'b', 4, 'k', 'i', 'b', 's', 3, 'k', 'i', 's', 4, 'k', 'i', 's', 's', 4, 'k', 'i', 'n', 'g', 3, 'k', 'i', 'j', 3, 'k', 'i', 'c', 3, 'k', 'i', 'k', 3, 'k', 'i', 't', 3, 'k', 'i', 'p', 3, 'k', 'i', 'h', 2, 't', 'a', 3, 't', 'a', 'g', 4, 't', 'a', 'g', 'g', 4, 't', 'a', 'g', 's', 3, 't', 'a', 'n', 4, 't', 'a', 'n', 'j', 4, 't', 'a', 'n', 'h', 3, 't', 'a', 'd', 3, 't', 'a', 'l', 4, 't', 'a', 'l', 'g', 4, 't', 'a', 'l', 'm', 4, 't', 'a', 'l', 'b', 4, 't', 'a', 'l', 's', 4, 't', 'a', 'l', 't', 4, 't', 'a', 'l', 'p', 4, 't', 'a', 'l', 'h', 3, 't', 'a', 'm', 3, 't', 'a', 'b', 4, 't', 'a', 'b', 's', 3, 't', 'a', 's', 4, 't', 'a', 's', 's', 4, 't', 'a', 'n', 'g', 3, 't', 'a', 'j', 3, 't', 'a', 'c', 3, 't', 'a', 'k', 3, 't', 'a', 't', 3, 't', 'a', 'p', 3, 't', 'a', 'h', 3, 't', 'a', 'e', 4, 't', 'a', 'e', 'g', 5, 't', 'a', 'e', 'g', 'g', 5, 't', 'a', 'e', 'g', 's', 4, 't', 'a', 'e', 'n', 5, 't', 'a', 'e', 'n', 'j', 5, 't', 'a', 'e', 'n', 'h', 4, 't', 'a', 'e', 'd', 4, 't', 'a', 'e', 'l', 5, 't', 'a', 'e', 'l', 'g', 5, 't', 'a', 'e', 'l', 'm', 5, 't', 'a', 'e', 'l', 'b', 5, 't', 'a', 'e', 'l', 's', 5, 't', 'a', 'e', 'l', 't', 5, 't', 'a', 'e', 'l', 'p', 5, 't', 'a', 'e', 'l', 'h', 4, 't', 'a', 'e', 'm', 4, 't', 'a', 'e', 'b', 5, 't', 'a', 'e', 'b', 's', 4, 't', 'a', 'e', 's', 5, 't', 'a', 'e', 's', 's', 5, 't', 'a', 'e', 'n', 'g', 4, 't', 'a', 'e', 'j', 4, 't', 'a', 'e', 'c', 4, 't', 'a', 'e', 'k', 4, 't', 'a', 'e', 't', 4, 't', 'a', 'e', 'p', 4, 't', 'a', 'e', 'h', 3, 't', 'y', 'a', 4, 't', 'y', 'a', 'g', 5, 't', 'y', 'a', 'g', 'g', 5, 't', 'y', 'a', 'g', 's', 4, 't', 'y', 'a', 'n', 5, 't', 'y', 'a', 'n', 'j', 5, 't', 'y', 'a', 'n', 'h', 4, 't', 'y', 'a', 'd', 4, 't', 'y', 'a', 'l', 5, 't', 'y', 'a', 'l', 'g', 5, 't', 'y', 'a', 'l', 'm', 5, 't', 'y', 'a', 'l', 'b', 5, 't', 'y', 'a', 'l', 's', 5, 't', 'y', 'a', 'l', 't', 5, 't', 'y', 'a', 'l', 'p', 5, 't', 'y', 'a', 'l', 'h', 4, 't', 'y', 'a', 'm', 4, 't', 'y', 'a', 'b', 5, 't', 'y', 'a', 'b', 's', 4, 't', 'y', 'a', 's', 5, 't', 'y', 'a', 's', 's', 5, 't', 'y', 'a', 'n', 'g', 4, 't', 'y', 'a', 'j', 4, 't', 'y', 'a', 'c', 4, 't', 'y', 'a', 'k', 4, 't', 'y', 'a', 't', 4, 't', 'y', 'a', 'p', 4, 't', 'y', 'a', 'h', 4, 't', 'y', 'a', 'e', 5, 't', 'y', 'a', 'e', 'g', 6, 't', 'y', 'a', 'e', 'g', 'g', 6, 't', 'y', 'a', 'e', 'g', 's', 5, 't', 'y', 'a', 'e', 'n', 6, 't', 'y', 'a', 'e', 'n', 'j', 6, 't', 'y', 'a', 'e', 'n', 'h', 5, 't', 'y', 'a', 'e', 'd', 5, 't', 'y', 'a', 'e', 'l', 6, 't', 'y', 'a', 'e', 'l', 'g', 6, 't', 'y', 'a', 'e', 'l', 'm', 6, 't', 'y', 'a', 'e', 'l', 'b', 6, 't', 'y', 'a', 'e', 'l', 's', 6, 't', 'y', 'a', 'e', 'l', 't', 6, 't', 'y', 'a', 'e', 'l', 'p', 6, 't', 'y', 'a', 'e', 'l', 'h', 5, 't', 'y', 'a', 'e', 'm', 5, 't', 'y', 'a', 'e', 'b', 6, 't', 'y', 'a', 'e', 'b', 's', 5, 't', 'y', 'a', 'e', 's', 6, 't', 'y', 'a', 'e', 's', 's', 6, 't', 'y', 'a', 'e', 'n', 'g', 5, 't', 'y', 'a', 'e', 'j', 5, 't', 'y', 'a', 'e', 'c', 5, 't', 'y', 'a', 'e', 'k', 5, 't', 'y', 'a', 'e', 't', 5, 't', 'y', 'a', 'e', 'p', 5, 't', 'y', 'a', 'e', 'h', 3, 't', 'e', 'o', 4, 't', 'e', 'o', 'g', 5, 't', 'e', 'o', 'g', 'g', 5, 't', 'e', 'o', 'g', 's', 4, 't', 'e', 'o', 'n', 5, 't', 'e', 'o', 'n', 'j', 5, 't', 'e', 'o', 'n', 'h', 4, 't', 'e', 'o', 'd', 4, 't', 'e', 'o', 'l', 5, 't', 'e', 'o', 'l', 'g', 5, 't', 'e', 'o', 'l', 'm', 5, 't', 'e', 'o', 'l', 'b', 5, 't', 'e', 'o', 'l', 's', 5, 't', 'e', 'o', 'l', 't', 5, 't', 'e', 'o', 'l', 'p', 5, 't', 'e', 'o', 'l', 'h', 4, 't', 'e', 'o', 'm', 4, 't', 'e', 'o', 'b', 5, 't', 'e', 'o', 'b', 's', 4, 't', 'e', 'o', 's', 5, 't', 'e', 'o', 's', 's', 5, 't', 'e', 'o', 'n', 'g', 4, 't', 'e', 'o', 'j', 4, 't', 'e', 'o', 'c', 4, 't', 'e', 'o', 'k', 4, 't', 'e', 'o', 't', 4, 't', 'e', 'o', 'p', 4, 't', 'e', 'o', 'h', 2, 't', 'e', 3, 't', 'e', 'g', 4, 't', 'e', 'g', 'g', 4, 't', 'e', 'g', 's', 3, 't', 'e', 'n', 4, 't', 'e', 'n', 'j', 4, 't', 'e', 'n', 'h', 3, 't', 'e', 'd', 3, 't', 'e', 'l', 4, 't', 'e', 'l', 'g', 4, 't', 'e', 'l', 'm', 4, 't', 'e', 'l', 'b', 4, 't', 'e', 'l', 's', 4, 't', 'e', 'l', 't', 4, 't', 'e', 'l', 'p', 4, 't', 'e', 'l', 'h', 3, 't', 'e', 'm', 3, 't', 'e', 'b', 4, 't', 'e', 'b', 's', 3, 't', 'e', 's', 4, 't', 'e', 's', 's', 4, 't', 'e', 'n', 'g', 3, 't', 'e', 'j', 3, 't', 'e', 'c', 3, 't', 'e', 'k', 3, 't', 'e', 't', 3, 't', 'e', 'p', 3, 't', 'e', 'h', 4, 't', 'y', 'e', 'o', 5, 't', 'y', 'e', 'o', 'g', 6, 't', 'y', 'e', 'o', 'g', 'g', 6, 't', 'y', 'e', 'o', 'g', 's', 5, 't', 'y', 'e', 'o', 'n', 6, 't', 'y', 'e', 'o', 'n', 'j', 6, 't', 'y', 'e', 'o', 'n', 'h', 5, 't', 'y', 'e', 'o', 'd', 5, 't', 'y', 'e', 'o', 'l', 6, 't', 'y', 'e', 'o', 'l', 'g', 6, 't', 'y', 'e', 'o', 'l', 'm', 6, 't', 'y', 'e', 'o', 'l', 'b', 6, 't', 'y', 'e', 'o', 'l', 's', 6, 't', 'y', 'e', 'o', 'l', 't', 6, 't', 'y', 'e', 'o', 'l', 'p', 6, 't', 'y', 'e', 'o', 'l', 'h', 5, 't', 'y', 'e', 'o', 'm', 5, 't', 'y', 'e', 'o', 'b', 6, 't', 'y', 'e', 'o', 'b', 's', 5, 't', 'y', 'e', 'o', 's', 6, 't', 'y', 'e', 'o', 's', 's', 6, 't', 'y', 'e', 'o', 'n', 'g', 5, 't', 'y', 'e', 'o', 'j', 5, 't', 'y', 'e', 'o', 'c', 5, 't', 'y', 'e', 'o', 'k', 5, 't', 'y', 'e', 'o', 't', 5, 't', 'y', 'e', 'o', 'p', 5, 't', 'y', 'e', 'o', 'h', 3, 't', 'y', 'e', 4, 't', 'y', 'e', 'g', 5, 't', 'y', 'e', 'g', 'g', 5, 't', 'y', 'e', 'g', 's', 4, 't', 'y', 'e', 'n', 5, 't', 'y', 'e', 'n', 'j', 5, 't', 'y', 'e', 'n', 'h', 4, 't', 'y', 'e', 'd', 4, 't', 'y', 'e', 'l', 5, 't', 'y', 'e', 'l', 'g', 5, 't', 'y', 'e', 'l', 'm', 5, 't', 'y', 'e', 'l', 'b', 5, 't', 'y', 'e', 'l', 's', 5, 't', 'y', 'e', 'l', 't', 5, 't', 'y', 'e', 'l', 'p', 5, 't', 'y', 'e', 'l', 'h', 4, 't', 'y', 'e', 'm', 4, 't', 'y', 'e', 'b', 5, 't', 'y', 'e', 'b', 's', 4, 't', 'y', 'e', 's', 5, 't', 'y', 'e', 's', 's', 5, 't', 'y', 'e', 'n', 'g', 4, 't', 'y', 'e', 'j', 4, 't', 'y', 'e', 'c', 4, 't', 'y', 'e', 'k', 4, 't', 'y', 'e', 't', 4, 't', 'y', 'e', 'p', 4, 't', 'y', 'e', 'h', 2, 't', 'o', 3, 't', 'o', 'g', 4, 't', 'o', 'g', 'g', 4, 't', 'o', 'g', 's', 3, 't', 'o', 'n', 4, 't', 'o', 'n', 'j', 4, 't', 'o', 'n', 'h', 3, 't', 'o', 'd', 3, 't', 'o', 'l', 4, 't', 'o', 'l', 'g', 4, 't', 'o', 'l', 'm', 4, 't', 'o', 'l', 'b', 4, 't', 'o', 'l', 's', 4, 't', 'o', 'l', 't', 4, 't', 'o', 'l', 'p', 4, 't', 'o', 'l', 'h', 3, 't', 'o', 'm', 3, 't', 'o', 'b', 4, 't', 'o', 'b', 's', 3, 't', 'o', 's', 4, 't', 'o', 's', 's', 4, 't', 'o', 'n', 'g', 3, 't', 'o', 'j', 3, 't', 'o', 'c', 3, 't', 'o', 'k', 3, 't', 'o', 't', 3, 't', 'o', 'p', 3, 't', 'o', 'h', 3, 't', 'w', 'a', 4, 't', 'w', 'a', 'g', 5, 't', 'w', 'a', 'g', 'g', 5, 't', 'w', 'a', 'g', 's', 4, 't', 'w', 'a', 'n', 5, 't', 'w', 'a', 'n', 'j', 5, 't', 'w', 'a', 'n', 'h', 4, 't', 'w', 'a', 'd', 4, 't', 'w', 'a', 'l', 5, 't', 'w', 'a', 'l', 'g', 5, 't', 'w', 'a', 'l', 'm', 5, 't', 'w', 'a', 'l', 'b', 5, 't', 'w', 'a', 'l', 's', 5, 't', 'w', 'a', 'l', 't', 5, 't', 'w', 'a', 'l', 'p', 5, 't', 'w', 'a', 'l', 'h', 4, 't', 'w', 'a', 'm', 4, 't', 'w', 'a', 'b', 5, 't', 'w', 'a', 'b', 's', 4, 't', 'w', 'a', 's', 5, 't', 'w', 'a', 's', 's', 5, 't', 'w', 'a', 'n', 'g', 4, 't', 'w', 'a', 'j', 4, 't', 'w', 'a', 'c', 4, 't', 'w', 'a', 'k', 4, 't', 'w', 'a', 't', 4, 't', 'w', 'a', 'p', 4, 't', 'w', 'a', 'h', 4, 't', 'w', 'a', 'e', 5, 't', 'w', 'a', 'e', 'g', 6, 't', 'w', 'a', 'e', 'g', 'g', 6, 't', 'w', 'a', 'e', 'g', 's', 5, 't', 'w', 'a', 'e', 'n', 6, 't', 'w', 'a', 'e', 'n', 'j', 6, 't', 'w', 'a', 'e', 'n', 'h', 5, 't', 'w', 'a', 'e', 'd', 5, 't', 'w', 'a', 'e', 'l', 6, 't', 'w', 'a', 'e', 'l', 'g', 6, 't', 'w', 'a', 'e', 'l', 'm', 6, 't', 'w', 'a', 'e', 'l', 'b', 6, 't', 'w', 'a', 'e', 'l', 's', 6, 't', 'w', 'a', 'e', 'l', 't', 6, 't', 'w', 'a', 'e', 'l', 'p', 6, 't', 'w', 'a', 'e', 'l', 'h', 5, 't', 'w', 'a', 'e', 'm', 5, 't', 'w', 'a', 'e', 'b', 6, 't', 'w', 'a', 'e', 'b', 's', 5, 't', 'w', 'a', 'e', 's', 6, 't', 'w', 'a', 'e', 's', 's', 6, 't', 'w', 'a', 'e', 'n', 'g', 5, 't', 'w', 'a', 'e', 'j', 5, 't', 'w', 'a', 'e', 'c', 5, 't', 'w', 'a', 'e', 'k', 5, 't', 'w', 'a', 'e', 't', 5, 't', 'w', 'a', 'e', 'p', 5, 't', 'w', 'a', 'e', 'h', 3, 't', 'o', 'e', 4, 't', 'o', 'e', 'g', 5, 't', 'o', 'e', 'g', 'g', 5, 't', 'o', 'e', 'g', 's', 4, 't', 'o', 'e', 'n', 5, 't', 'o', 'e', 'n', 'j', 5, 't', 'o', 'e', 'n', 'h', 4, 't', 'o', 'e', 'd', 4, 't', 'o', 'e', 'l', 5, 't', 'o', 'e', 'l', 'g', 5, 't', 'o', 'e', 'l', 'm', 5, 't', 'o', 'e', 'l', 'b', 5, 't', 'o', 'e', 'l', 's', 5, 't', 'o', 'e', 'l', 't', 5, 't', 'o', 'e', 'l', 'p', 5, 't', 'o', 'e', 'l', 'h', 4, 't', 'o', 'e', 'm', 4, 't', 'o', 'e', 'b', 5, 't', 'o', 'e', 'b', 's', 4, 't', 'o', 'e', 's', 5, 't', 'o', 'e', 's', 's', 5, 't', 'o', 'e', 'n', 'g', 4, 't', 'o', 'e', 'j', 4, 't', 'o', 'e', 'c', 4, 't', 'o', 'e', 'k', 4, 't', 'o', 'e', 't', 4, 't', 'o', 'e', 'p', 4, 't', 'o', 'e', 'h', 3, 't', 'y', 'o', 4, 't', 'y', 'o', 'g', 5, 't', 'y', 'o', 'g', 'g', 5, 't', 'y', 'o', 'g', 's', 4, 't', 'y', 'o', 'n', 5, 't', 'y', 'o', 'n', 'j', 5, 't', 'y', 'o', 'n', 'h', 4, 't', 'y', 'o', 'd', 4, 't', 'y', 'o', 'l', 5, 't', 'y', 'o', 'l', 'g', 5, 't', 'y', 'o', 'l', 'm', 5, 't', 'y', 'o', 'l', 'b', 5, 't', 'y', 'o', 'l', 's', 5, 't', 'y', 'o', 'l', 't', 5, 't', 'y', 'o', 'l', 'p', 5, 't', 'y', 'o', 'l', 'h', 4, 't', 'y', 'o', 'm', 4, 't', 'y', 'o', 'b', 5, 't', 'y', 'o', 'b', 's', 4, 't', 'y', 'o', 's', 5, 't', 'y', 'o', 's', 's', 5, 't', 'y', 'o', 'n', 'g', 4, 't', 'y', 'o', 'j', 4, 't', 'y', 'o', 'c', 4, 't', 'y', 'o', 'k', 4, 't', 'y', 'o', 't', 4, 't', 'y', 'o', 'p', 4, 't', 'y', 'o', 'h', 2, 't', 'u', 3, 't', 'u', 'g', 4, 't', 'u', 'g', 'g', 4, 't', 'u', 'g', 's', 3, 't', 'u', 'n', 4, 't', 'u', 'n', 'j', 4, 't', 'u', 'n', 'h', 3, 't', 'u', 'd', 3, 't', 'u', 'l', 4, 't', 'u', 'l', 'g', 4, 't', 'u', 'l', 'm', 4, 't', 'u', 'l', 'b', 4, 't', 'u', 'l', 's', 4, 't', 'u', 'l', 't', 4, 't', 'u', 'l', 'p', 4, 't', 'u', 'l', 'h', 3, 't', 'u', 'm', 3, 't', 'u', 'b', 4, 't', 'u', 'b', 's', 3, 't', 'u', 's', 4, 't', 'u', 's', 's', 4, 't', 'u', 'n', 'g', 3, 't', 'u', 'j', 3, 't', 'u', 'c', 3, 't', 'u', 'k', 3, 't', 'u', 't', 3, 't', 'u', 'p', 3, 't', 'u', 'h', 4, 't', 'w', 'e', 'o', 5, 't', 'w', 'e', 'o', 'g', 6, 't', 'w', 'e', 'o', 'g', 'g', 6, 't', 'w', 'e', 'o', 'g', 's', 5, 't', 'w', 'e', 'o', 'n', 6, 't', 'w', 'e', 'o', 'n', 'j', 6, 't', 'w', 'e', 'o', 'n', 'h', 5, 't', 'w', 'e', 'o', 'd', 5, 't', 'w', 'e', 'o', 'l', 6, 't', 'w', 'e', 'o', 'l', 'g', 6, 't', 'w', 'e', 'o', 'l', 'm', 6, 't', 'w', 'e', 'o', 'l', 'b', 6, 't', 'w', 'e', 'o', 'l', 's', 6, 't', 'w', 'e', 'o', 'l', 't', 6, 't', 'w', 'e', 'o', 'l', 'p', 6, 't', 'w', 'e', 'o', 'l', 'h', 5, 't', 'w', 'e', 'o', 'm', 5, 't', 'w', 'e', 'o', 'b', 6, 't', 'w', 'e', 'o', 'b', 's', 5, 't', 'w', 'e', 'o', 's', 6, 't', 'w', 'e', 'o', 's', 's', 6, 't', 'w', 'e', 'o', 'n', 'g', 5, 't', 'w', 'e', 'o', 'j', 5, 't', 'w', 'e', 'o', 'c', 5, 't', 'w', 'e', 'o', 'k', 5, 't', 'w', 'e', 'o', 't', 5, 't', 'w', 'e', 'o', 'p', 5, 't', 'w', 'e', 'o', 'h', 3, 't', 'w', 'e', 4, 't', 'w', 'e', 'g', 5, 't', 'w', 'e', 'g', 'g', 5, 't', 'w', 'e', 'g', 's', 4, 't', 'w', 'e', 'n', 5, 't', 'w', 'e', 'n', 'j', 5, 't', 'w', 'e', 'n', 'h', 4, 't', 'w', 'e', 'd', 4, 't', 'w', 'e', 'l', 5, 't', 'w', 'e', 'l', 'g', 5, 't', 'w', 'e', 'l', 'm', 5, 't', 'w', 'e', 'l', 'b', 5, 't', 'w', 'e', 'l', 's', 5, 't', 'w', 'e', 'l', 't', 5, 't', 'w', 'e', 'l', 'p', 5, 't', 'w', 'e', 'l', 'h', 4, 't', 'w', 'e', 'm', 4, 't', 'w', 'e', 'b', 5, 't', 'w', 'e', 'b', 's', 4, 't', 'w', 'e', 's', 5, 't', 'w', 'e', 's', 's', 5, 't', 'w', 'e', 'n', 'g', 4, 't', 'w', 'e', 'j', 4, 't', 'w', 'e', 'c', 4, 't', 'w', 'e', 'k', 4, 't', 'w', 'e', 't', 4, 't', 'w', 'e', 'p', 4, 't', 'w', 'e', 'h', 3, 't', 'w', 'i', 4, 't', 'w', 'i', 'g', 5, 't', 'w', 'i', 'g', 'g', 5, 't', 'w', 'i', 'g', 's', 4, 't', 'w', 'i', 'n', 5, 't', 'w', 'i', 'n', 'j', 5, 't', 'w', 'i', 'n', 'h', 4, 't', 'w', 'i', 'd', 4, 't', 'w', 'i', 'l', 5, 't', 'w', 'i', 'l', 'g', 5, 't', 'w', 'i', 'l', 'm', 5, 't', 'w', 'i', 'l', 'b', 5, 't', 'w', 'i', 'l', 's', 5, 't', 'w', 'i', 'l', 't', 5, 't', 'w', 'i', 'l', 'p', 5, 't', 'w', 'i', 'l', 'h', 4, 't', 'w', 'i', 'm', 4, 't', 'w', 'i', 'b', 5, 't', 'w', 'i', 'b', 's', 4, 't', 'w', 'i', 's', 5, 't', 'w', 'i', 's', 's', 5, 't', 'w', 'i', 'n', 'g', 4, 't', 'w', 'i', 'j', 4, 't', 'w', 'i', 'c', 4, 't', 'w', 'i', 'k', 4, 't', 'w', 'i', 't', 4, 't', 'w', 'i', 'p', 4, 't', 'w', 'i', 'h', 3, 't', 'y', 'u', 4, 't', 'y', 'u', 'g', 5, 't', 'y', 'u', 'g', 'g', 5, 't', 'y', 'u', 'g', 's', 4, 't', 'y', 'u', 'n', 5, 't', 'y', 'u', 'n', 'j', 5, 't', 'y', 'u', 'n', 'h', 4, 't', 'y', 'u', 'd', 4, 't', 'y', 'u', 'l', 5, 't', 'y', 'u', 'l', 'g', 5, 't', 'y', 'u', 'l', 'm', 5, 't', 'y', 'u', 'l', 'b', 5, 't', 'y', 'u', 'l', 's', 5, 't', 'y', 'u', 'l', 't', 5, 't', 'y', 'u', 'l', 'p', 5, 't', 'y', 'u', 'l', 'h', 4, 't', 'y', 'u', 'm', 4, 't', 'y', 'u', 'b', 5, 't', 'y', 'u', 'b', 's', 4, 't', 'y', 'u', 's', 5, 't', 'y', 'u', 's', 's', 5, 't', 'y', 'u', 'n', 'g', 4, 't', 'y', 'u', 'j', 4, 't', 'y', 'u', 'c', 4, 't', 'y', 'u', 'k', 4, 't', 'y', 'u', 't', 4, 't', 'y', 'u', 'p', 4, 't', 'y', 'u', 'h', 3, 't', 'e', 'u', 4, 't', 'e', 'u', 'g', 5, 't', 'e', 'u', 'g', 'g', 5, 't', 'e', 'u', 'g', 's', 4, 't', 'e', 'u', 'n', 5, 't', 'e', 'u', 'n', 'j', 5, 't', 'e', 'u', 'n', 'h', 4, 't', 'e', 'u', 'd', 4, 't', 'e', 'u', 'l', 5, 't', 'e', 'u', 'l', 'g', 5, 't', 'e', 'u', 'l', 'm', 5, 't', 'e', 'u', 'l', 'b', 5, 't', 'e', 'u', 'l', 's', 5, 't', 'e', 'u', 'l', 't', 5, 't', 'e', 'u', 'l', 'p', 5, 't', 'e', 'u', 'l', 'h', 4, 't', 'e', 'u', 'm', 4, 't', 'e', 'u', 'b', 5, 't', 'e', 'u', 'b', 's', 4, 't', 'e', 'u', 's', 5, 't', 'e', 'u', 's', 's', 5, 't', 'e', 'u', 'n', 'g', 4, 't', 'e', 'u', 'j', 4, 't', 'e', 'u', 'c', 4, 't', 'e', 'u', 'k', 4, 't', 'e', 'u', 't', 4, 't', 'e', 'u', 'p', 4, 't', 'e', 'u', 'h', 3, 't', 'y', 'i', 4, 't', 'y', 'i', 'g', 5, 't', 'y', 'i', 'g', 'g', 5, 't', 'y', 'i', 'g', 's', 4, 't', 'y', 'i', 'n', 5, 't', 'y', 'i', 'n', 'j', 5, 't', 'y', 'i', 'n', 'h', 4, 't', 'y', 'i', 'd', 4, 't', 'y', 'i', 'l', 5, 't', 'y', 'i', 'l', 'g', 5, 't', 'y', 'i', 'l', 'm', 5, 't', 'y', 'i', 'l', 'b', 5, 't', 'y', 'i', 'l', 's', 5, 't', 'y', 'i', 'l', 't', 5, 't', 'y', 'i', 'l', 'p', 5, 't', 'y', 'i', 'l', 'h', 4, 't', 'y', 'i', 'm', 4, 't', 'y', 'i', 'b', 5, 't', 'y', 'i', 'b', 's', 4, 't', 'y', 'i', 's', 5, 't', 'y', 'i', 's', 's', 5, 't', 'y', 'i', 'n', 'g', 4, 't', 'y', 'i', 'j', 4, 't', 'y', 'i', 'c', 4, 't', 'y', 'i', 'k', 4, 't', 'y', 'i', 't', 4, 't', 'y', 'i', 'p', 4, 't', 'y', 'i', 'h', 2, 't', 'i', 3, 't', 'i', 'g', 4, 't', 'i', 'g', 'g', 4, 't', 'i', 'g', 's', 3, 't', 'i', 'n', 4, 't', 'i', 'n', 'j', 4, 't', 'i', 'n', 'h', 3, 't', 'i', 'd', 3, 't', 'i', 'l', 4, 't', 'i', 'l', 'g', 4, 't', 'i', 'l', 'm', 4, 't', 'i', 'l', 'b', 4, 't', 'i', 'l', 's', 4, 't', 'i', 'l', 't', 4, 't', 'i', 'l', 'p', 4, 't', 'i', 'l', 'h', 3, 't', 'i', 'm', 3, 't', 'i', 'b', 4, 't', 'i', 'b', 's', 3, 't', 'i', 's', 4, 't', 'i', 's', 's', 4, 't', 'i', 'n', 'g', 3, 't', 'i', 'j', 3, 't', 'i', 'c', 3, 't', 'i', 'k', 3, 't', 'i', 't', 3, 't', 'i', 'p', 3, 't', 'i', 'h', 2, 'p', 'a', 3, 'p', 'a', 'g', 4, 'p', 'a', 'g', 'g', 4, 'p', 'a', 'g', 's', 3, 'p', 'a', 'n', 4, 'p', 'a', 'n', 'j', 4, 'p', 'a', 'n', 'h', 3, 'p', 'a', 'd', 3, 'p', 'a', 'l', 4, 'p', 'a', 'l', 'g', 4, 'p', 'a', 'l', 'm', 4, 'p', 'a', 'l', 'b', 4, 'p', 'a', 'l', 's', 4, 'p', 'a', 'l', 't', 4, 'p', 'a', 'l', 'p', 4, 'p', 'a', 'l', 'h', 3, 'p', 'a', 'm', 3, 'p', 'a', 'b', 4, 'p', 'a', 'b', 's', 3, 'p', 'a', 's', 4, 'p', 'a', 's', 's', 4, 'p', 'a', 'n', 'g', 3, 'p', 'a', 'j', 3, 'p', 'a', 'c', 3, 'p', 'a', 'k', 3, 'p', 'a', 't', 3, 'p', 'a', 'p', 3, 'p', 'a', 'h', 3, 'p', 'a', 'e', 4, 'p', 'a', 'e', 'g', 5, 'p', 'a', 'e', 'g', 'g', 5, 'p', 'a', 'e', 'g', 's', 4, 'p', 'a', 'e', 'n', 5, 'p', 'a', 'e', 'n', 'j', 5, 'p', 'a', 'e', 'n', 'h', 4, 'p', 'a', 'e', 'd', 4, 'p', 'a', 'e', 'l', 5, 'p', 'a', 'e', 'l', 'g', 5, 'p', 'a', 'e', 'l', 'm', 5, 'p', 'a', 'e', 'l', 'b', 5, 'p', 'a', 'e', 'l', 's', 5, 'p', 'a', 'e', 'l', 't', 5, 'p', 'a', 'e', 'l', 'p', 5, 'p', 'a', 'e', 'l', 'h', 4, 'p', 'a', 'e', 'm', 4, 'p', 'a', 'e', 'b', 5, 'p', 'a', 'e', 'b', 's', 4, 'p', 'a', 'e', 's', 5, 'p', 'a', 'e', 's', 's', 5, 'p', 'a', 'e', 'n', 'g', 4, 'p', 'a', 'e', 'j', 4, 'p', 'a', 'e', 'c', 4, 'p', 'a', 'e', 'k', 4, 'p', 'a', 'e', 't', 4, 'p', 'a', 'e', 'p', 4, 'p', 'a', 'e', 'h', 3, 'p', 'y', 'a', 4, 'p', 'y', 'a', 'g', 5, 'p', 'y', 'a', 'g', 'g', 5, 'p', 'y', 'a', 'g', 's', 4, 'p', 'y', 'a', 'n', 5, 'p', 'y', 'a', 'n', 'j', 5, 'p', 'y', 'a', 'n', 'h', 4, 'p', 'y', 'a', 'd', 4, 'p', 'y', 'a', 'l', 5, 'p', 'y', 'a', 'l', 'g', 5, 'p', 'y', 'a', 'l', 'm', 5, 'p', 'y', 'a', 'l', 'b', 5, 'p', 'y', 'a', 'l', 's', 5, 'p', 'y', 'a', 'l', 't', 5, 'p', 'y', 'a', 'l', 'p', 5, 'p', 'y', 'a', 'l', 'h', 4, 'p', 'y', 'a', 'm', 4, 'p', 'y', 'a', 'b', 5, 'p', 'y', 'a', 'b', 's', 4, 'p', 'y', 'a', 's', 5, 'p', 'y', 'a', 's', 's', 5, 'p', 'y', 'a', 'n', 'g', 4, 'p', 'y', 'a', 'j', 4, 'p', 'y', 'a', 'c', 4, 'p', 'y', 'a', 'k', 4, 'p', 'y', 'a', 't', 4, 'p', 'y', 'a', 'p', 4, 'p', 'y', 'a', 'h', 4, 'p', 'y', 'a', 'e', 5, 'p', 'y', 'a', 'e', 'g', 6, 'p', 'y', 'a', 'e', 'g', 'g', 6, 'p', 'y', 'a', 'e', 'g', 's', 5, 'p', 'y', 'a', 'e', 'n', 6, 'p', 'y', 'a', 'e', 'n', 'j', 6, 'p', 'y', 'a', 'e', 'n', 'h', 5, 'p', 'y', 'a', 'e', 'd', 5, 'p', 'y', 'a', 'e', 'l', 6, 'p', 'y', 'a', 'e', 'l', 'g', 6, 'p', 'y', 'a', 'e', 'l', 'm', 6, 'p', 'y', 'a', 'e', 'l', 'b', 6, 'p', 'y', 'a', 'e', 'l', 's', 6, 'p', 'y', 'a', 'e', 'l', 't', 6, 'p', 'y', 'a', 'e', 'l', 'p', 6, 'p', 'y', 'a', 'e', 'l', 'h', 5, 'p', 'y', 'a', 'e', 'm', 5, 'p', 'y', 'a', 'e', 'b', 6, 'p', 'y', 'a', 'e', 'b', 's', 5, 'p', 'y', 'a', 'e', 's', 6, 'p', 'y', 'a', 'e', 's', 's', 6, 'p', 'y', 'a', 'e', 'n', 'g', 5, 'p', 'y', 'a', 'e', 'j', 5, 'p', 'y', 'a', 'e', 'c', 5, 'p', 'y', 'a', 'e', 'k', 5, 'p', 'y', 'a', 'e', 't', 5, 'p', 'y', 'a', 'e', 'p', 5, 'p', 'y', 'a', 'e', 'h', 3, 'p', 'e', 'o', 4, 'p', 'e', 'o', 'g', 5, 'p', 'e', 'o', 'g', 'g', 5, 'p', 'e', 'o', 'g', 's', 4, 'p', 'e', 'o', 'n', 5, 'p', 'e', 'o', 'n', 'j', 5, 'p', 'e', 'o', 'n', 'h', 4, 'p', 'e', 'o', 'd', 4, 'p', 'e', 'o', 'l', 5, 'p', 'e', 'o', 'l', 'g', 5, 'p', 'e', 'o', 'l', 'm', 5, 'p', 'e', 'o', 'l', 'b', 5, 'p', 'e', 'o', 'l', 's', 5, 'p', 'e', 'o', 'l', 't', 5, 'p', 'e', 'o', 'l', 'p', 5, 'p', 'e', 'o', 'l', 'h', 4, 'p', 'e', 'o', 'm', 4, 'p', 'e', 'o', 'b', 5, 'p', 'e', 'o', 'b', 's', 4, 'p', 'e', 'o', 's', 5, 'p', 'e', 'o', 's', 's', 5, 'p', 'e', 'o', 'n', 'g', 4, 'p', 'e', 'o', 'j', 4, 'p', 'e', 'o', 'c', 4, 'p', 'e', 'o', 'k', 4, 'p', 'e', 'o', 't', 4, 'p', 'e', 'o', 'p', 4, 'p', 'e', 'o', 'h', 2, 'p', 'e', 3, 'p', 'e', 'g', 4, 'p', 'e', 'g', 'g', 4, 'p', 'e', 'g', 's', 3, 'p', 'e', 'n', 4, 'p', 'e', 'n', 'j', 4, 'p', 'e', 'n', 'h', 3, 'p', 'e', 'd', 3, 'p', 'e', 'l', 4, 'p', 'e', 'l', 'g', 4, 'p', 'e', 'l', 'm', 4, 'p', 'e', 'l', 'b', 4, 'p', 'e', 'l', 's', 4, 'p', 'e', 'l', 't', 4, 'p', 'e', 'l', 'p', 4, 'p', 'e', 'l', 'h', 3, 'p', 'e', 'm', 3, 'p', 'e', 'b', 4, 'p', 'e', 'b', 's', 3, 'p', 'e', 's', 4, 'p', 'e', 's', 's', 4, 'p', 'e', 'n', 'g', 3, 'p', 'e', 'j', 3, 'p', 'e', 'c', 3, 'p', 'e', 'k', 3, 'p', 'e', 't', 3, 'p', 'e', 'p', 3, 'p', 'e', 'h', 4, 'p', 'y', 'e', 'o', 5, 'p', 'y', 'e', 'o', 'g', 6, 'p', 'y', 'e', 'o', 'g', 'g', 6, 'p', 'y', 'e', 'o', 'g', 's', 5, 'p', 'y', 'e', 'o', 'n', 6, 'p', 'y', 'e', 'o', 'n', 'j', 6, 'p', 'y', 'e', 'o', 'n', 'h', 5, 'p', 'y', 'e', 'o', 'd', 5, 'p', 'y', 'e', 'o', 'l', 6, 'p', 'y', 'e', 'o', 'l', 'g', 6, 'p', 'y', 'e', 'o', 'l', 'm', 6, 'p', 'y', 'e', 'o', 'l', 'b', 6, 'p', 'y', 'e', 'o', 'l', 's', 6, 'p', 'y', 'e', 'o', 'l', 't', 6, 'p', 'y', 'e', 'o', 'l', 'p', 6, 'p', 'y', 'e', 'o', 'l', 'h', 5, 'p', 'y', 'e', 'o', 'm', 5, 'p', 'y', 'e', 'o', 'b', 6, 'p', 'y', 'e', 'o', 'b', 's', 5, 'p', 'y', 'e', 'o', 's', 6, 'p', 'y', 'e', 'o', 's', 's', 6, 'p', 'y', 'e', 'o', 'n', 'g', 5, 'p', 'y', 'e', 'o', 'j', 5, 'p', 'y', 'e', 'o', 'c', 5, 'p', 'y', 'e', 'o', 'k', 5, 'p', 'y', 'e', 'o', 't', 5, 'p', 'y', 'e', 'o', 'p', 5, 'p', 'y', 'e', 'o', 'h', 3, 'p', 'y', 'e', 4, 'p', 'y', 'e', 'g', 5, 'p', 'y', 'e', 'g', 'g', 5, 'p', 'y', 'e', 'g', 's', 4, 'p', 'y', 'e', 'n', 5, 'p', 'y', 'e', 'n', 'j', 5, 'p', 'y', 'e', 'n', 'h', 4, 'p', 'y', 'e', 'd', 4, 'p', 'y', 'e', 'l', 5, 'p', 'y', 'e', 'l', 'g', 5, 'p', 'y', 'e', 'l', 'm', 5, 'p', 'y', 'e', 'l', 'b', 5, 'p', 'y', 'e', 'l', 's', 5, 'p', 'y', 'e', 'l', 't', 5, 'p', 'y', 'e', 'l', 'p', 5, 'p', 'y', 'e', 'l', 'h', 4, 'p', 'y', 'e', 'm', 4, 'p', 'y', 'e', 'b', 5, 'p', 'y', 'e', 'b', 's', 4, 'p', 'y', 'e', 's', 5, 'p', 'y', 'e', 's', 's', 5, 'p', 'y', 'e', 'n', 'g', 4, 'p', 'y', 'e', 'j', 4, 'p', 'y', 'e', 'c', 4, 'p', 'y', 'e', 'k', 4, 'p', 'y', 'e', 't', 4, 'p', 'y', 'e', 'p', 4, 'p', 'y', 'e', 'h', 2, 'p', 'o', 3, 'p', 'o', 'g', 4, 'p', 'o', 'g', 'g', 4, 'p', 'o', 'g', 's', 3, 'p', 'o', 'n', 4, 'p', 'o', 'n', 'j', 4, 'p', 'o', 'n', 'h', 3, 'p', 'o', 'd', 3, 'p', 'o', 'l', 4, 'p', 'o', 'l', 'g', 4, 'p', 'o', 'l', 'm', 4, 'p', 'o', 'l', 'b', 4, 'p', 'o', 'l', 's', 4, 'p', 'o', 'l', 't', 4, 'p', 'o', 'l', 'p', 4, 'p', 'o', 'l', 'h', 3, 'p', 'o', 'm', 3, 'p', 'o', 'b', 4, 'p', 'o', 'b', 's', 3, 'p', 'o', 's', 4, 'p', 'o', 's', 's', 4, 'p', 'o', 'n', 'g', 3, 'p', 'o', 'j', 3, 'p', 'o', 'c', 3, 'p', 'o', 'k', 3, 'p', 'o', 't', 3, 'p', 'o', 'p', 3, 'p', 'o', 'h', 3, 'p', 'w', 'a', 4, 'p', 'w', 'a', 'g', 5, 'p', 'w', 'a', 'g', 'g', 5, 'p', 'w', 'a', 'g', 's', 4, 'p', 'w', 'a', 'n', 5, 'p', 'w', 'a', 'n', 'j', 5, 'p', 'w', 'a', 'n', 'h', 4, 'p', 'w', 'a', 'd', 4, 'p', 'w', 'a', 'l', 5, 'p', 'w', 'a', 'l', 'g', 5, 'p', 'w', 'a', 'l', 'm', 5, 'p', 'w', 'a', 'l', 'b', 5, 'p', 'w', 'a', 'l', 's', 5, 'p', 'w', 'a', 'l', 't', 5, 'p', 'w', 'a', 'l', 'p', 5, 'p', 'w', 'a', 'l', 'h', 4, 'p', 'w', 'a', 'm', 4, 'p', 'w', 'a', 'b', 5, 'p', 'w', 'a', 'b', 's', 4, 'p', 'w', 'a', 's', 5, 'p', 'w', 'a', 's', 's', 5, 'p', 'w', 'a', 'n', 'g', 4, 'p', 'w', 'a', 'j', 4, 'p', 'w', 'a', 'c', 4, 'p', 'w', 'a', 'k', 4, 'p', 'w', 'a', 't', 4, 'p', 'w', 'a', 'p', 4, 'p', 'w', 'a', 'h', 4, 'p', 'w', 'a', 'e', 5, 'p', 'w', 'a', 'e', 'g', 6, 'p', 'w', 'a', 'e', 'g', 'g', 6, 'p', 'w', 'a', 'e', 'g', 's', 5, 'p', 'w', 'a', 'e', 'n', 6, 'p', 'w', 'a', 'e', 'n', 'j', 6, 'p', 'w', 'a', 'e', 'n', 'h', 5, 'p', 'w', 'a', 'e', 'd', 5, 'p', 'w', 'a', 'e', 'l', 6, 'p', 'w', 'a', 'e', 'l', 'g', 6, 'p', 'w', 'a', 'e', 'l', 'm', 6, 'p', 'w', 'a', 'e', 'l', 'b', 6, 'p', 'w', 'a', 'e', 'l', 's', 6, 'p', 'w', 'a', 'e', 'l', 't', 6, 'p', 'w', 'a', 'e', 'l', 'p', 6, 'p', 'w', 'a', 'e', 'l', 'h', 5, 'p', 'w', 'a', 'e', 'm', 5, 'p', 'w', 'a', 'e', 'b', 6, 'p', 'w', 'a', 'e', 'b', 's', 5, 'p', 'w', 'a', 'e', 's', 6, 'p', 'w', 'a', 'e', 's', 's', 6, 'p', 'w', 'a', 'e', 'n', 'g', 5, 'p', 'w', 'a', 'e', 'j', 5, 'p', 'w', 'a', 'e', 'c', 5, 'p', 'w', 'a', 'e', 'k', 5, 'p', 'w', 'a', 'e', 't', 5, 'p', 'w', 'a', 'e', 'p', 5, 'p', 'w', 'a', 'e', 'h', 3, 'p', 'o', 'e', 4, 'p', 'o', 'e', 'g', 5, 'p', 'o', 'e', 'g', 'g', 5, 'p', 'o', 'e', 'g', 's', 4, 'p', 'o', 'e', 'n', 5, 'p', 'o', 'e', 'n', 'j', 5, 'p', 'o', 'e', 'n', 'h', 4, 'p', 'o', 'e', 'd', 4, 'p', 'o', 'e', 'l', 5, 'p', 'o', 'e', 'l', 'g', 5, 'p', 'o', 'e', 'l', 'm', 5, 'p', 'o', 'e', 'l', 'b', 5, 'p', 'o', 'e', 'l', 's', 5, 'p', 'o', 'e', 'l', 't', 5, 'p', 'o', 'e', 'l', 'p', 5, 'p', 'o', 'e', 'l', 'h', 4, 'p', 'o', 'e', 'm', 4, 'p', 'o', 'e', 'b', 5, 'p', 'o', 'e', 'b', 's', 4, 'p', 'o', 'e', 's', 5, 'p', 'o', 'e', 's', 's', 5, 'p', 'o', 'e', 'n', 'g', 4, 'p', 'o', 'e', 'j', 4, 'p', 'o', 'e', 'c', 4, 'p', 'o', 'e', 'k', 4, 'p', 'o', 'e', 't', 4, 'p', 'o', 'e', 'p', 4, 'p', 'o', 'e', 'h', 3, 'p', 'y', 'o', 4, 'p', 'y', 'o', 'g', 5, 'p', 'y', 'o', 'g', 'g', 5, 'p', 'y', 'o', 'g', 's', 4, 'p', 'y', 'o', 'n', 5, 'p', 'y', 'o', 'n', 'j', 5, 'p', 'y', 'o', 'n', 'h', 4, 'p', 'y', 'o', 'd', 4, 'p', 'y', 'o', 'l', 5, 'p', 'y', 'o', 'l', 'g', 5, 'p', 'y', 'o', 'l', 'm', 5, 'p', 'y', 'o', 'l', 'b', 5, 'p', 'y', 'o', 'l', 's', 5, 'p', 'y', 'o', 'l', 't', 5, 'p', 'y', 'o', 'l', 'p', 5, 'p', 'y', 'o', 'l', 'h', 4, 'p', 'y', 'o', 'm', 4, 'p', 'y', 'o', 'b', 5, 'p', 'y', 'o', 'b', 's', 4, 'p', 'y', 'o', 's', 5, 'p', 'y', 'o', 's', 's', 5, 'p', 'y', 'o', 'n', 'g', 4, 'p', 'y', 'o', 'j', 4, 'p', 'y', 'o', 'c', 4, 'p', 'y', 'o', 'k', 4, 'p', 'y', 'o', 't', 4, 'p', 'y', 'o', 'p', 4, 'p', 'y', 'o', 'h', 2, 'p', 'u', 3, 'p', 'u', 'g', 4, 'p', 'u', 'g', 'g', 4, 'p', 'u', 'g', 's', 3, 'p', 'u', 'n', 4, 'p', 'u', 'n', 'j', 4, 'p', 'u', 'n', 'h', 3, 'p', 'u', 'd', 3, 'p', 'u', 'l', 4, 'p', 'u', 'l', 'g', 4, 'p', 'u', 'l', 'm', 4, 'p', 'u', 'l', 'b', 4, 'p', 'u', 'l', 's', 4, 'p', 'u', 'l', 't', 4, 'p', 'u', 'l', 'p', 4, 'p', 'u', 'l', 'h', 3, 'p', 'u', 'm', 3, 'p', 'u', 'b', 4, 'p', 'u', 'b', 's', 3, 'p', 'u', 's', 4, 'p', 'u', 's', 's', 4, 'p', 'u', 'n', 'g', 3, 'p', 'u', 'j', 3, 'p', 'u', 'c', 3, 'p', 'u', 'k', 3, 'p', 'u', 't', 3, 'p', 'u', 'p', 3, 'p', 'u', 'h', 4, 'p', 'w', 'e', 'o', 5, 'p', 'w', 'e', 'o', 'g', 6, 'p', 'w', 'e', 'o', 'g', 'g', 6, 'p', 'w', 'e', 'o', 'g', 's', 5, 'p', 'w', 'e', 'o', 'n', 6, 'p', 'w', 'e', 'o', 'n', 'j', 6, 'p', 'w', 'e', 'o', 'n', 'h', 5, 'p', 'w', 'e', 'o', 'd', 5, 'p', 'w', 'e', 'o', 'l', 6, 'p', 'w', 'e', 'o', 'l', 'g', 6, 'p', 'w', 'e', 'o', 'l', 'm', 6, 'p', 'w', 'e', 'o', 'l', 'b', 6, 'p', 'w', 'e', 'o', 'l', 's', 6, 'p', 'w', 'e', 'o', 'l', 't', 6, 'p', 'w', 'e', 'o', 'l', 'p', 6, 'p', 'w', 'e', 'o', 'l', 'h', 5, 'p', 'w', 'e', 'o', 'm', 5, 'p', 'w', 'e', 'o', 'b', 6, 'p', 'w', 'e', 'o', 'b', 's', 5, 'p', 'w', 'e', 'o', 's', 6, 'p', 'w', 'e', 'o', 's', 's', 6, 'p', 'w', 'e', 'o', 'n', 'g', 5, 'p', 'w', 'e', 'o', 'j', 5, 'p', 'w', 'e', 'o', 'c', 5, 'p', 'w', 'e', 'o', 'k', 5, 'p', 'w', 'e', 'o', 't', 5, 'p', 'w', 'e', 'o', 'p', 5, 'p', 'w', 'e', 'o', 'h', 3, 'p', 'w', 'e', 4, 'p', 'w', 'e', 'g', 5, 'p', 'w', 'e', 'g', 'g', 5, 'p', 'w', 'e', 'g', 's', 4, 'p', 'w', 'e', 'n', 5, 'p', 'w', 'e', 'n', 'j', 5, 'p', 'w', 'e', 'n', 'h', 4, 'p', 'w', 'e', 'd', 4, 'p', 'w', 'e', 'l', 5, 'p', 'w', 'e', 'l', 'g', 5, 'p', 'w', 'e', 'l', 'm', 5, 'p', 'w', 'e', 'l', 'b', 5, 'p', 'w', 'e', 'l', 's', 5, 'p', 'w', 'e', 'l', 't', 5, 'p', 'w', 'e', 'l', 'p', 5, 'p', 'w', 'e', 'l', 'h', 4, 'p', 'w', 'e', 'm', 4, 'p', 'w', 'e', 'b', 5, 'p', 'w', 'e', 'b', 's', 4, 'p', 'w', 'e', 's', 5, 'p', 'w', 'e', 's', 's', 5, 'p', 'w', 'e', 'n', 'g', 4, 'p', 'w', 'e', 'j', 4, 'p', 'w', 'e', 'c', 4, 'p', 'w', 'e', 'k', 4, 'p', 'w', 'e', 't', 4, 'p', 'w', 'e', 'p', 4, 'p', 'w', 'e', 'h', 3, 'p', 'w', 'i', 4, 'p', 'w', 'i', 'g', 5, 'p', 'w', 'i', 'g', 'g', 5, 'p', 'w', 'i', 'g', 's', 4, 'p', 'w', 'i', 'n', 5, 'p', 'w', 'i', 'n', 'j', 5, 'p', 'w', 'i', 'n', 'h', 4, 'p', 'w', 'i', 'd', 4, 'p', 'w', 'i', 'l', 5, 'p', 'w', 'i', 'l', 'g', 5, 'p', 'w', 'i', 'l', 'm', 5, 'p', 'w', 'i', 'l', 'b', 5, 'p', 'w', 'i', 'l', 's', 5, 'p', 'w', 'i', 'l', 't', 5, 'p', 'w', 'i', 'l', 'p', 5, 'p', 'w', 'i', 'l', 'h', 4, 'p', 'w', 'i', 'm', 4, 'p', 'w', 'i', 'b', 5, 'p', 'w', 'i', 'b', 's', 4, 'p', 'w', 'i', 's', 5, 'p', 'w', 'i', 's', 's', 5, 'p', 'w', 'i', 'n', 'g', 4, 'p', 'w', 'i', 'j', 4, 'p', 'w', 'i', 'c', 4, 'p', 'w', 'i', 'k', 4, 'p', 'w', 'i', 't', 4, 'p', 'w', 'i', 'p', 4, 'p', 'w', 'i', 'h', 3, 'p', 'y', 'u', 4, 'p', 'y', 'u', 'g', 5, 'p', 'y', 'u', 'g', 'g', 5, 'p', 'y', 'u', 'g', 's', 4, 'p', 'y', 'u', 'n', 5, 'p', 'y', 'u', 'n', 'j', 5, 'p', 'y', 'u', 'n', 'h', 4, 'p', 'y', 'u', 'd', 4, 'p', 'y', 'u', 'l', 5, 'p', 'y', 'u', 'l', 'g', 5, 'p', 'y', 'u', 'l', 'm', 5, 'p', 'y', 'u', 'l', 'b', 5, 'p', 'y', 'u', 'l', 's', 5, 'p', 'y', 'u', 'l', 't', 5, 'p', 'y', 'u', 'l', 'p', 5, 'p', 'y', 'u', 'l', 'h', 4, 'p', 'y', 'u', 'm', 4, 'p', 'y', 'u', 'b', 5, 'p', 'y', 'u', 'b', 's', 4, 'p', 'y', 'u', 's', 5, 'p', 'y', 'u', 's', 's', 5, 'p', 'y', 'u', 'n', 'g', 4, 'p', 'y', 'u', 'j', 4, 'p', 'y', 'u', 'c', 4, 'p', 'y', 'u', 'k', 4, 'p', 'y', 'u', 't', 4, 'p', 'y', 'u', 'p', 4, 'p', 'y', 'u', 'h', 3, 'p', 'e', 'u', 4, 'p', 'e', 'u', 'g', 5, 'p', 'e', 'u', 'g', 'g', 5, 'p', 'e', 'u', 'g', 's', 4, 'p', 'e', 'u', 'n', 5, 'p', 'e', 'u', 'n', 'j', 5, 'p', 'e', 'u', 'n', 'h', 4, 'p', 'e', 'u', 'd', 4, 'p', 'e', 'u', 'l', 5, 'p', 'e', 'u', 'l', 'g', 5, 'p', 'e', 'u', 'l', 'm', 5, 'p', 'e', 'u', 'l', 'b', 5, 'p', 'e', 'u', 'l', 's', 5, 'p', 'e', 'u', 'l', 't', 5, 'p', 'e', 'u', 'l', 'p', 5, 'p', 'e', 'u', 'l', 'h', 4, 'p', 'e', 'u', 'm', 4, 'p', 'e', 'u', 'b', 5, 'p', 'e', 'u', 'b', 's', 4, 'p', 'e', 'u', 's', 5, 'p', 'e', 'u', 's', 's', 5, 'p', 'e', 'u', 'n', 'g', 4, 'p', 'e', 'u', 'j', 4, 'p', 'e', 'u', 'c', 4, 'p', 'e', 'u', 'k', 4, 'p', 'e', 'u', 't', 4, 'p', 'e', 'u', 'p', 4, 'p', 'e', 'u', 'h', 3, 'p', 'y', 'i', 4, 'p', 'y', 'i', 'g', 5, 'p', 'y', 'i', 'g', 'g', 5, 'p', 'y', 'i', 'g', 's', 4, 'p', 'y', 'i', 'n', 5, 'p', 'y', 'i', 'n', 'j', 5, 'p', 'y', 'i', 'n', 'h', 4, 'p', 'y', 'i', 'd', 4, 'p', 'y', 'i', 'l', 5, 'p', 'y', 'i', 'l', 'g', 5, 'p', 'y', 'i', 'l', 'm', 5, 'p', 'y', 'i', 'l', 'b', 5, 'p', 'y', 'i', 'l', 's', 5, 'p', 'y', 'i', 'l', 't', 5, 'p', 'y', 'i', 'l', 'p', 5, 'p', 'y', 'i', 'l', 'h', 4, 'p', 'y', 'i', 'm', 4, 'p', 'y', 'i', 'b', 5, 'p', 'y', 'i', 'b', 's', 4, 'p', 'y', 'i', 's', 5, 'p', 'y', 'i', 's', 's', 5, 'p', 'y', 'i', 'n', 'g', 4, 'p', 'y', 'i', 'j', 4, 'p', 'y', 'i', 'c', 4, 'p', 'y', 'i', 'k', 4, 'p', 'y', 'i', 't', 4, 'p', 'y', 'i', 'p', 4, 'p', 'y', 'i', 'h', 2, 'p', 'i', 3, 'p', 'i', 'g', 4, 'p', 'i', 'g', 'g', 4, 'p', 'i', 'g', 's', 3, 'p', 'i', 'n', 4, 'p', 'i', 'n', 'j', 4, 'p', 'i', 'n', 'h', 3, 'p', 'i', 'd', 3, 'p', 'i', 'l', 4, 'p', 'i', 'l', 'g', 4, 'p', 'i', 'l', 'm', 4, 'p', 'i', 'l', 'b', 4, 'p', 'i', 'l', 's', 4, 'p', 'i', 'l', 't', 4, 'p', 'i', 'l', 'p', 4, 'p', 'i', 'l', 'h', 3, 'p', 'i', 'm', 3, 'p', 'i', 'b', 4, 'p', 'i', 'b', 's', 3, 'p', 'i', 's', 4, 'p', 'i', 's', 's', 4, 'p', 'i', 'n', 'g', 3, 'p', 'i', 'j', 3, 'p', 'i', 'c', 3, 'p', 'i', 'k', 3, 'p', 'i', 't', 3, 'p', 'i', 'p', 3, 'p', 'i', 'h', 2, 'h', 'a', 3, 'h', 'a', 'g', 4, 'h', 'a', 'g', 'g', 4, 'h', 'a', 'g', 's', 3, 'h', 'a', 'n', 4, 'h', 'a', 'n', 'j', 4, 'h', 'a', 'n', 'h', 3, 'h', 'a', 'd', 3, 'h', 'a', 'l', 4, 'h', 'a', 'l', 'g', 4, 'h', 'a', 'l', 'm', 4, 'h', 'a', 'l', 'b', 4, 'h', 'a', 'l', 's', 4, 'h', 'a', 'l', 't', 4, 'h', 'a', 'l', 'p', 4, 'h', 'a', 'l', 'h', 3, 'h', 'a', 'm', 3, 'h', 'a', 'b', 4, 'h', 'a', 'b', 's', 3, 'h', 'a', 's', 4, 'h', 'a', 's', 's', 4, 'h', 'a', 'n', 'g', 3, 'h', 'a', 'j', 3, 'h', 'a', 'c', 3, 'h', 'a', 'k', 3, 'h', 'a', 't', 3, 'h', 'a', 'p', 3, 'h', 'a', 'h', 3, 'h', 'a', 'e', 4, 'h', 'a', 'e', 'g', 5, 'h', 'a', 'e', 'g', 'g', 5, 'h', 'a', 'e', 'g', 's', 4, 'h', 'a', 'e', 'n', 5, 'h', 'a', 'e', 'n', 'j', 5, 'h', 'a', 'e', 'n', 'h', 4, 'h', 'a', 'e', 'd', 4, 'h', 'a', 'e', 'l', 5, 'h', 'a', 'e', 'l', 'g', 5, 'h', 'a', 'e', 'l', 'm', 5, 'h', 'a', 'e', 'l', 'b', 5, 'h', 'a', 'e', 'l', 's', 5, 'h', 'a', 'e', 'l', 't', 5, 'h', 'a', 'e', 'l', 'p', 5, 'h', 'a', 'e', 'l', 'h', 4, 'h', 'a', 'e', 'm', 4, 'h', 'a', 'e', 'b', 5, 'h', 'a', 'e', 'b', 's', 4, 'h', 'a', 'e', 's', 5, 'h', 'a', 'e', 's', 's', 5, 'h', 'a', 'e', 'n', 'g', 4, 'h', 'a', 'e', 'j', 4, 'h', 'a', 'e', 'c', 4, 'h', 'a', 'e', 'k', 4, 'h', 'a', 'e', 't', 4, 'h', 'a', 'e', 'p', 4, 'h', 'a', 'e', 'h', 3, 'h', 'y', 'a', 4, 'h', 'y', 'a', 'g', 5, 'h', 'y', 'a', 'g', 'g', 5, 'h', 'y', 'a', 'g', 's', 4, 'h', 'y', 'a', 'n', 5, 'h', 'y', 'a', 'n', 'j', 5, 'h', 'y', 'a', 'n', 'h', 4, 'h', 'y', 'a', 'd', 4, 'h', 'y', 'a', 'l', 5, 'h', 'y', 'a', 'l', 'g', 5, 'h', 'y', 'a', 'l', 'm', 5, 'h', 'y', 'a', 'l', 'b', 5, 'h', 'y', 'a', 'l', 's', 5, 'h', 'y', 'a', 'l', 't', 5, 'h', 'y', 'a', 'l', 'p', 5, 'h', 'y', 'a', 'l', 'h', 4, 'h', 'y', 'a', 'm', 4, 'h', 'y', 'a', 'b', 5, 'h', 'y', 'a', 'b', 's', 4, 'h', 'y', 'a', 's', 5, 'h', 'y', 'a', 's', 's', 5, 'h', 'y', 'a', 'n', 'g', 4, 'h', 'y', 'a', 'j', 4, 'h', 'y', 'a', 'c', 4, 'h', 'y', 'a', 'k', 4, 'h', 'y', 'a', 't', 4, 'h', 'y', 'a', 'p', 4, 'h', 'y', 'a', 'h', 4, 'h', 'y', 'a', 'e', 5, 'h', 'y', 'a', 'e', 'g', 6, 'h', 'y', 'a', 'e', 'g', 'g', 6, 'h', 'y', 'a', 'e', 'g', 's', 5, 'h', 'y', 'a', 'e', 'n', 6, 'h', 'y', 'a', 'e', 'n', 'j', 6, 'h', 'y', 'a', 'e', 'n', 'h', 5, 'h', 'y', 'a', 'e', 'd', 5, 'h', 'y', 'a', 'e', 'l', 6, 'h', 'y', 'a', 'e', 'l', 'g', 6, 'h', 'y', 'a', 'e', 'l', 'm', 6, 'h', 'y', 'a', 'e', 'l', 'b', 6, 'h', 'y', 'a', 'e', 'l', 's', 6, 'h', 'y', 'a', 'e', 'l', 't', 6, 'h', 'y', 'a', 'e', 'l', 'p', 6, 'h', 'y', 'a', 'e', 'l', 'h', 5, 'h', 'y', 'a', 'e', 'm', 5, 'h', 'y', 'a', 'e', 'b', 6, 'h', 'y', 'a', 'e', 'b', 's', 5, 'h', 'y', 'a', 'e', 's', 6, 'h', 'y', 'a', 'e', 's', 's', 6, 'h', 'y', 'a', 'e', 'n', 'g', 5, 'h', 'y', 'a', 'e', 'j', 5, 'h', 'y', 'a', 'e', 'c', 5, 'h', 'y', 'a', 'e', 'k', 5, 'h', 'y', 'a', 'e', 't', 5, 'h', 'y', 'a', 'e', 'p', 5, 'h', 'y', 'a', 'e', 'h', 3, 'h', 'e', 'o', 4, 'h', 'e', 'o', 'g', 5, 'h', 'e', 'o', 'g', 'g', 5, 'h', 'e', 'o', 'g', 's', 4, 'h', 'e', 'o', 'n', 5, 'h', 'e', 'o', 'n', 'j', 5, 'h', 'e', 'o', 'n', 'h', 4, 'h', 'e', 'o', 'd', 4, 'h', 'e', 'o', 'l', 5, 'h', 'e', 'o', 'l', 'g', 5, 'h', 'e', 'o', 'l', 'm', 5, 'h', 'e', 'o', 'l', 'b', 5, 'h', 'e', 'o', 'l', 's', 5, 'h', 'e', 'o', 'l', 't', 5, 'h', 'e', 'o', 'l', 'p', 5, 'h', 'e', 'o', 'l', 'h', 4, 'h', 'e', 'o', 'm', 4, 'h', 'e', 'o', 'b', 5, 'h', 'e', 'o', 'b', 's', 4, 'h', 'e', 'o', 's', 5, 'h', 'e', 'o', 's', 's', 5, 'h', 'e', 'o', 'n', 'g', 4, 'h', 'e', 'o', 'j', 4, 'h', 'e', 'o', 'c', 4, 'h', 'e', 'o', 'k', 4, 'h', 'e', 'o', 't', 4, 'h', 'e', 'o', 'p', 4, 'h', 'e', 'o', 'h', 2, 'h', 'e', 3, 'h', 'e', 'g', 4, 'h', 'e', 'g', 'g', 4, 'h', 'e', 'g', 's', 3, 'h', 'e', 'n', 4, 'h', 'e', 'n', 'j', 4, 'h', 'e', 'n', 'h', 3, 'h', 'e', 'd', 3, 'h', 'e', 'l', 4, 'h', 'e', 'l', 'g', 4, 'h', 'e', 'l', 'm', 4, 'h', 'e', 'l', 'b', 4, 'h', 'e', 'l', 's', 4, 'h', 'e', 'l', 't', 4, 'h', 'e', 'l', 'p', 4, 'h', 'e', 'l', 'h', 3, 'h', 'e', 'm', 3, 'h', 'e', 'b', 4, 'h', 'e', 'b', 's', 3, 'h', 'e', 's', 4, 'h', 'e', 's', 's', 4, 'h', 'e', 'n', 'g', 3, 'h', 'e', 'j', 3, 'h', 'e', 'c', 3, 'h', 'e', 'k', 3, 'h', 'e', 't', 3, 'h', 'e', 'p', 3, 'h', 'e', 'h', 4, 'h', 'y', 'e', 'o', 5, 'h', 'y', 'e', 'o', 'g', 6, 'h', 'y', 'e', 'o', 'g', 'g', 6, 'h', 'y', 'e', 'o', 'g', 's', 5, 'h', 'y', 'e', 'o', 'n', 6, 'h', 'y', 'e', 'o', 'n', 'j', 6, 'h', 'y', 'e', 'o', 'n', 'h', 5, 'h', 'y', 'e', 'o', 'd', 5, 'h', 'y', 'e', 'o', 'l', 6, 'h', 'y', 'e', 'o', 'l', 'g', 6, 'h', 'y', 'e', 'o', 'l', 'm', 6, 'h', 'y', 'e', 'o', 'l', 'b', 6, 'h', 'y', 'e', 'o', 'l', 's', 6, 'h', 'y', 'e', 'o', 'l', 't', 6, 'h', 'y', 'e', 'o', 'l', 'p', 6, 'h', 'y', 'e', 'o', 'l', 'h', 5, 'h', 'y', 'e', 'o', 'm', 5, 'h', 'y', 'e', 'o', 'b', 6, 'h', 'y', 'e', 'o', 'b', 's', 5, 'h', 'y', 'e', 'o', 's', 6, 'h', 'y', 'e', 'o', 's', 's', 6, 'h', 'y', 'e', 'o', 'n', 'g', 5, 'h', 'y', 'e', 'o', 'j', 5, 'h', 'y', 'e', 'o', 'c', 5, 'h', 'y', 'e', 'o', 'k', 5, 'h', 'y', 'e', 'o', 't', 5, 'h', 'y', 'e', 'o', 'p', 5, 'h', 'y', 'e', 'o', 'h', 3, 'h', 'y', 'e', 4, 'h', 'y', 'e', 'g', 5, 'h', 'y', 'e', 'g', 'g', 5, 'h', 'y', 'e', 'g', 's', 4, 'h', 'y', 'e', 'n', 5, 'h', 'y', 'e', 'n', 'j', 5, 'h', 'y', 'e', 'n', 'h', 4, 'h', 'y', 'e', 'd', 4, 'h', 'y', 'e', 'l', 5, 'h', 'y', 'e', 'l', 'g', 5, 'h', 'y', 'e', 'l', 'm', 5, 'h', 'y', 'e', 'l', 'b', 5, 'h', 'y', 'e', 'l', 's', 5, 'h', 'y', 'e', 'l', 't', 5, 'h', 'y', 'e', 'l', 'p', 5, 'h', 'y', 'e', 'l', 'h', 4, 'h', 'y', 'e', 'm', 4, 'h', 'y', 'e', 'b', 5, 'h', 'y', 'e', 'b', 's', 4, 'h', 'y', 'e', 's', 5, 'h', 'y', 'e', 's', 's', 5, 'h', 'y', 'e', 'n', 'g', 4, 'h', 'y', 'e', 'j', 4, 'h', 'y', 'e', 'c', 4, 'h', 'y', 'e', 'k', 4, 'h', 'y', 'e', 't', 4, 'h', 'y', 'e', 'p', 4, 'h', 'y', 'e', 'h', 2, 'h', 'o', 3, 'h', 'o', 'g', 4, 'h', 'o', 'g', 'g', 4, 'h', 'o', 'g', 's', 3, 'h', 'o', 'n', 4, 'h', 'o', 'n', 'j', 4, 'h', 'o', 'n', 'h', 3, 'h', 'o', 'd', 3, 'h', 'o', 'l', 4, 'h', 'o', 'l', 'g', 4, 'h', 'o', 'l', 'm', 4, 'h', 'o', 'l', 'b', 4, 'h', 'o', 'l', 's', 4, 'h', 'o', 'l', 't', 4, 'h', 'o', 'l', 'p', 4, 'h', 'o', 'l', 'h', 3, 'h', 'o', 'm', 3, 'h', 'o', 'b', 4, 'h', 'o', 'b', 's', 3, 'h', 'o', 's', 4, 'h', 'o', 's', 's', 4, 'h', 'o', 'n', 'g', 3, 'h', 'o', 'j', 3, 'h', 'o', 'c', 3, 'h', 'o', 'k', 3, 'h', 'o', 't', 3, 'h', 'o', 'p', 3, 'h', 'o', 'h', 3, 'h', 'w', 'a', 4, 'h', 'w', 'a', 'g', 5, 'h', 'w', 'a', 'g', 'g', 5, 'h', 'w', 'a', 'g', 's', 4, 'h', 'w', 'a', 'n', 5, 'h', 'w', 'a', 'n', 'j', 5, 'h', 'w', 'a', 'n', 'h', 4, 'h', 'w', 'a', 'd', 4, 'h', 'w', 'a', 'l', 5, 'h', 'w', 'a', 'l', 'g', 5, 'h', 'w', 'a', 'l', 'm', 5, 'h', 'w', 'a', 'l', 'b', 5, 'h', 'w', 'a', 'l', 's', 5, 'h', 'w', 'a', 'l', 't', 5, 'h', 'w', 'a', 'l', 'p', 5, 'h', 'w', 'a', 'l', 'h', 4, 'h', 'w', 'a', 'm', 4, 'h', 'w', 'a', 'b', 5, 'h', 'w', 'a', 'b', 's', 4, 'h', 'w', 'a', 's', 5, 'h', 'w', 'a', 's', 's', 5, 'h', 'w', 'a', 'n', 'g', 4, 'h', 'w', 'a', 'j', 4, 'h', 'w', 'a', 'c', 4, 'h', 'w', 'a', 'k', 4, 'h', 'w', 'a', 't', 4, 'h', 'w', 'a', 'p', 4, 'h', 'w', 'a', 'h', 4, 'h', 'w', 'a', 'e', 5, 'h', 'w', 'a', 'e', 'g', 6, 'h', 'w', 'a', 'e', 'g', 'g', 6, 'h', 'w', 'a', 'e', 'g', 's', 5, 'h', 'w', 'a', 'e', 'n', 6, 'h', 'w', 'a', 'e', 'n', 'j', 6, 'h', 'w', 'a', 'e', 'n', 'h', 5, 'h', 'w', 'a', 'e', 'd', 5, 'h', 'w', 'a', 'e', 'l', 6, 'h', 'w', 'a', 'e', 'l', 'g', 6, 'h', 'w', 'a', 'e', 'l', 'm', 6, 'h', 'w', 'a', 'e', 'l', 'b', 6, 'h', 'w', 'a', 'e', 'l', 's', 6, 'h', 'w', 'a', 'e', 'l', 't', 6, 'h', 'w', 'a', 'e', 'l', 'p', 6, 'h', 'w', 'a', 'e', 'l', 'h', 5, 'h', 'w', 'a', 'e', 'm', 5, 'h', 'w', 'a', 'e', 'b', 6, 'h', 'w', 'a', 'e', 'b', 's', 5, 'h', 'w', 'a', 'e', 's', 6, 'h', 'w', 'a', 'e', 's', 's', 6, 'h', 'w', 'a', 'e', 'n', 'g', 5, 'h', 'w', 'a', 'e', 'j', 5, 'h', 'w', 'a', 'e', 'c', 5, 'h', 'w', 'a', 'e', 'k', 5, 'h', 'w', 'a', 'e', 't', 5, 'h', 'w', 'a', 'e', 'p', 5, 'h', 'w', 'a', 'e', 'h', 3, 'h', 'o', 'e', 4, 'h', 'o', 'e', 'g', 5, 'h', 'o', 'e', 'g', 'g', 5, 'h', 'o', 'e', 'g', 's', 4, 'h', 'o', 'e', 'n', 5, 'h', 'o', 'e', 'n', 'j', 5, 'h', 'o', 'e', 'n', 'h', 4, 'h', 'o', 'e', 'd', 4, 'h', 'o', 'e', 'l', 5, 'h', 'o', 'e', 'l', 'g', 5, 'h', 'o', 'e', 'l', 'm', 5, 'h', 'o', 'e', 'l', 'b', 5, 'h', 'o', 'e', 'l', 's', 5, 'h', 'o', 'e', 'l', 't', 5, 'h', 'o', 'e', 'l', 'p', 5, 'h', 'o', 'e', 'l', 'h', 4, 'h', 'o', 'e', 'm', 4, 'h', 'o', 'e', 'b', 5, 'h', 'o', 'e', 'b', 's', 4, 'h', 'o', 'e', 's', 5, 'h', 'o', 'e', 's', 's', 5, 'h', 'o', 'e', 'n', 'g', 4, 'h', 'o', 'e', 'j', 4, 'h', 'o', 'e', 'c', 4, 'h', 'o', 'e', 'k', 4, 'h', 'o', 'e', 't', 4, 'h', 'o', 'e', 'p', 4, 'h', 'o', 'e', 'h', 3, 'h', 'y', 'o', 4, 'h', 'y', 'o', 'g', 5, 'h', 'y', 'o', 'g', 'g', 5, 'h', 'y', 'o', 'g', 's', 4, 'h', 'y', 'o', 'n', 5, 'h', 'y', 'o', 'n', 'j', 5, 'h', 'y', 'o', 'n', 'h', 4, 'h', 'y', 'o', 'd', 4, 'h', 'y', 'o', 'l', 5, 'h', 'y', 'o', 'l', 'g', 5, 'h', 'y', 'o', 'l', 'm', 5, 'h', 'y', 'o', 'l', 'b', 5, 'h', 'y', 'o', 'l', 's', 5, 'h', 'y', 'o', 'l', 't', 5, 'h', 'y', 'o', 'l', 'p', 5, 'h', 'y', 'o', 'l', 'h', 4, 'h', 'y', 'o', 'm', 4, 'h', 'y', 'o', 'b', 5, 'h', 'y', 'o', 'b', 's', 4, 'h', 'y', 'o', 's', 5, 'h', 'y', 'o', 's', 's', 5, 'h', 'y', 'o', 'n', 'g', 4, 'h', 'y', 'o', 'j', 4, 'h', 'y', 'o', 'c', 4, 'h', 'y', 'o', 'k', 4, 'h', 'y', 'o', 't', 4, 'h', 'y', 'o', 'p', 4, 'h', 'y', 'o', 'h', 2, 'h', 'u', 3, 'h', 'u', 'g', 4, 'h', 'u', 'g', 'g', 4, 'h', 'u', 'g', 's', 3, 'h', 'u', 'n', 4, 'h', 'u', 'n', 'j', 4, 'h', 'u', 'n', 'h', 3, 'h', 'u', 'd', 3, 'h', 'u', 'l', 4, 'h', 'u', 'l', 'g', 4, 'h', 'u', 'l', 'm', 4, 'h', 'u', 'l', 'b', 4, 'h', 'u', 'l', 's', 4, 'h', 'u', 'l', 't', 4, 'h', 'u', 'l', 'p', 4, 'h', 'u', 'l', 'h', 3, 'h', 'u', 'm', 3, 'h', 'u', 'b', 4, 'h', 'u', 'b', 's', 3, 'h', 'u', 's', 4, 'h', 'u', 's', 's', 4, 'h', 'u', 'n', 'g', 3, 'h', 'u', 'j', 3, 'h', 'u', 'c', 3, 'h', 'u', 'k', 3, 'h', 'u', 't', 3, 'h', 'u', 'p', 3, 'h', 'u', 'h', 4, 'h', 'w', 'e', 'o', 5, 'h', 'w', 'e', 'o', 'g', 6, 'h', 'w', 'e', 'o', 'g', 'g', 6, 'h', 'w', 'e', 'o', 'g', 's', 5, 'h', 'w', 'e', 'o', 'n', 6, 'h', 'w', 'e', 'o', 'n', 'j', 6, 'h', 'w', 'e', 'o', 'n', 'h', 5, 'h', 'w', 'e', 'o', 'd', 5, 'h', 'w', 'e', 'o', 'l', 6, 'h', 'w', 'e', 'o', 'l', 'g', 6, 'h', 'w', 'e', 'o', 'l', 'm', 6, 'h', 'w', 'e', 'o', 'l', 'b', 6, 'h', 'w', 'e', 'o', 'l', 's', 6, 'h', 'w', 'e', 'o', 'l', 't', 6, 'h', 'w', 'e', 'o', 'l', 'p', 6, 'h', 'w', 'e', 'o', 'l', 'h', 5, 'h', 'w', 'e', 'o', 'm', 5, 'h', 'w', 'e', 'o', 'b', 6, 'h', 'w', 'e', 'o', 'b', 's', 5, 'h', 'w', 'e', 'o', 's', 6, 'h', 'w', 'e', 'o', 's', 's', 6, 'h', 'w', 'e', 'o', 'n', 'g', 5, 'h', 'w', 'e', 'o', 'j', 5, 'h', 'w', 'e', 'o', 'c', 5, 'h', 'w', 'e', 'o', 'k', 5, 'h', 'w', 'e', 'o', 't', 5, 'h', 'w', 'e', 'o', 'p', 5, 'h', 'w', 'e', 'o', 'h', 3, 'h', 'w', 'e', 4, 'h', 'w', 'e', 'g', 5, 'h', 'w', 'e', 'g', 'g', 5, 'h', 'w', 'e', 'g', 's', 4, 'h', 'w', 'e', 'n', 5, 'h', 'w', 'e', 'n', 'j', 5, 'h', 'w', 'e', 'n', 'h', 4, 'h', 'w', 'e', 'd', 4, 'h', 'w', 'e', 'l', 5, 'h', 'w', 'e', 'l', 'g', 5, 'h', 'w', 'e', 'l', 'm', 5, 'h', 'w', 'e', 'l', 'b', 5, 'h', 'w', 'e', 'l', 's', 5, 'h', 'w', 'e', 'l', 't', 5, 'h', 'w', 'e', 'l', 'p', 5, 'h', 'w', 'e', 'l', 'h', 4, 'h', 'w', 'e', 'm', 4, 'h', 'w', 'e', 'b', 5, 'h', 'w', 'e', 'b', 's', 4, 'h', 'w', 'e', 's', 5, 'h', 'w', 'e', 's', 's', 5, 'h', 'w', 'e', 'n', 'g', 4, 'h', 'w', 'e', 'j', 4, 'h', 'w', 'e', 'c', 4, 'h', 'w', 'e', 'k', 4, 'h', 'w', 'e', 't', 4, 'h', 'w', 'e', 'p', 4, 'h', 'w', 'e', 'h', 3, 'h', 'w', 'i', 4, 'h', 'w', 'i', 'g', 5, 'h', 'w', 'i', 'g', 'g', 5, 'h', 'w', 'i', 'g', 's', 4, 'h', 'w', 'i', 'n', 5, 'h', 'w', 'i', 'n', 'j', 5, 'h', 'w', 'i', 'n', 'h', 4, 'h', 'w', 'i', 'd', 4, 'h', 'w', 'i', 'l', 5, 'h', 'w', 'i', 'l', 'g', 5, 'h', 'w', 'i', 'l', 'm', 5, 'h', 'w', 'i', 'l', 'b', 5, 'h', 'w', 'i', 'l', 's', 5, 'h', 'w', 'i', 'l', 't', 5, 'h', 'w', 'i', 'l', 'p', 5, 'h', 'w', 'i', 'l', 'h', 4, 'h', 'w', 'i', 'm', 4, 'h', 'w', 'i', 'b', 5, 'h', 'w', 'i', 'b', 's', 4, 'h', 'w', 'i', 's', 5, 'h', 'w', 'i', 's', 's', 5, 'h', 'w', 'i', 'n', 'g', 4, 'h', 'w', 'i', 'j', 4, 'h', 'w', 'i', 'c', 4, 'h', 'w', 'i', 'k', 4, 'h', 'w', 'i', 't', 4, 'h', 'w', 'i', 'p', 4, 'h', 'w', 'i', 'h', 3, 'h', 'y', 'u', 4, 'h', 'y', 'u', 'g', 5, 'h', 'y', 'u', 'g', 'g', 5, 'h', 'y', 'u', 'g', 's', 4, 'h', 'y', 'u', 'n', 5, 'h', 'y', 'u', 'n', 'j', 5, 'h', 'y', 'u', 'n', 'h', 4, 'h', 'y', 'u', 'd', 4, 'h', 'y', 'u', 'l', 5, 'h', 'y', 'u', 'l', 'g', 5, 'h', 'y', 'u', 'l', 'm', 5, 'h', 'y', 'u', 'l', 'b', 5, 'h', 'y', 'u', 'l', 's', 5, 'h', 'y', 'u', 'l', 't', 5, 'h', 'y', 'u', 'l', 'p', 5, 'h', 'y', 'u', 'l', 'h', 4, 'h', 'y', 'u', 'm', 4, 'h', 'y', 'u', 'b', 5, 'h', 'y', 'u', 'b', 's', 4, 'h', 'y', 'u', 's', 5, 'h', 'y', 'u', 's', 's', 5, 'h', 'y', 'u', 'n', 'g', 4, 'h', 'y', 'u', 'j', 4, 'h', 'y', 'u', 'c', 4, 'h', 'y', 'u', 'k', 4, 'h', 'y', 'u', 't', 4, 'h', 'y', 'u', 'p', 4, 'h', 'y', 'u', 'h', 3, 'h', 'e', 'u', 4, 'h', 'e', 'u', 'g', 5, 'h', 'e', 'u', 'g', 'g', 5, 'h', 'e', 'u', 'g', 's', 4, 'h', 'e', 'u', 'n', 5, 'h', 'e', 'u', 'n', 'j', 5, 'h', 'e', 'u', 'n', 'h', 4, 'h', 'e', 'u', 'd', 4, 'h', 'e', 'u', 'l', 5, 'h', 'e', 'u', 'l', 'g', 5, 'h', 'e', 'u', 'l', 'm', 5, 'h', 'e', 'u', 'l', 'b', 5, 'h', 'e', 'u', 'l', 's', 5, 'h', 'e', 'u', 'l', 't', 5, 'h', 'e', 'u', 'l', 'p', 5, 'h', 'e', 'u', 'l', 'h', 4, 'h', 'e', 'u', 'm', 4, 'h', 'e', 'u', 'b', 5, 'h', 'e', 'u', 'b', 's', 4, 'h', 'e', 'u', 's', 5, 'h', 'e', 'u', 's', 's', 5, 'h', 'e', 'u', 'n', 'g', 4, 'h', 'e', 'u', 'j', 4, 'h', 'e', 'u', 'c', 4, 'h', 'e', 'u', 'k', 4, 'h', 'e', 'u', 't', 4, 'h', 'e', 'u', 'p', 4, 'h', 'e', 'u', 'h', 3, 'h', 'y', 'i', 4, 'h', 'y', 'i', 'g', 5, 'h', 'y', 'i', 'g', 'g', 5, 'h', 'y', 'i', 'g', 's', 4, 'h', 'y', 'i', 'n', 5, 'h', 'y', 'i', 'n', 'j', 5, 'h', 'y', 'i', 'n', 'h', 4, 'h', 'y', 'i', 'd', 4, 'h', 'y', 'i', 'l', 5, 'h', 'y', 'i', 'l', 'g', 5, 'h', 'y', 'i', 'l', 'm', 5, 'h', 'y', 'i', 'l', 'b', 5, 'h', 'y', 'i', 'l', 's', 5, 'h', 'y', 'i', 'l', 't', 5, 'h', 'y', 'i', 'l', 'p', 5, 'h', 'y', 'i', 'l', 'h', 4, 'h', 'y', 'i', 'm', 4, 'h', 'y', 'i', 'b', 5, 'h', 'y', 'i', 'b', 's', 4, 'h', 'y', 'i', 's', 5, 'h', 'y', 'i', 's', 's', 5, 'h', 'y', 'i', 'n', 'g', 4, 'h', 'y', 'i', 'j', 4, 'h', 'y', 'i', 'c', 4, 'h', 'y', 'i', 'k', 4, 'h', 'y', 'i', 't', 4, 'h', 'y', 'i', 'p', 4, 'h', 'y', 'i', 'h', 2, 'h', 'i', 3, 'h', 'i', 'g', 4, 'h', 'i', 'g', 'g', 4, 'h', 'i', 'g', 's', 3, 'h', 'i', 'n', 4, 'h', 'i', 'n', 'j', 4, 'h', 'i', 'n', 'h', 3, 'h', 'i', 'd', 3, 'h', 'i', 'l', 4, 'h', 'i', 'l', 'g', 4, 'h', 'i', 'l', 'm', 4, 'h', 'i', 'l', 'b', 4, 'h', 'i', 'l', 's', 4, 'h', 'i', 'l', 't', 4, 'h', 'i', 'l', 'p', 4, 'h', 'i', 'l', 'h', 3, 'h', 'i', 'm', 3, 'h', 'i', 'b', 4, 'h', 'i', 'b', 's', 3, 'h', 'i', 's', 4, 'h', 'i', 's', 's', 4, 'h', 'i', 'n', 'g', 3, 'h', 'i', 'j', 3, 'h', 'i', 'c', 3, 'h', 'i', 'k', 3, 'h', 'i', 't', 3, 'h', 'i', 'p', 3, 'h', 'i', 'h', 4, 'K', 'a', 'y', ' ', 6, 'K', 'a', 'y', 'n', 'g', ' ', 3, 'K', 'e', ' ', 3, 'K', 'o', ' ', 4, 'K', 'o', 'l', ' ', 4, 'K', 'o', 'c', ' ', 4, 'K', 'w', 'i', ' ', 4, 'K', 'w', 'i', ' ', 5, 'K', 'y', 'u', 'n', ' ', 4, 'K', 'u', 'l', ' ', 4, 'K', 'u', 'm', ' ', 3, 'N', 'a', ' ', 3, 'N', 'a', ' ', 3, 'N', 'a', ' ', 3, 'L', 'a', ' ', 3, 'N', 'a', ' ', 3, 'N', 'a', ' ', 3, 'N', 'a', ' ', 3, 'N', 'a', ' ', 3, 'N', 'a', ' ', 4, 'N', 'a', 'k', ' ', 4, 'N', 'a', 'k', ' ', 4, 'N', 'a', 'k', ' ', 4, 'N', 'a', 'k', ' ', 4, 'N', 'a', 'k', ' ', 4, 'N', 'a', 'k', ' ', 4, 'N', 'a', 'k', ' ', 4, 'N', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 4, 'N', 'a', 'n', ' ', 4, 'N', 'a', 'm', ' ', 4, 'N', 'a', 'm', ' ', 4, 'N', 'a', 'm', ' ', 4, 'N', 'a', 'm', ' ', 4, 'N', 'a', 'p', ' ', 4, 'N', 'a', 'p', ' ', 4, 'N', 'a', 'p', ' ', 5, 'N', 'a', 'n', 'g', ' ', 5, 'N', 'a', 'n', 'g', ' ', 5, 'N', 'a', 'n', 'g', ' ', 5, 'N', 'a', 'n', 'g', ' ', 5, 'N', 'a', 'n', 'g', ' ', 4, 'N', 'a', 'y', ' ', 6, 'N', 'a', 'y', 'n', 'g', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 3, 'N', 'o', ' ', 4, 'N', 'o', 'k', ' ', 4, 'N', 'o', 'k', ' ', 4, 'N', 'o', 'k', ' ', 4, 'N', 'o', 'k', ' ', 4, 'N', 'o', 'k', ' ', 4, 'N', 'o', 'k', ' ', 4, 'N', 'o', 'n', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'N', 'o', 'n', 'g', ' ', 5, 'N', 'o', 'n', 'g', ' ', 4, 'N', 'o', 'y', ' ', 4, 'N', 'o', 'y', ' ', 4, 'N', 'o', 'y', ' ', 4, 'N', 'o', 'y', ' ', 4, 'N', 'w', 'u', ' ', 4, 'N', 'w', 'u', ' ', 4, 'N', 'w', 'u', ' ', 4, 'N', 'w', 'u', ' ', 4, 'N', 'w', 'u', ' ', 4, 'N', 'w', 'u', ' ', 4, 'N', 'w', 'u', ' ', 4, 'N', 'w', 'u', ' ', 4, 'N', 'u', 'k', ' ', 4, 'N', 'u', 'k', ' ', 4, 'N', 'u', 'm', ' ', 5, 'N', 'u', 'n', 'g', ' ', 5, 'N', 'u', 'n', 'g', ' ', 5, 'N', 'u', 'n', 'g', ' ', 5, 'N', 'u', 'n', 'g', ' ', 5, 'N', 'u', 'n', 'g', ' ', 4, 'T', 'w', 'u', ' ', 3, 'L', 'a', ' ', 4, 'L', 'a', 'k', ' ', 4, 'L', 'a', 'k', ' ', 4, 'L', 'a', 'n', ' ', 6, 'L', 'y', 'e', 'n', 'g', ' ', 3, 'L', 'o', ' ', 5, 'L', 'y', 'u', 'l', ' ', 3, 'L', 'i', ' ', 4, 'P', 'e', 'y', ' ', 4, 'P', 'e', 'n', ' ', 5, 'P', 'y', 'e', 'n', ' ', 4, 'P', 'w', 'u', ' ', 5, 'P', 'w', 'u', 'l', ' ', 3, 'P', 'i', ' ', 4, 'S', 'a', 'k', ' ', 4, 'S', 'a', 'k', ' ', 4, 'S', 'a', 'm', ' ', 5, 'S', 'a', 'y', 'k', ' ', 6, 'S', 'a', 'y', 'n', 'g', ' ', 4, 'S', 'e', 'p', ' ', 4, 'S', 'e', 'y', ' ', 5, 'S', 'w', 'a', 'y', ' ', 4, 'S', 'i', 'n', ' ', 4, 'S', 'i', 'm', ' ', 4, 'S', 'i', 'p', ' ', 3, 'Y', 'a', ' ', 4, 'Y', 'a', 'k', ' ', 4, 'Y', 'a', 'k', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 5, 'Y', 'a', 'n', 'g', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 3, 'Y', 'e', ' ', 4, 'Y', 'e', 'k', ' ', 4, 'Y', 'e', 'k', ' ', 4, 'Y', 'e', 'k', ' ', 4, 'Y', 'e', 'k', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'n', ' ', 4, 'Y', 'e', 'l', ' ', 4, 'Y', 'e', 'l', ' ', 4, 'Y', 'e', 'l', ' ', 4, 'Y', 'e', 'l', ' ', 4, 'Y', 'e', 'l', ' ', 4, 'Y', 'e', 'l', ' ', 4, 'Y', 'e', 'm', ' ', 4, 'Y', 'e', 'm', ' ', 4, 'Y', 'e', 'm', ' ', 4, 'Y', 'e', 'm', ' ', 4, 'Y', 'e', 'm', ' ', 4, 'Y', 'e', 'p', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 5, 'Y', 'e', 'n', 'g', ' ', 4, 'Y', 'e', 'y', ' ', 4, 'Y', 'e', 'y', ' ', 4, 'Y', 'e', 'y', ' ', 4, 'Y', 'e', 'y', ' ', 2, 'O', ' ', 3, 'Y', 'o', ' ', 3, 'Y', 'o', ' ', 3, 'Y', 'o', ' ', 3, 'Y', 'o', ' ', 3, 'Y', 'o', ' ', 3, 'Y', 'o', ' ', 3, 'Y', 'o', ' ', 3, 'Y', 'o', ' ', 3, 'Y', 'o', ' ', 3, 'Y', 'o', ' ', 5, 'Y', 'o', 'n', 'g', ' ', 4, 'W', 'u', 'n', ' ', 4, 'W', 'e', 'n', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 3, 'Y', 'u', ' ', 4, 'Y', 'u', 'k', ' ', 4, 'Y', 'u', 'k', ' ', 4, 'Y', 'u', 'k', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Y', 'u', 'n', ' ', 4, 'Y', 'u', 'l', ' ', 4, 'Y', 'u', 'l', ' ', 4, 'Y', 'u', 'l', ' ', 4, 'Y', 'u', 'l', ' ', 5, 'Y', 'u', 'n', 'g', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 2, 'I', ' ', 3, 'I', 'k', ' ', 3, 'I', 'k', ' ', 3, 'I', 'n', ' ', 3, 'I', 'n', ' ', 3, 'I', 'n', ' ', 3, 'I', 'n', ' ', 3, 'I', 'n', ' ', 3, 'I', 'n', ' ', 3, 'I', 'n', ' ', 3, 'I', 'm', ' ', 3, 'I', 'm', ' ', 3, 'I', 'm', ' ', 3, 'I', 'p', ' ', 3, 'I', 'p', ' ', 3, 'I', 'p', ' ', 5, 'C', 'a', 'n', 'g', ' ', 4, 'C', 'e', 'k', ' ', 3, 'C', 'i', ' ', 4, 'C', 'i', 'p', ' ', 4, 'C', 'h', 'a', ' ', 5, 'C', 'h', 'e', 'k', ' ', 5, 'C', 'h', 'e', 'y', ' ', 5, 'T', 'h', 'a', 'k', ' ', 5, 'T', 'h', 'a', 'k', ' ', 6, 'T', 'h', 'a', 'n', 'g', ' ', 6, 'T', 'h', 'a', 'y', 'k', ' ', 6, 'T', 'h', 'o', 'n', 'g', ' ', 4, 'P', 'h', 'o', ' ', 5, 'P', 'h', 'o', 'k', ' ', 5, 'H', 'a', 'n', 'g', ' ', 5, 'H', 'a', 'n', 'g', ' ', 5, 'H', 'y', 'e', 'n', ' ', 5, 'H', 'w', 'a', 'k', ' ', 3, 'W', 'u', ' ', 4, 'H', 'u', 'o', ' ', 6, 'Z', 'h', 'o', 'n', 'g', ' ', 5, 'Q', 'i', 'n', 'g', ' ', 3, 'X', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'L', 'i', ' ', 5, 'S', 'h', 'e', 'n', ' ', 6, 'X', 'i', 'a', 'n', 'g', ' ', 3, 'F', 'u', ' ', 5, 'J', 'i', 'n', 'g', ' ', 5, 'J', 'i', 'n', 'g', ' ', 3, 'Y', 'u', ' ', 5, 'H', 'a', 'g', 'i', ' ', 4, 'Z', 'h', 'u', ' ', 3, 'Y', 'i', ' ', 3, 'D', 'u', ' ', 4, 'F', 'a', 'n', ' ', 3, 'S', 'i', ' ', 5, 'G', 'u', 'a', 'n', ' ', 2, 'f', 'f', 2, 'f', 'i', 2, 'f', 'l', 3, 'f', 'f', 'i', 3, 'f', 'f', 'l', 2, 's', 't', 2, 's', 't', 2, 'm', 'n', 2, 'm', 'e', 2, 'm', 'i', 2, 'v', 'n', 3, 'm', 'k', 'h', 1, 'i', 2, 'A', 'Y', 1, '`', 1, 'A', 1, 'd', 1, 'h', 2, 'K', 'H', 1, 'l', 1, 'm', 1, 'r', 1, 't', 1, '+', 2, 'S', 'H', 1, 'S', 2, 'S', 'H', 1, 'S', 1, 'a', 1, 'a', 1, 'A', 1, 'b', 1, 'g', 1, 'd', 1, 'h', 1, 'v', 1, 'z', 1, 't', 1, 'y', 2, 'K', 'H', 2, 'K', 'H', 1, 'l', 1, 'm', 1, 'n', 1, 's', 1, 'p', 1, 'p', 2, 'T', 'S', 1, 'k', 1, 'r', 2, 'S', 'H', 1, 't', 1, 'o', 1, 'v', 2, 'K', 'H', 1, 'f', 2, 'E', 'L', 1, '~', 2, '.', '.', 2, '-', '-', 1, '-', 1, '_', 1, '_', 1, '(', 2, ')', ' ', 1, '{', 2, '}', ' ', 1, '[', 2, ']', ' ', 2, '[', '(', 3, ')', ']', ' ', 2, '<', '<', 3, '>', '>', ' ', 1, '<', 2, '>', ' ', 1, '[', 2, ']', ' ', 1, '{', 1, '}', 1, ',', 1, ',', 1, '.', 1, ';', 1, ':', 1, '?', 1, '!', 1, '-', 1, '(', 1, ')', 1, '{', 1, '}', 1, '{', 1, '}', 1, '#', 1, '&', 1, '*', 1, '+', 1, '-', 1, '<', 1, '>', 1, '=', 1, '\\', 1, '$', 1, '%', 1, '@', 1, '!', 1, '\"', 1, '#', 1, '$', 1, '%', 1, '&', 1, '\'', 1, '(', 1, ')', 1, '*', 1, '+', 1, ',', 1, '-', 1, '.', 1, '/', 1, '0', 1, '1', 1, '2', 1, '3', 1, '4', 1, '5', 1, '6', 1, '7', 1, '8', 1, '9', 1, ':', 1, ';', 1, '<', 1, '=', 1, '>', 1, '?', 1, '@', 1, 'A', 1, 'B', 1, 'C', 1, 'D', 1, 'E', 1, 'F', 1, 'G', 1, 'H', 1, 'I', 1, 'J', 1, 'K', 1, 'L', 1, 'M', 1, 'N', 1, 'O', 1, 'P', 1, 'Q', 1, 'R', 1, 'S', 1, 'T', 1, 'U', 1, 'V', 1, 'W', 1, 'X', 1, 'Y', 1, 'Z', 1, '[', 1, '\\', 1, ']', 1, '^', 1, '_', 1, '`', 1, 'a', 1, 'b', 1, 'c', 1, 'd', 1, 'e', 1, 'f', 1, 'g', 1, 'h', 1, 'i', 1, 'j', 1, 'k', 1, 'l', 1, 'm', 1, 'n', 1, 'o', 1, 'p', 1, 'q', 1, 'r', 1, 's', 1, 't', 1, 'u', 1, 'v', 1, 'w', 1, 'x', 1, 'y', 1, 'z', 1, '{', 1, '|', 1, '}', 1, '~', 1, '.', 1, '[', 1, ']', 1, ',', 1, '*', 2, 'w', 'o', 1, 'a', 1, 'i', 1, 'u', 1, 'e', 1, 'o', 2, 'y', 'a', 2, 'y', 'u', 2, 'y', 'o', 2, 't', 'u', 1, '+', 1, 'a', 1, 'i', 1, 'u', 1, 'e', 1, 'o', 2, 'k', 'a', 2, 'k', 'i', 2, 'k', 'u', 2, 'k', 'e', 2, 'k', 'o', 2, 's', 'a', 2, 's', 'i', 2, 's', 'u', 2, 's', 'e', 2, 's', 'o', 2, 't', 'a', 2, 't', 'i', 2, 't', 'u', 2, 't', 'e', 2, 't', 'o', 2, 'n', 'a', 2, 'n', 'i', 2, 'n', 'u', 2, 'n', 'e', 2, 'n', 'o', 2, 'h', 'a', 2, 'h', 'i', 2, 'h', 'u', 2, 'h', 'e', 2, 'h', 'o', 2, 'm', 'a', 2, 'm', 'i', 2, 'm', 'u', 2, 'm', 'e', 2, 'm', 'o', 2, 'y', 'a', 2, 'y', 'u', 2, 'y', 'o', 2, 'r', 'a', 2, 'r', 'i', 2, 'r', 'u', 2, 'r', 'e', 2, 'r', 'o', 2, 'w', 'a', 1, 'n', 1, ':', 1, ';', 1, 'g', 2, 'g', 'g', 2, 'g', 's', 1, 'n', 2, 'n', 'j', 2, 'n', 'h', 1, 'd', 2, 'd', 'd', 1, 'r', 2, 'l', 'g', 2, 'l', 'm', 2, 'l', 'b', 2, 'l', 's', 2, 'l', 't', 2, 'l', 'p', 2, 'r', 'h', 1, 'm', 1, 'b', 2, 'b', 'b', 2, 'b', 's', 1, 's', 2, 's', 's', 1, 'j', 2, 'j', 'j', 1, 'c', 1, 'k', 1, 't', 1, 'p', 1, 'h', 1, 'a', 2, 'a', 'e', 2, 'y', 'a', 3, 'y', 'a', 'e', 2, 'e', 'o', 1, 'e', 3, 'y', 'e', 'o', 2, 'y', 'e', 1, 'o', 2, 'w', 'a', 3, 'w', 'a', 'e', 2, 'o', 'e', 2, 'y', 'o', 1, 'u', 3, 'w', 'e', 'o', 2, 'w', 'e', 2, 'w', 'i', 2, 'y', 'u', 2, 'e', 'u', 2, 'y', 'i', 1, 'i', 2, '/', 'C', 2, 'P', 'S', 1, '!', 1, '-', 1, '|', 2, 'Y', '=', 2, 'W', '=', 1, '|', 1, '-', 1, '|', 1, '-', 1, '|', 1, '#', 1, 'O', 1, '{', 1, '|', 1, '}', }; const int Data::tranlitIndexMap[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 2, 4, 7, 10, 13, 16, 18, 21, 23, 27, 29, 32, -1, 34, 38, 40, 44, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 68, 74, 80, 86, 88, 90, 92, 94, 96, 98, 100, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 152, 155, 157, 159, 161, 163, 165, 167, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 324, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, 367, 369, 372, 375, 378, 380, 382, 384, 386, 388, 390, 393, 396, 398, 400, 402, 404, 406, 408, 410, 412, 414, 416, 418, 420, 422, 424, 426, 428, 430, 432, 434, 436, 438, 440, 442, 444, 446, 448, 450, 452, 454, 456, 458, 460, 462, 464, 466, 468, 470, 472, 474, 476, 478, 480, 482, 484, 486, 488, 490, 492, 494, 496, 498, 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 529, 531, 533, 535, 537, 539, 541, 543, 545, 547, 549, 551, 553, 556, 559, 561, 563, 566, 568, 570, 573, 576, 578, 580, 582, 584, 586, 588, 590, 592, 594, 596, 598, 600, 603, 606, 609, 612, 614, 616, 618, 621, 623, 625, 628, 631, 633, 636, 639, 642, 645, 648, 651, 654, 657, 660, 662, 664, 666, 668, 670, 672, 674, 676, 678, 680, 682, 684, 686, 688, 690, 692, 694, 696, 698, 700, 702, 705, 708, 710, 712, 714, 716, 718, 720, 722, 724, 726, 728, 731, 734, 736, 739, 742, 745, 747, 749, 752, 754, 756, 758, 760, 762, 765, 768, 770, 772, 774, 776, 778, 780, 782, 784, 786, 788, 790, 792, 794, 796, 798, 800, 802, 804, 806, 808, 810, 812, 814, 816, 818, 820, 822, 824, 826, 828, 830, 832, 834, 836, 838, 840, 843, 846, 848, 850, 852, 854, 856, 858, 860, 862, 864, 866, 868, 870, 872, 874, 876, 878, 880, 882, 884, 886, 889, 892, 894, 896, 898, 900, 902, 904, -1, -1, 906, 908, 910, 912, 914, 916, 918, 920, 922, 924, 926, 928, 930, 932, 934, 936, 938, 940, 942, 944, 946, 948, 950, 952, 954, 956, 958, 960, 962, 964, 966, 968, 970, 972, 974, 976, 978, 980, 982, 984, 986, 988, 990, 992, 995, 997, 999, 1001, 1003, 1005, 1007, 1009, 1012, 1014, 1016, 1018, 1020, 1022, 1024, 1026, 1028, 1030, 1032, 1034, 1036, 1038, 1040, 1042, 1044, 1046, 1048, 1050, 1052, 1054, 1056, 1058, 1060, 1062, 1064, 1066, 1068, 1070, 1072, 1074, 1076, 1078, 1080, 1082, 1084, 1086, 1088, 1090, 1092, 1094, 1096, 1098, 1100, 1103, 1106, 1109, 1112, 1115, 1118, 1121, 1124, 1127, 1130, 1133, 1135, 1137, 1139, 1141, 1143, 1145, 1147, 1149, 1151, 1153, 1155, 1157, 1159, 1161, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187, 1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, 1209, 1211, 1213, 1215, 1217, 1219, 1221, 1223, 1225, 1227, 1229, 1231, 1233, 1235, 1237, 1239, 1241, -1, -1, -1, -1, -1, -1, -1, 1243, 1245, 1247, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1249, 1251, 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1271, 1273, -1, -1, -1, -1, 1275, 1277, -1, -1, -1, -1, -1, -1, -1, -1, 1279, -1, -1, -1, -1, -1, -1, -1, 1281, 1283, 1285, 1287, 1289, -1, 1291, -1, 1293, 1295, 1297, 1299, 1301, 1303, 1305, 1307, 1309, 1311, 1313, 1316, 1318, 1320, 1322, 1324, 1326, 1329, 1331, 1333, -1, 1335, 1337, 1339, 1341, 1344, 1347, 1350, 1352, 1354, 1356, 1358, 1360, 1362, 1364, 1366, 1368, 1370, 1372, 1374, 1376, 1378, 1380, 1383, 1385, 1387, 1389, 1391, 1393, 1395, 1397, 1399, 1401, 1403, 1405, 1407, 1409, 1412, 1415, 1418, 1420, 1422, 1424, 1426, 1428, -1, 1430, 1432, 1435, 1437, 1439, 1441, 1444, 1446, -1, -1, 1448, 1451, 1454, 1456, 1458, 1460, 1462, 1465, 1468, 1471, 1474, 1476, 1478, 1481, 1484, 1486, 1488, 1490, 1492, 1495, 1498, 1501, 1504, 1506, 1508, 1510, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1512, 1515, 1518, 1521, 1524, 1527, 1530, 1532, 1535, 1537, 1540, 1543, 1547, 1550, 1552, 1554, 1558, 1560, 1562, 1564, 1566, 1568, 1570, 1573, 1575, 1577, 1579, 1581, 1583, 1585, 1587, 1589, 1591, 1593, 1595, 1597, 1599, 1601, 1604, 1607, 1610, 1613, 1618, 1620, 1622, 1624, 1626, 1629, 1632, 1634, 1636, 1638, 1640, 1642, 1644, 1647, 1649, 1651, 1653, 1655, 1657, 1659, 1661, 1663, 1665, 1667, 1669, 1671, 1673, 1675, 1678, 1681, 1684, 1687, 1692, 1694, 1696, 1698, 1700, 1703, 1706, 1709, 1712, 1715, 1718, 1721, 1724, 1726, 1729, 1731, 1734, 1737, 1741, 1744, 1746, 1748, 1752, 1754, 1756, 1758, 1760, 1763, 1766, 1768, 1770, 1773, 1776, 1778, 1780, 1783, 1786, 1789, 1792, 1795, 1798, 1800, 1802, 1804, 1806, 1808, 1810, 1812, 1814, 1816, 1818, 1820, 1822, 1825, 1828, 1830, 1832, -1, -1, -1, -1, -1, 1839, 1849, -1, -1, 1861, 1863, 1865, 1868, 1871, 1874, 1877, 1880, 1883, 1886, 1889, 1893, 1897, 1900, 1903, 1906, 1909, 1912, 1915, 1918, 1921, 1924, 1927, 1930, 1933, 1936, 1939, 1942, 1945, 1948, 1951, 1954, 1957, 1960, 1963, 1965, 1967, 1970, 1973, 1977, 1981, 1985, 1989, 1993, 1997, 2001, 2005, 2007, 2009, 2012, 2015, 2019, 2023, 2025, 2028, 2031, 2034, -1, -1, 2037, 2040, -1, -1, 2043, 2046, -1, -1, -1, 2049, 2051, 2053, 2055, 2057, 2060, 2063, 2066, 2069, 2071, 2073, 2075, 2077, 2080, 2083, 2085, 2087, 2090, 2093, 2095, 2097, 2099, 2101, 2103, 2105, 2107, 2109, 2111, 2113, 2115, 2117, 2119, 2121, 2123, 2125, 2127, 2129, 2132, -1, -1, 2135, 2137, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2139, 2141, 2143, 2145, 2147, 2149, 2151, 2153, 2155, 2158, 2161, 2163, 2165, 2168, 2171, 2173, 2175, 2178, 2181, 2184, 2186, 2188, 2190, 2193, 2195, 2199, 2201, 2203, 2206, 2208, 2210, 2212, 2214, 2218, 2220, 2223, 2226, 2228, -1, -1, 2230, 2232, 2234, 2236, 2238, 2240, 2242, -1, 2244, 2246, 2248, 2250, 2252, 2254, 2256, 2258, 2260, 2263, 2266, 2268, 2270, 2273, 2276, 2278, 2280, 2283, 2286, 2289, 2291, 2293, 2295, 2298, 2300, 2304, 2306, 2308, 2311, 2313, 2315, 2317, 2319, 2323, 2325, 2328, 2331, 2333, 2335, -1, 2338, 2340, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2342, 2344, 2346, 2348, 2350, 2352, 2354, 2356, 2358, 2360, 2362, -1, -1, 2364, -1, 2366, -1, -1, 2368, -1, -1, 2370, 2372, -1, -1, -1, -1, -1, -1, -1, -1, 2374, 2376, 2378, 2380, 2382, 2384, 2386, 2388, 2390, 2392, 2394, 2397, 2400, 2402, 2404, 2406, 2408, 2410, 2412, 2414, 2416, 2418, 2421, 2424, 2426, 2428, 2431, -1, -1, -1, -1, 2433, 2437, 2439, 2442, 2445, 2447, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2449, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2451, -1, -1, -1, 2453, -1, -1, 2455, 2457, 2459, -1, 2462, -1, 2465, 2467, 2469, 2471, 2474, 2476, 2478, 2481, 2483, 2486, 2488, 2490, 2492, 2495, 2497, 2499, 2501, 2503, 2505, -1, -1, -1, -1, -1, -1, 2507, 2509, 2511, 2513, 2515, 2517, 2519, 2521, 2523, 2525, 2527, 2530, 2533, 2536, 2538, 2540, 2542, -1, -1, 2544, 2546, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2548, 2550, 2552, 2554, 2556, 2558, 2560, 2562, 2564, 2566, 2568, 2570, 2572, 2574, -1, -1, -1, 2576, 2578, 2580, -1, 2582, 2584, 2587, 2590, 2593, 2596, 2600, 2602, 2604, 2606, 2608, 2611, 2614, 2617, 2619, 2622, 2625, 2627, 2630, 2634, 2637, 2639, 2641, 2644, 2647, 2651, 2653, 2655, 2657, 2660, 2662, 2664, 2666, 2668, 2670, 2672, 2674, 2676, 2678, 2680, 2682, 2684, 2686, 2688, 2691, 2693, 2695, 2697, 2699, 2701, 2704, 2706, 2708, 2711, 2713, 2715, 2717, 2720, 2722, 2724, 2726, 2728, 2730, 2732, 2734, 2736, 2738, 2740, 2742, 2744, 2746, 2748, 2750, 2752, 2754, 2757, 2760, 2762, 2764, 2766, 2768, 2771, 2774, 2776, 2779, 2782, 2784, 2786, 2788, 2790, 2792, -1, -1, 2794, 2796, 2799, 2801, -1, -1, -1, -1, -1, -1, -1, 2804, 2806, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2808, -1, -1, -1, -1, -1, -1, 2810, 2812, 2814, 2816, 2818, 2820, 2822, 2824, 2826, 2828, 2830, 2833, 2835, 2838, 2840, -1, 2843, 2846, 2848, 2850, 2852, 2854, 2856, 2858, 2860, 2862, 2864, 2866, 2868, 2870, -1, -1, 2872, -1, 2874, 2876, 2878, 2880, 2882, 2884, 2886, 2888, 2890, 2892, 2894, 2896, 2898, 2901, 2903, 2905, 2907, 2909, 2911, 2913, 2915, 2917, 2919, 2921, 2923, 2925, 2928, -1, -1, -1, 2930, 2932, 2934, 2936, 2938, 2940, 2942, 2944, 2946, 2948, 2950, 2952, 2954, 2956, 2958, 2960, -1, 2962, 2964, -1, -1, 2966, 2968, 2970, 2972, 2974, 2976, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2978, 2980, 2983, 2985, 2987, 2989, 2991, 2993, 2995, 2997, 2999, 3001, 3004, 3007, 3009, 3011, 3014, 3016, 3018, 3020, 3022, 3024, 3026, 3028, 3031, 3034, 3037, 3040, 3043, 3045, 3048, 3050, 3052, 3054, 3056, 3058, 3061, 3063, 3065, 3067, 3070, 3072, 3075, 3077, 3080, 3082, 3085, 3087, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3090, 3092, 3094, -1, 3096, 3098, 3101, 3103, 3106, 3108, 3111, 3113, 3115, 3118, 3120, 3122, 3125, 3128, 3130, 3132, 3135, 3137, 3140, 3142, 3145, 3148, 3150, 3153, 3155, 3158, 3161, 3164, 3168, 3171, 3175, 3178, 3180, 3183, 3185, 3188, 3190, 3194, 3196, 3199, 3201, 3204, 3206, 3208, 3210, 3213, 3215, 3217, 3221, 3223, 3226, 3229, 3231, -1, -1, 3233, 3235, 3237, 3240, 3242, 3245, 3247, 3250, 3252, 3255, 3258, 3260, 3262, 3265, 3268, 3270, 3272, -1, -1, -1, 3275, 3279, 3281, 3283, 3285, -1, -1, -1, 3287, 3289, 3293, 3297, 3299, 3304, 3307, 3309, 3312, 3315, 3318, 3320, 3323, 3327, 3332, 3334, 3336, 3338, 3340, 3342, 3344, 3346, 3348, 3350, 3352, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3354, 3356, 3358, -1, 3360, 3362, 3365, 3367, 3370, 3372, 3375, 3377, -1, -1, 3380, 3382, -1, -1, 3385, 3387, 3390, 3392, 3395, 3397, 3400, 3403, 3405, 3408, 3410, 3413, 3416, 3419, 3423, 3426, 3430, 3433, 3435, 3438, 3440, 3443, -1, 3445, 3447, 3450, 3452, 3455, 3457, 3459, -1, 3461, -1, -1, -1, 3463, 3466, 3469, 3471, -1, -1, 3473, -1, 3475, 3478, 3480, 3483, 3485, 3488, 3490, -1, -1, 3493, 3495, -1, -1, 3498, 3500, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3503, -1, -1, -1, -1, 3505, 3508, -1, 3511, 3514, 3517, 3520, 3522, -1, -1, 3525, 3527, 3529, 3531, 3533, 3535, 3537, 3539, 3541, 3543, 3545, 3548, 3551, 3554, 3557, 3560, 3563, 3566, 3569, 3577, -1, -1, -1, -1, -1, -1, -1, -1, 3581, -1, -1, 3583, 3585, 3588, 3590, 3593, 3595, -1, -1, -1, -1, 3598, 3601, -1, -1, 3604, 3607, 3610, 3612, 3615, 3617, 3620, 3623, 3625, 3628, 3630, 3633, 3636, 3639, 3643, 3646, 3650, 3653, 3655, 3658, 3660, 3663, -1, 3665, 3667, 3670, 3672, 3675, 3677, 3679, -1, 3681, 3683, -1, 3686, 3688, -1, 3691, 3693, -1, -1, 3695, -1, 3697, 3700, 3702, 3705, 3707, -1, -1, -1, -1, 3710, 3713, -1, -1, 3716, 3719, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3722, 3726, 3730, 3732, -1, 3735, -1, -1, -1, -1, -1, -1, -1, 3737, 3739, 3741, 3743, 3745, 3747, 3749, 3751, 3753, 3755, 3757, 3759, -1, -1, 3761, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3768, 3770, 3772, -1, 3774, 3776, 3779, 3781, 3784, 3786, 3789, -1, 3791, -1, 3794, 3796, 3799, -1, 3802, 3804, 3807, 3809, 3812, 3814, 3817, 3820, 3822, 3825, 3827, 3830, 3833, 3836, 3840, 3843, 3847, 3850, 3852, 3855, 3857, 3860, -1, 3862, 3864, 3867, 3869, 3872, 3874, 3877, -1, 3879, 3881, -1, 3884, 3886, 3889, 3892, 3894, -1, -1, 3896, 3898, 3900, 3903, 3905, 3908, 3910, 3913, 3915, 3918, -1, 3921, 3923, 3926, -1, 3929, 3931, -1, -1, -1, 3934, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3938, -1, -1, -1, -1, -1, 3941, 3943, 3945, 3947, 3949, 3951, 3953, 3955, 3957, 3959, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3961, 3963, 3965, -1, 3967, 3969, 3972, 3974, 3977, 3979, 3982, 3984, -1, -1, 3986, 3988, -1, -1, 3991, 3993, 3996, 3998, 4001, 4003, 4006, 4009, 4011, 4014, 4016, 4019, 4022, 4025, 4029, 4032, 4036, 4039, 4041, 4044, 4046, 4049, -1, 4051, 4053, 4056, 4058, 4061, 4063, 4065, -1, 4067, 4069, -1, -1, 4072, 4075, 4078, 4080, -1, -1, 4082, 4084, 4086, 4089, 4091, 4094, 4096, 4099, -1, -1, -1, 4101, 4103, -1, -1, 4106, 4108, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4111, 4113, -1, -1, -1, -1, 4115, 4118, -1, 4121, 4124, 4127, -1, -1, -1, -1, 4130, 4132, 4134, 4136, 4138, 4140, 4142, 4144, 4146, 4148, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4150, 4152, -1, 4154, 4156, 4159, 4161, 4164, 4166, -1, -1, -1, 4169, 4171, 4174, -1, 4177, 4179, 4182, 4185, -1, -1, -1, 4187, 4190, -1, 4192, -1, 4194, 4197, -1, -1, -1, 4200, 4203, -1, -1, -1, 4205, 4207, 4211, -1, -1, -1, 4213, 4215, 4217, 4219, 4222, 4224, 4227, 4231, -1, 4233, 4236, 4238, -1, -1, -1, -1, 4240, 4243, 4245, 4248, 4250, -1, -1, -1, 4253, 4255, 4258, -1, 4261, 4263, 4266, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4269, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, 4289, 4291, 4296, 4302, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4309, 4311, 4313, -1, 4315, 4317, 4320, 4322, 4325, 4327, 4330, 4332, -1, 4334, 4336, 4339, -1, 4342, 4344, 4347, 4350, 4352, 4355, 4357, 4360, 4363, 4365, 4368, 4370, 4373, 4376, 4379, 4383, 4386, 4390, 4393, 4395, 4398, 4400, 4403, -1, 4405, 4407, 4410, 4412, 4415, 4417, 4419, 4421, 4424, 4426, -1, 4429, 4431, 4434, 4437, 4439, -1, -1, -1, -1, 4441, 4444, 4446, 4449, 4451, 4454, 4456, -1, 4459, 4461, 4464, -1, 4467, 4469, 4472, -1, -1, -1, -1, -1, -1, -1, -1, 4475, 4477, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4479, 4482, -1, -1, -1, -1, 4485, 4487, 4489, 4491, 4493, 4495, 4497, 4499, 4501, 4503, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4505, 4507, -1, 4509, 4511, 4514, 4516, 4519, 4521, 4524, 4526, -1, 4528, 4530, 4533, -1, 4536, 4538, 4541, 4544, 4546, 4549, 4551, 4554, 4557, 4559, 4562, 4564, 4567, 4570, 4573, 4577, 4580, 4584, 4587, 4589, 4592, 4594, 4597, -1, 4599, 4601, 4604, 4606, 4609, 4611, 4613, 4615, 4618, 4620, -1, 4623, 4625, 4628, 4631, 4633, -1, -1, -1, -1, 4635, 4638, 4640, 4643, 4645, 4648, 4650, -1, 4653, 4655, 4658, -1, 4661, 4663, 4666, -1, -1, -1, -1, -1, -1, -1, -1, 4669, 4671, -1, -1, -1, -1, -1, -1, -1, 4673, -1, 4677, 4680, -1, -1, -1, -1, 4683, 4685, 4687, 4689, 4691, 4693, 4695, 4697, 4699, 4701, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4703, 4705, -1, 4707, 4709, 4712, 4714, 4717, 4719, 4722, 4724, -1, 4726, 4728, 4731, -1, 4734, 4736, 4739, 4742, 4744, 4747, 4749, 4752, 4755, 4757, 4760, 4762, 4765, 4768, 4771, 4775, 4778, 4782, 4785, 4787, 4790, 4792, 4795, -1, 4797, 4799, 4802, 4804, 4807, 4809, 4811, 4813, 4816, 4818, 4821, 4825, 4827, 4830, 4833, 4835, -1, -1, -1, -1, 4837, 4840, 4842, 4845, 4847, 4850, -1, -1, 4852, 4854, 4857, -1, 4860, 4862, 4865, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4868, -1, -1, -1, -1, -1, -1, -1, -1, 4870, 4873, -1, -1, -1, -1, 4876, 4878, 4880, 4882, 4884, 4886, 4888, 4890, 4892, 4894, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4896, 4898, -1, 4900, 4902, 4905, 4908, 4912, 4914, 4917, 4919, 4922, 4924, 4927, 4929, 4932, 4934, 4937, 4940, 4942, 4945, -1, -1, -1, 4948, 4950, 4953, 4955, 4958, 4961, 4965, 4967, 4970, 4972, 4975, 4978, 4982, 4986, 4989, 4993, 4996, 5000, 5003, 5008, 5010, 5013, 5015, 5018, -1, 5020, 5023, 5025, 5028, 5030, 5033, 5035, 5038, 5040, -1, 5042, -1, -1, 5044, 5046, 5049, 5052, 5054, 5056, 5059, -1, -1, -1, -1, -1, -1, -1, -1, 5061, 5064, 5067, 5071, 5073, 5076, -1, 5078, -1, 5081, 5083, 5085, 5088, 5091, 5093, 5096, 5099, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5101, 5104, 5107, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5111, 5113, 5116, 5119, 5122, 5125, 5128, 5131, 5135, 5138, 5141, 5144, 5147, 5149, 5151, 5153, 5156, 5159, 5162, 5164, 5166, 5168, 5171, 5174, 5177, 5179, 5181, 5183, 5186, 5188, 5191, 5193, 5196, 5198, 5200, 5202, 5204, 5206, 5208, 5210, 5212, 5214, 5216, 5218, 5220, 5222, 5224, 5226, 5228, 5230, 5233, 5236, 5238, 5241, 5244, 5248, 5250, 5253, -1, -1, -1, -1, 5255, 5259, 5261, 5264, 5266, 5269, 5272, 5275, -1, -1, -1, -1, -1, -1, 5277, -1, 5279, 5283, 5285, 5287, 5289, 5291, 5293, 5295, 5297, 5299, 5301, 5303, 5308, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5314, 5316, -1, 5319, -1, -1, 5322, 5325, -1, 5328, -1, -1, 5330, -1, -1, -1, -1, -1, -1, 5333, 5335, 5337, 5340, -1, 5343, 5345, 5347, 5349, 5352, 5354, 5357, -1, 5359, 5361, 5363, -1, 5365, -1, 5367, -1, -1, 5369, 5371, -1, 5373, -1, 5375, 5377, -1, 5379, 5382, 5385, 5387, 5390, 5392, 5395, 5397, -1, 5400, 5402, 5404, -1, -1, 5407, 5409, 5412, 5414, 5417, -1, 5420, -1, -1, -1, -1, -1, -1, 5422, -1, -1, 5424, 5426, 5428, 5430, 5432, 5434, 5436, 5438, 5440, 5442, -1, -1, 5444, 5447, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5450, -1, -1, -1, -1, -1, -1, -1, 5454, 5459, -1, 5463, 5465, 5469, 5473, 5478, 5483, 5488, 5493, 5500, 5506, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5509, 5511, 5513, 5515, 5517, 5519, 5521, 5523, 5525, 5527, 5529, 5532, 5536, 5540, 5544, 5548, 5552, 5556, 5560, 5564, 5568, 5570, 5572, 5574, -1, 5576, -1, 5578, 5580, 5583, -1, -1, 5586, 5588, 5591, 5593, 5596, 5599, 5601, 5604, -1, 5606, 5609, 5612, 5616, 5619, 5623, 5626, 5628, 5631, 5633, 5636, 5638, 5640, 5643, 5645, 5648, 5650, 5653, 5657, 5660, 5664, 5666, 5669, 5671, 5673, 5675, 5677, 5679, 5682, 5686, 5688, 5690, 5692, 5696, -1, -1, -1, -1, -1, -1, 5698, 5701, 5703, 5706, 5708, 5711, 5713, 5716, 5718, 5721, 5723, 5726, 5728, 5731, 5733, 5735, 5737, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5740, 5742, 5745, 5747, 5750, 5753, 5755, 5758, -1, 5760, 5763, 5766, 5770, 5773, 5777, 5780, 5782, 5785, 5787, 5790, 5792, 5794, 5797, 5799, 5802, 5804, 5807, 5811, 5814, 5818, 5820, 5823, 5825, 5827, 5829, 5831, 5833, 5836, 5839, 5841, 5843, 5845, 5849, 5851, 5853, -1, 5855, 5857, 5863, 5869, 5875, 5881, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5887, 5889, 5892, 5894, 5897, 5900, 5902, 5905, 5907, 5910, 5913, 5917, 5920, 5924, 5927, 5931, 5934, 5937, 5940, 5942, 5945, 5947, 5949, 5952, 5954, 5957, 5959, 5961, 5963, 5965, 5967, 5969, 5971, 5974, -1, 5976, 5978, 5981, 5983, 5986, -1, 5988, 5990, -1, 5993, 5996, 5998, 6001, 6003, 6006, 6008, -1, -1, -1, 6011, 6013, 6015, -1, -1, -1, -1, -1, -1, -1, 6017, 6019, 6021, 6023, 6025, 6027, 6029, 6031, 6033, 6035, 6037, 6041, 6046, 6049, 6052, 6055, 6058, 6061, 6064, 6066, 6069, 6071, 6074, 6076, 6079, 6081, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6084, 6086, 6088, 6090, 6092, 6094, 6096, 6098, 6101, 6103, 6105, 6107, 6109, 6111, 6113, 6115, 6118, 6120, 6122, 6124, 6126, 6129, 6132, 6135, 6137, 6140, 6144, 6147, 6150, 6152, 6155, 6157, 6159, 6161, 6163, 6165, 6167, 6170, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6173, 6175, 6177, 6179, 6181, 6183, 6185, 6187, 6190, 6192, 6194, 6196, 6198, 6200, 6202, 6204, 6207, 6209, 6211, 6213, 6215, 6218, 6221, 6224, 6226, 6229, 6233, 6236, 6239, 6241, 6244, 6246, 6248, 6250, 6252, 6254, 6256, 6259, 6262, -1, -1, -1, -1, 6264, -1, -1, -1, -1, 6269, 6271, 6274, 6276, 6278, 6281, 6283, 6285, 6287, 6290, 6292, -1, 6295, 6297, 6300, 6302, 6304, 6306, 6308, 6310, 6313, 6316, 6319, 6322, 6325, 6328, 6331, 6334, 6337, 6340, 6343, 6346, -1, 6349, 6352, 6356, 6360, 6364, 6368, 6372, 6375, 6378, 6381, 6384, 6387, 6391, 6394, 6397, 6400, 6403, 6406, 6409, 6413, 6417, 6419, 6422, 6425, 6428, 6431, 6434, -1, -1, -1, -1, 6437, 6439, 6441, 6443, 6445, 6447, 6449, -1, 6451, 6453, 6455, 6457, 6459, 6461, -1, -1, -1, -1, 6463, 6466, -1, -1, 6469, 6472, 6475, 6478, -1, -1, -1, -1, -1, -1, -1, 6480, 6482, 6485, 6488, 6492, 6495, 6497, 6501, 6504, 6506, 6509, 6513, 6516, 6519, 6521, 6525, 6528, 6531, 6534, 6537, 6540, 6542, 6546, 6550, 6555, 6561, 6566, 6571, 6577, 6583, 6589, 6594, 6598, 6603, 6607, 6611, 6617, 6624, 6631, 6636, 6641, 6645, 6650, 6658, 6663, 6667, 6672, 6678, 6683, 6690, 6696, 6701, 6706, 6711, 6717, 6722, 6726, 6731, 6735, 6739, 6744, 6748, 6750, 6755, 6759, 6763, -1, -1, -1, -1, -1, 6766, 6768, 6771, 6774, 6776, 6779, 6782, 6784, 6786, 6789, 6792, 6795, 6798, 6801, 6804, 6807, 6809, 6811, 6814, 6816, 6819, 6822, 6824, 6826, 6828, 6830, 6832, 6834, 6837, 6841, 6844, 6847, 6850, 6853, 6856, 6859, 6862, 6866, 6869, 6872, 6876, 6879, 6883, 6887, 6891, 6895, 6899, 6903, 6906, 6909, 6912, 6915, 6918, 6921, 6924, 6928, 6931, 6934, 6937, 6940, 6943, 6946, 6949, 6952, 6955, 6958, 6961, 6964, 6966, 6968, -1, 6971, 6974, 6976, 6979, 6982, 6985, 6988, 6991, 6994, 6997, 7000, -1, -1, -1, -1, -1, -1, 7002, 7005, 7008, 7011, 7015, 7019, 7022, -1, 7025, 7028, 7031, 7034, 7038, 7042, 7045, 7048, 7052, 7056, 7060, 7064, 7069, 7074, 7078, 7082, 7087, 7090, 7093, 7096, 7100, 7104, 7107, 7110, 7114, 7118, 7122, 7126, 7131, 7136, 7140, 7144, 7149, 7152, 7155, 7158, 7162, 7166, 7169, 7172, 7176, 7179, 7182, 7185, 7189, 7193, 7196, 7199, 7203, 7207, 7211, 7215, 7220, 7225, 7229, 7233, 7238, 7241, 7244, 7247, 7251, 7255, 7258, -1, 7261, -1, 7265, 7269, 7274, 7279, -1, -1, 7283, 7287, 7291, 7295, 7300, 7305, 7309, -1, 7313, -1, 7318, 7323, 7329, 7335, -1, -1, 7340, 7343, 7346, 7349, 7353, 7357, 7360, 7363, 7367, 7370, 7373, 7376, 7380, 7384, 7387, 7390, 7394, 7397, 7400, 7403, 7407, 7411, 7414, 7417, 7421, 7424, 7427, 7430, 7434, 7438, 7441, 7444, 7448, 7451, 7454, 7457, 7461, 7465, 7468, -1, 7471, -1, 7475, 7479, 7484, 7489, -1, -1, 7493, 7496, 7499, 7502, 7506, 7510, 7513, 7516, 7520, 7524, 7528, 7532, 7537, 7542, 7546, 7550, 7555, 7558, -1, 7561, 7565, 7569, 7572, 7575, 7579, 7582, 7585, 7588, 7592, 7596, 7599, -1, 7602, -1, 7606, 7610, 7615, 7620, -1, -1, 7624, 7628, 7632, 7636, 7641, 7646, 7650, -1, 7654, -1, 7659, 7664, 7670, 7676, -1, -1, 7681, 7684, 7687, 7690, 7694, 7698, 7701, -1, 7704, 7707, 7710, 7713, 7717, 7721, 7724, -1, 7727, 7730, 7733, 7736, 7740, 7744, 7747, 7750, 7754, 7758, 7762, 7766, 7771, 7776, 7780, 7784, 7789, 7792, 7795, 7798, 7802, 7806, 7809, -1, 7812, 7815, 7818, 7821, 7825, 7829, 7832, 7835, 7839, 7843, 7847, 7851, 7856, 7861, 7865, 7869, 7874, 7877, 7880, 7883, 7887, 7891, 7894, 7897, 7901, 7904, 7907, 7910, 7914, 7918, 7921, -1, 7924, -1, 7928, 7932, 7937, 7942, -1, -1, 7946, 7950, 7954, 7958, 7963, 7968, 7972, -1, 7976, 7980, 7984, 7988, 7993, 7998, 8002, 8006, 8011, 8015, 8019, 8023, 8028, 8033, 8037, 8041, 8046, 8050, 8054, 8058, 8063, 8068, 8072, 8076, 8081, 8085, 8089, 8093, 8098, 8103, 8107, 8111, 8116, 8120, 8124, 8128, 8133, 8138, 8142, -1, 8146, 8149, 8152, 8155, 8159, 8163, 8166, 8169, 8173, 8176, 8179, 8182, 8186, 8190, 8193, 8196, 8200, 8204, 8208, -1, -1, -1, -1, -1, -1, 8212, 8214, 8216, 8218, 8220, 8222, 8226, 8228, 8231, 8233, 8235, 8237, 8239, 8241, 8243, 8245, 8247, 8249, 8253, 8257, 8261, 8265, 8269, 8273, 8277, 8281, 8285, 8290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8298, 8300, 8302, 8304, 8306, 8308, 8310, 8313, 8316, 8319, 8322, 8325, 8328, 8331, 8334, 8337, 8340, 8343, 8346, 8349, 8352, 8355, 8358, 8361, 8364, 8367, 8370, 8373, 8376, 8379, 8382, 8385, 8389, 8393, 8396, 8399, 8402, 8405, 8408, 8412, 8416, 8420, 8424, 8428, 8432, 8435, 8437, 8440, 8443, 8446, 8449, 8452, 8455, 8458, 8461, 8464, 8467, 8470, 8473, 8476, 8479, 8483, 8487, 8491, 8495, 8499, 8503, 8507, 8511, 8515, 8519, 8523, 8527, 8531, 8534, 8537, 8540, 8543, 8546, 8549, 8552, 8555, 8558, 8561, 8564, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8567, 8569, 8573, 8575, 8578, 8580, 8583, 8586, 8589, 8591, 8593, 8596, 8599, 8602, 8605, 8608, 8612, 8616, 8619, 8622, 8626, 8630, 8634, 8637, 8640, 8644, 8648, 8652, 8655, 8657, 8659, 8661, 8663, 8666, 8668, 8670, 8672, -1, 8674, 8676, 8678, 8680, 8682, 8685, 8688, 8691, 8694, 8697, 8702, 8705, 8709, 8712, 8716, 8720, 8724, 8727, 8730, 8734, 8738, 8742, 8746, 8750, 8755, 8760, 8764, 8768, 8773, 8778, 8782, 8786, 8791, 8796, 8801, 8803, 8805, 8807, 8810, 8815, 8818, 8822, 8825, 8829, 8833, 8837, 8840, 8843, 8847, 8851, 8855, 8859, 8863, 8868, 8873, 8877, 8881, 8886, 8891, 8895, 8899, 8904, 8909, 8914, 8916, 8920, 8924, 8928, 8932, 8935, 8940, 8943, 8947, 8950, 8954, 8958, 8961, 8965, 8969, 8973, 8977, 8981, 8986, 8991, 8995, 8999, 9004, 9009, 9013, 9017, 9022, 9027, 9032, 9034, 9037, 9041, 9045, 9049, 9053, 9056, 9061, 9064, 9068, 9071, 9075, 9079, 9082, 9086, 9090, 9094, 9098, 9102, 9107, 9112, 9116, 9120, 9125, 9130, 9134, 9138, 9143, 9148, 9153, 9155, 9158, 9161, 9166, 9169, 9173, 9176, 9180, 9184, 9187, 9191, 9195, 9199, 9203, 9207, 9212, 9217, 9221, 9225, 9230, 9235, 9239, 9243, 9248, 9253, 9258, 9260, 9262, 9265, 9267, 9269, 9272, 9277, 9280, 9284, 9287, 9291, 9295, 9298, 9302, 9306, 9310, 9314, 9318, 9323, 9328, 9333, 9335, 9338, 9341, 9344, 9349, 9352, 9356, 9359, 9363, 9367, 9370, 9374, 9378, 9382, 9386, 9390, 9395, 9400, 9404, 9408, 9413, 9418, 9422, 9426, 9431, 9436, 9438, 9440, 9442, 9445, 9450, 9453, 9457, 9460, 9464, 9468, 9471, 9475, 9479, 9483, 9487, 9491, 9496, 9501, 9505, 9509, 9514, 9519, 9523, 9527, 9532, 9537, 9542, 9544, 9546, 9549, 9551, 9554, 9558, 9561, 9566, 9571, 9576, 9581, 9585, 9589, 9594, 9598, 9603, 9607, 9612, 9617, 9622, 9627, 9632, 9638, 9644, 9649, 9654, 9660, 9666, 9671, 9676, 9682, 9688, 9691, 9694, 9699, 9702, 9706, 9709, 9713, 9717, 9720, 9724, 9728, 9732, 9736, 9740, 9745, 9750, 9754, 9758, 9763, 9768, 9772, 9776, 9781, 9786, 9791, 9793, 9795, 9797, 9800, 9803, 9806, 9809, 9814, 9817, 9821, 9824, 9828, 9831, 9834, 9838, 9841, 9846, 9851, 9853, 9855, 9857, 9860, 9865, 9868, 9872, 9875, 9879, 9882, 9886, 9891, 9896, 9898, 9902, 9906, 9910, 9914, 9919, 9924, 9928, 9933, 9937, 9942, 9948, 9954, 9957, 9962, 9967, 9972, 9977, 9981, 9985, 9989, 9993, 9997, 10000, 10003, 10007, 10010, 10014, 10017, 10021, 10023, 10025, 10028, 10033, 10036, 10040, 10043, 10047, 10050, 10054, 10056, 10061, 10066, 10071, 10076, 10079, 10082, 10085, 10088, 10094, 10098, 10103, 10107, 10112, 10116, 10121, 10124, 10128, 10132, 10136, 10140, 10144, 10148, 10152, 10156, 10160, 10163, 10167, 10172, 10176, 10181, 10185, 10190, 10193, 10197, 10201, 10206, 10210, 10215, 10219, 10224, 10227, 10229, 10231, 10233, 10235, 10237, 10240, 10243, 10246, 10249, 10252, 10255, 10258, 10261, 10264, 10267, 10270, 10273, 10276, 10279, 10282, 10285, 10289, 10293, 10297, 10302, 10306, 10310, 10313, 10316, 10319, 10323, 10326, 10329, 10332, 10335, 10338, 10342, 10345, 10348, 10352, 10356, 10360, 10365, 10369, 10373, 10377, 10381, 10385, 10390, 10394, 10398, 10402, 10406, 10410, 10415, 10419, 10423, 10426, 10429, 10432, 10436, 10439, 10442, 10444, 10447, 10450, 10453, 10457, 10460, 10463, 10467, 10471, 10475, 10480, 10484, 10488, 10492, 10496, 10500, 10505, 10509, 10513, 10516, 10519, 10522, 10525, 10529, 10532, 10535, 10538, 10541, 10544, 10548, 10551, 10554, 10557, 10560, 10563, 10567, 10570, 10573, 10576, 10579, 10582, 10585, 10589, 10592, 10595, 10598, 10602, 10606, 10610, 10615, 10619, 10623, 10626, 10629, 10632, 10636, 10639, 10642, 10646, 10650, 10654, 10659, 10663, 10667, 10671, 10675, 10679, 10684, 10688, 10692, 10697, 10702, 10707, 10713, 10718, 10723, 10727, 10731, 10735, 10740, 10744, 10748, 10751, 10754, 10757, 10761, 10764, 10767, 10769, 10771, 10775, 10779, 10783, 10788, 10792, 10796, 10799, 10802, 10805, 10809, 10812, 10815, 10819, 10823, 10827, 10832, 10836, 10840, 10843, 10847, 10851, 10855, 10860, 10864, 10868, 10872, 10876, 10880, 10885, 10889, 10893, 10898, 10903, 10908, 10914, 10919, 10924, 10926, 10928, 10932, 10937, 10942, 10948, 10953, 10959, 10964, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10970, 10972, 10974, 10976, 10978, 10980, 10982, 10984, 10986, 10988, 10990, 10992, 10994, 10996, 10999, 11001, 11003, 11005, 11007, 11009, 11011, 11013, 11016, 11019, 11022, 11024, 11026, 11028, 11030, -1, -1, -1, 11032, 11034, 11036, 11038, 11041, 11043, 11045, 11048, 11051, 11053, 11055, 11058, 11061, 11063, 11065, 11067, 11070, 11073, 11075, 11077, 11079, 11081, 11083, 11086, 11088, 11090, 11092, 11094, 11096, 11098, 11100, 11102, 11104, 11106, 11108, 11110, 11112, 11114, 11117, 11119, 11122, 11124, 11126, 11128, 11130, 11132, 11134, 11136, 11138, 11140, 11142, 11144, 11146, 11148, 11150, 11152, 11154, 11156, 11158, 11160, 11162, 11165, 11168, 11170, 11172, 11176, 11180, 11183, 11186, 11189, 11191, 11194, 11197, 11200, 11202, 11204, 11206, 11208, 11210, 11213, 11216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11219, 11221, 11224, 11226, 11229, 11232, 11234, 11237, 11239, 11242, 11245, 11247, 11251, 11253, 11257, 11260, 11262, 11265, 11267, 11270, 11272, 11274, 11277, 11279, 11282, 11284, 11286, 11288, 11290, 11292, 11295, 11298, 11300, 11302, 11304, 11306, 11308, 11311, 11313, 11316, 11318, 11321, 11324, 11328, 11331, 11335, 11338, 11342, 11344, 11347, 11350, 11353, 11356, 11358, 11361, 11364, 11366, 11369, 11371, 11374, 11376, 11379, 11382, 11385, 11388, 11391, 11393, 11396, 11399, 11402, 11405, 11407, 11409, -1, -1, -1, 11412, -1, 11414, -1, -1, -1, -1, -1, 11416, 11418, 11423, 11425, 11427, 11430, 11434, 11440, 11443, -1, -1, -1, 11445, 11447, 11449, 11451, 11453, 11455, 11457, 11459, 11461, 11463, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11465, 11469, 11475, 11478, 11481, 11484, -1, 11489, 11491, 11494, -1, -1, -1, -1, -1, -1, 11497, 11499, 11501, 11503, 11505, 11507, 11509, 11511, 11513, 11515, -1, -1, -1, -1, -1, -1, 11517, 11519, 11521, 11523, 11525, 11527, 11529, 11531, 11534, 11536, 11539, 11541, 11543, 11545, 11547, 11549, 11551, 11553, 11556, 11558, 11560, 11563, 11565, 11567, 11569, 11571, 11573, 11575, 11579, 11582, 11584, 11586, 11589, 11592, 11595, 11598, 11600, 11602, 11604, 11606, 11608, 11610, 11612, 11615, 11617, 11619, 11621, 11623, 11625, 11627, 11629, 11632, 11634, 11637, 11639, 11641, 11643, 11645, 11647, 11650, 11653, 11656, 11658, 11660, 11663, 11665, 11667, 11670, 11672, 11674, 11676, 11678, 11681, 11683, 11685, 11687, 11689, 11691, 11693, 11696, 11698, 11700, 11703, 11706, 11708, 11710, 11712, 11714, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11717, 11719, 11721, 11723, 11725, 11729, 11735, 11737, 11739, 11741, 11744, 11746, 11749, 11753, 11756, 11759, 11761, 11763, 11765, 11768, 11771, 11774, 11776, 11778, 11780, 11783, 11786, 11789, 11791, 11794, 11798, 11802, 11804, 11807, 11810, 11813, 11816, 11818, 11820, 11822, 11825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11827, 11829, 11832, 11835, 11837, 11839, 11841, 11843, 11845, 11847, 11849, 11851, 11853, 11855, 11857, 11859, -1, 11861, -1, 11863, 11865, 11868, -1, -1, 11871, 11873, 11875, 11877, 11879, 11881, 11883, 11885, 11887, 11889, 11891, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11893, 11895, 11898, 11900, 11902, 11904, 11906, 11908, 11910, 11912, 11914, 11916, 11918, 11920, 11922, 11924, 11926, 11928, 11931, 11933, 11935, 11937, 11939, 11941, 11943, 11945, 11947, 11950, 11952, 11954, -1, 11956, 11958, 11960, 11962, 11964, 11966, -1, 11968, -1, -1, -1, 11970, 11972, 11974, 11976, 11978, 11980, -1, 11982, 11984, 11986, 11988, -1, 11990, 11992, 11994, 11996, 11998, 12000, 12002, 12004, -1, -1, 12006, 12008, 12010, 12012, 12014, 12016, 12018, 12020, 12022, 12024, 12026, 12028, -1, -1, -1, -1, -1, 12030, -1, -1, 12032, 12034, 12036, 12038, 12040, 12042, 12044, 12046, 12048, 12050, 12052, -1, 12054, 12056, 12058, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12060, 12062, 12064, 12066, 12068, 12070, 12072, 12074, 12076, 12078, 12080, 12082, 12084, 12086, 12088, 12090, 12092, 12094, 12096, 12098, 12100, 12102, 12104, 12106, 12108, 12110, 12112, 12114, 12116, 12118, 12120, 12122, 12124, 12126, 12128, 12130, 12132, 12134, 12136, 12138, 12140, 12142, 12144, 12146, 12148, 12150, 12152, 12154, 12156, 12158, 12160, 12162, 12164, 12166, 12168, 12170, 12172, 12174, 12176, 12178, 12180, 12182, 12184, 12186, 12188, 12190, 12192, 12194, 12196, 12198, 12200, 12202, 12204, 12206, 12208, 12210, 12212, 12214, 12216, 12218, 12220, 12222, 12224, 12226, 12228, 12230, 12232, 12234, 12236, 12238, 12240, 12242, 12244, 12246, 12248, 12250, 12252, 12254, 12256, 12258, 12260, 12262, 12264, 12266, 12268, 12270, 12272, 12274, 12276, 12278, 12280, 12282, 12284, 12286, 12288, 12290, 12292, 12294, 12296, 12298, 12300, 12302, 12304, 12306, 12308, 12310, 12312, 12314, 12316, 12318, 12320, 12322, 12324, 12326, 12328, 12330, 12332, 12334, 12336, 12338, 12340, 12342, 12344, 12346, 12348, 12350, 12352, 12354, 12356, 12358, 12360, 12362, 12364, 12366, 12368, 12370, -1, -1, 12372, -1, 12375, 12377, 12379, 12381, 12383, 12385, 12387, 12389, 12391, 12393, 12395, 12397, 12399, 12401, 12403, 12405, 12407, 12409, 12411, 12413, 12415, 12417, 12419, 12421, 12423, 12425, 12427, 12429, 12431, 12433, 12435, 12437, 12439, 12441, 12443, 12445, 12447, 12449, 12451, 12453, 12455, 12457, 12459, 12461, 12463, 12465, 12467, 12469, 12471, 12473, 12475, 12477, 12479, 12481, 12483, 12485, 12487, 12489, 12491, 12493, 12495, 12497, 12499, 12501, 12503, 12505, 12507, 12509, 12511, 12513, 12515, 12517, 12519, 12521, 12523, 12525, 12527, 12529, 12531, 12533, 12535, 12537, 12539, 12541, 12543, 12545, 12547, 12549, 12551, 12553, -1, -1, -1, -1, -1, -1, 12555, 12557, 12559, 12561, 12563, 12565, 12567, 12569, 12571, 12573, 12575, 12577, 12579, 12581, 12583, 12585, 12587, 12589, 12591, 12593, 12595, 12597, -1, -1, 12599, 12601, 12603, 12605, 12607, 12609, -1, -1, 12611, 12613, 12615, 12617, 12619, 12621, 12623, 12625, 12627, 12629, 12631, 12633, 12635, 12637, 12639, 12641, 12643, 12645, 12647, 12649, 12651, 12653, 12655, 12657, 12659, 12661, 12663, 12665, 12667, 12669, 12671, 12673, 12675, 12677, 12679, 12681, 12683, 12685, -1, -1, 12687, 12689, 12691, 12693, 12695, 12697, -1, -1, 12699, 12701, 12703, 12705, 12707, 12709, 12711, 12713, -1, 12715, -1, 12717, -1, 12719, -1, 12721, 12723, 12725, 12727, 12729, 12731, 12733, 12735, 12737, 12739, 12741, 12743, 12745, 12747, 12749, 12751, 12753, 12755, 12757, 12759, 12761, 12763, 12765, 12767, 12769, 12771, 12773, 12775, 12777, 12779, 12781, -1, -1, 12783, 12785, 12787, 12789, 12791, 12793, 12795, 12797, 12799, 12801, 12803, 12805, 12807, 12809, 12811, 12813, 12815, 12817, 12819, 12821, 12823, 12825, 12827, 12829, 12831, 12833, 12835, 12837, 12839, 12841, 12843, 12845, 12847, 12849, 12851, 12853, 12855, 12857, 12859, 12861, 12863, 12865, 12867, 12869, 12871, 12873, 12875, 12877, 12879, 12881, 12883, 12885, 12887, -1, 12889, 12891, 12893, 12895, 12897, 12899, 12901, 12903, 12905, 12907, 12909, 12911, 12914, 12916, 12918, -1, 12920, 12922, 12924, 12926, 12928, 12930, 12932, 12934, 12937, 12940, 12943, 12945, 12947, 12949, -1, -1, 12951, 12953, 12955, 12957, 12959, 12961, -1, 12963, 12966, 12969, 12972, 12974, 12976, 12978, 12980, 12982, 12984, 12986, 12988, 12990, 12992, 12994, 12996, 12998, 13001, 13004, -1, -1, 13006, 13008, 13010, -1, 13012, 13014, 13016, 13018, 13020, 13022, 13024, 13026, 13028, -1, 13030, 13032, 13034, 13036, 13038, 13040, 13042, 13044, 13046, 13048, 13050, 13052, -1, -1, -1, -1, 13054, 13056, 13058, 13060, 13062, 13065, 13068, 13071, 13073, 13075, 13077, 13079, 13081, 13083, 13085, 13088, 13090, 13092, 13095, 13097, 13100, 13102, 13105, 13109, 13111, 13113, -1, -1, -1, -1, -1, 13116, 13118, 13121, 13125, 13127, 13130, 13134, 13136, 13139, 13143, 13145, 13147, 13149, 13151, 13154, 13157, 13159, 13161, 13163, 13165, 13169, 13172, 13174, 13177, 13180, 13183, 13186, 13189, 13191, 13194, 13197, 13200, -1, -1, -1, 13202, 13204, -1, -1, -1, 13206, -1, -1, -1, -1, -1, -1, -1, 13211, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13213, 13215, -1, -1, 13217, 13219, 13221, 13223, 13225, 13227, 13229, 13231, 13233, 13235, 13237, 13239, 13241, 13243, 13245, 13247, 13249, 13251, 13253, 13255, 13257, 13259, 13261, 13263, 13265, 13267, 13269, -1, 13271, 13273, 13275, 13277, -1, 13279, 13281, 13283, 13285, 13287, 13289, 13291, 13293, -1, -1, -1, 13295, 13299, 13302, 13305, 13308, 13310, 13314, 13316, 13320, 13323, 13325, 13328, 13330, 13334, 13336, 13338, 13341, 13344, 13346, 13348, 13350, 13354, 13357, 13359, 13362, 13364, 13367, 13369, 13371, 13373, 13375, 13377, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13381, 13387, 13393, -1, -1, 13395, 13401, -1, -1, -1, 13407, 13409, 13411, 13413, 13415, -1, 13417, 13419, 13421, 13423, -1, 13425, 13427, -1, -1, 13432, 13434, 13436, 13438, 13440, -1, -1, 13442, 13447, 13451, -1, 13456, -1, -1, -1, 13458, -1, 13460, 13462, 13464, 13466, 13468, 13470, 13472, 13474, 13476, 13478, 13480, -1, -1, -1, -1, 13482, -1, 13484, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13488, 13490, 13492, 13494, 13496, -1, -1, -1, -1, 13498, -1, 13500, 13506, 13512, 13519, 13525, 13531, 13537, 13543, 13549, 13555, 13561, 13567, 13573, 13579, 13585, 13591, 13595, 13597, 13600, 13604, 13607, 13609, 13612, 13616, 13621, 13624, 13626, 13629, 13633, 13635, 13637, 13639, 13641, 13643, 13646, 13650, 13653, 13655, 13658, 13662, 13667, 13670, 13672, 13675, 13679, 13681, 13683, 13685, 13687, 13690, 13693, 13699, -1, -1, -1, -1, -1, 13701, -1, -1, -1, -1, -1, -1, 13707, 13709, 13711, 13713, 13715, 13717, 13719, 13721, 13723, 13725, 13727, 13729, 13731, 13733, 13735, 13737, 13739, 13741, 13743, 13745, 13747, 13749, 13751, 13753, 13755, 13757, 13759, 13761, 13763, 13765, 13767, 13769, 13771, 13773, 13775, 13777, 13779, 13781, 13783, 13785, 13787, 13789, 13791, 13793, 13795, 13797, 13799, 13801, 13803, 13805, 13807, 13809, 13811, 13813, 13815, 13817, 13819, 13821, 13823, 13825, 13827, 13829, 13831, 13833, 13835, 13837, 13839, 13841, 13843, 13845, 13847, 13849, 13851, 13853, 13855, 13857, 13859, 13861, 13863, 13865, 13867, 13869, 13871, 13873, 13875, 13877, 13879, 13881, 13883, 13885, 13887, 13889, 13891, 13893, 13895, 13897, 13899, 13901, 13903, 13905, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13907, -1, -1, 13909, 13911, 13913, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13915, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13917, -1, -1, -1, -1, -1, 13919, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13921, 13924, 13927, 13930, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13933, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13935, 13937, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13940, 13942, 13944, 13946, 13948, 13950, 13952, 13954, 13956, 13958, 13961, 13964, 13967, 13970, 13973, 13976, 13979, 13982, 13985, 13988, 13991, 13995, 13999, 14003, 14007, 14011, 14015, 14019, 14023, 14027, 14032, 14037, 14042, 14047, 14052, 14057, 14062, 14067, 14072, 14077, 14082, 14085, 14088, 14091, 14094, 14097, 14100, 14103, 14106, 14109, 14113, 14117, 14121, 14125, 14129, 14133, 14137, 14141, 14145, 14149, 14153, 14157, 14161, 14165, 14169, 14173, 14177, 14181, 14185, 14189, 14193, 14197, 14201, 14205, 14209, 14213, 14217, 14221, 14225, 14229, 14233, 14237, 14241, 14245, 14249, 14253, 14257, 14259, 14261, 14263, 14265, 14267, 14269, 14271, 14273, 14275, 14277, 14279, 14281, 14283, 14285, 14287, 14289, 14291, 14293, 14295, 14297, 14299, 14301, 14303, 14305, 14307, 14309, 14311, 14313, 14315, 14317, 14319, 14321, 14323, 14325, 14327, 14329, 14331, 14333, 14335, 14337, 14339, 14341, 14343, 14345, 14347, 14349, 14351, 14353, 14355, 14357, 14359, 14361, 14363, 14366, 14369, 14372, 14375, 14378, 14381, 14384, 14387, 14390, 14393, 14395, 14397, 14399, 14401, 14403, 14405, 14407, 14409, 14411, 14414, 14416, 14418, 14420, 14422, 14424, 14426, 14428, 14430, 14432, 14434, 14436, 14438, 14440, 14442, 14444, 14446, 14448, 14450, 14452, 14454, 14456, 14458, 14460, 14462, 14464, 14466, 14468, 14470, 14472, 14474, 14476, 14478, 14480, 14482, 14484, 14486, 14488, 14490, 14492, 14494, 14496, 14498, 14500, 14502, 14504, 14506, 14508, 14510, 14512, 14514, 14516, 14518, 14520, 14522, 14524, 14526, 14528, 14530, 14532, 14534, 14536, 14538, 14540, 14542, 14544, 14546, 14548, 14550, 14552, 14554, 14556, 14558, 14560, 14562, 14564, 14566, 14568, 14570, 14572, 14574, 14576, 14578, 14580, 14582, 14584, 14586, 14588, 14590, 14592, 14594, 14596, 14598, 14600, 14602, 14604, 14606, 14608, 14610, 14612, 14614, 14616, 14618, 14620, 14622, 14624, 14626, 14628, 14630, 14632, 14634, 14636, 14638, 14640, 14642, 14644, 14646, 14648, 14650, 14652, 14654, 14656, 14658, 14660, 14662, 14664, 14666, 14668, 14670, 14672, 14674, 14676, 14678, 14680, 14682, 14684, 14686, 14688, 14690, 14692, 14694, 14696, 14698, 14700, 14702, 14704, 14706, 14708, 14710, 14712, 14714, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14716, 14718, 14720, 14722, 14724, 14726, 14728, 14730, 14732, 14734, 14736, 14738, 14740, 14742, 14744, 14746, 14748, 14750, 14752, 14754, 14756, 14758, 14760, 14762, 14764, 14766, 14768, 14770, 14772, 14774, 14776, 14778, 14780, 14782, 14784, 14786, 14788, 14790, 14792, 14794, 14796, 14798, 14800, 14802, 14804, 14806, 14808, 14810, 14812, 14814, 14816, 14818, 14820, 14822, 14824, 14826, 14828, 14830, 14832, 14834, 14836, 14838, 14840, 14842, 14844, 14846, 14848, 14850, 14852, 14854, 14856, 14858, 14860, 14862, 14864, 14866, 14868, 14870, 14872, 14874, 14876, 14878, 14880, 14882, 14884, 14886, 14888, 14890, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14892, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14894, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14896, -1, -1, -1, 14898, 14900, 14902, 14904, 14906, -1, 14909, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14911, -1, 14913, 14915, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14918, 14920, 14922, 14924, 14926, 14928, 14930, 14932, 14934, 14936, 14938, 14940, 14942, 14944, 14946, 14948, 14950, 14952, 14954, 14956, 14958, 14960, 14962, 14964, 14966, 14968, 14970, 14972, 14974, 14976, 14978, 14980, 14982, 14984, 14986, 14988, 14990, 14992, 14994, 14996, 14998, 15000, 15002, 15004, 15006, 15008, 15010, 15012, 15014, 15016, 15018, 15020, 15022, 15024, 15026, 15028, 15030, 15032, 15034, 15036, 15038, 15040, 15042, 15044, 15046, 15051, 15057, 15063, 15070, 15076, 15083, 15090, 15098, 15104, 15111, 15118, 15126, 15133, 15141, 15149, 15158, 15164, 15171, 15178, 15186, 15193, 15201, 15209, 15218, 15225, 15233, 15241, 15250, 15258, 15267, 15276, 15286, 15292, 15299, 15306, 15314, 15321, 15329, 15337, 15346, 15353, 15361, 15369, 15378, 15386, 15395, 15404, 15414, 15421, 15429, 15437, 15446, 15454, 15463, 15472, 15482, 15490, 15499, 15508, 15518, 15527, 15537, 15547, 15558, 15563, 15569, 15575, 15582, 15588, 15595, 15602, 15610, 15616, 15623, 15630, 15638, 15645, 15653, 15661, 15670, 15676, 15683, 15690, 15698, 15705, 15713, 15721, 15730, 15737, 15745, 15753, 15762, 15770, 15779, 15788, 15798, 15804, 15811, 15818, 15826, 15833, 15841, 15849, 15858, 15865, 15873, 15881, 15890, 15898, 15907, 15916, 15926, 15933, 15941, 15949, 15958, 15966, 15975, 15984, 15994, 16002, 16011, 16020, 16030, 16039, 16049, 16059, 16070, 16076, 16083, 16090, 16098, 16105, 16113, 16121, 16130, 16137, 16145, 16153, 16162, 16170, 16179, 16188, 16198, 16205, 16213, 16221, 16230, 16238, 16247, 16256, 16266, 16274, 16283, 16292, 16302, 16311, 16321, 16331, 16342, 16349, 16357, 16365, 16374, 16382, 16391, 16400, 16410, 16418, 16427, 16436, 16446, 16455, 16465, 16475, 16486, 16494, 16503, 16512, 16522, 16531, 16541, 16551, 16562, 16571, 16581, 16591, 16602, 16612, 16623, 16634, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16646, 16648, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16651, 16655, 16658, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16662, 16664, 16666, 16668, 16670, 16672, 16674, 16676, 16678, 16680, 16682, 16684, 16686, -1, 16688, 16690, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16692, 16694, -1, -1, -1, -1, 16697, 16699, -1, 16702, -1, 16704, 16707, 16709, -1, 16711, -1, -1, 16714, 16716, -1, -1, 16718, 16720, -1, 16722, 16724, 16726, 16728, 16730, 16732, 16734, 16736, 16739, -1, -1, -1, -1, 16742, 16745, 16748, 16751, -1, -1, 16754, -1, 16757, 16759, 16761, 16763, 16765, 16767, 16769, 16771, -1, -1, -1, -1, 16773, 16778, 16785, 16787, -1, -1, 16789, 16791, 16793, 16795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16799, 16801, 16804, 16807, 16809, 16815, 16817, 16819, 16821, 16823, 16826, 16829, 16833, 16835, 16838, 16840, 16843, 16846, 16850, 16852, 16855, 16857, 16860, 16863, 16867, 16870, 16874, 16877, 16881, 16884, 16887, 16890, 16893, 16895, 16897, 16899, 16901, 16903, 16905, 16907, 16909, 16911, -1, -1, -1, -1, -1, -1, 16913, 16915, 16917, 16919, 16921, -1, 16923, 16925, 16930, 16935, 16940, -1, -1, -1, -1, -1, -1, 16945, 16947, 16949, 16951, 16953, 16955, 16957, 16959, 16961, 16963, 16965, 16968, 16971, 16974, 16977, 16980, 16983, 16986, 16989, 16992, 16995, 16998, 17001, 17005, 17008, 17011, 17014, 17017, 17020, 17023, 17026, 17029, 17032, 17036, 17039, 17043, 17047, 17050, 17053, 17056, 17059, 17062, 17065, 17068, 17071, 17074, 17077, 17080, 17083, 17086, 17089, 17092, 17095, 17098, 17101, 17104, 17107, 17110, 17113, 17116, 17119, 17122, 17125, 17128, 17131, 17134, 17137, 17140, 17143, 17146, 17149, 17152, 17155, 17158, 17161, 17164, 17167, 17170, 17173, 17176, 17179, 17182, 17185, 17187, -1, -1, -1, -1, -1, -1, -1, -1, 17190, 17192, -1, -1, 17194, 17196, 17198, 17200, 17202, 17204, 17206, 17208, 17210, 17212, 17214, 17217, 17220, 17223, 17226, 17229, 17232, 17235, 17238, 17241, 17244, 17247, 17250, 17254, 17257, 17260, 17263, 17266, 17269, 17272, 17275, 17278, 17281, 17285, 17288, 17292, 17296, 17299, 17302, 17305, 17308, 17311, 17314, 17317, 17320, 17323, 17326, 17329, 17332, 17335, 17338, 17341, 17344, 17347, 17350, 17353, 17356, 17359, 17362, 17365, 17368, 17371, 17374, 17377, 17380, 17383, 17386, 17389, 17392, 17395, 17398, 17401, 17404, 17407, 17410, 17413, 17416, 17419, 17422, 17425, 17428, 17431, 17434, 17436, 17439, 17442, 17445, 17448, 17451, 17454, -1, -1, 17457, 17459, -1, -1, -1, -1, -1, -1, 17461, 17463, 17465, 17467, 17469, 17471, 17473, 17475, 17477, 17479, 17481, 17483, 17485, 17487, 17489, 17492, 17495, 17498, 17500, 17502, 17504, 17506, 17508, 17510, 17512, 17515, 17518, 17521, 17524, 17527, 17530, 17533, 17537, 17541, 17544, 17546, 17548, 17551, 17553, 17556, -1, -1, -1, -1, 17559, 17561, 17564, 17567, 17569, 17572, 17575, 17577, 17580, 17582, 17585, 17588, 17591, 17594, 17597, 17600, 17603, 17605, 17607, 17610, 17613, 17615, -1, 17618, 17620, 17623, 17625, 17627, 17629, 17631, 17633, 17635, 17638, 17641, 17645, 17648, 17650, 17654, 17657, 17659, 17662, 17666, 17669, 17672, 17674, 17678, 17681, 17684, 17687, 17690, 17693, -1, 17695, 17698, 17701, 17704, 17707, 17711, 17714, 17718, 17721, 17724, 17727, 17730, 17733, 17736, -1, 17739, 17743, 17747, 17750, 17753, 17756, 17760, 17763, 17766, 17769, 17772, 17775, -1, 17777, 17779, 17782, 17785, 17788, 17791, 17793, 17799, 17806, 17811, 17818, 17824, 17829, 17831, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17835, 17838, 17841, 17844, 17847, 17850, 17854, 17857, 17861, 17864, 17868, 17872, 17876, 17879, 17883, 17888, 17893, 17896, 17899, 17903, 17908, 17910, 17912, 17914, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17916, 17920, 17924, 17928, 17932, 17936, 17940, 17944, 17947, 17951, 17955, 17959, 17963, 17967, 17971, 17976, 17981, 17986, 17991, 17996, 18001, 18006, 18010, 18015, 18020, 18025, 18030, 18035, 18040, -1, -1, -1, 18045, 18050, 18055, 18060, 18065, 18070, 18075, 18080, 18085, 18090, 18096, 18103, 18110, 18118, 18124, 18131, 18137, 18143, 18150, 18157, 18164, 18172, 18178, 18185, 18192, 18199, 18206, 18212, 18219, 18227, 18233, 18239, 18246, 18252, 18259, 18262, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18265, 18268, 18271, 18274, 18277, 18280, 18283, 18286, 18289, 18292, 18295, 18298, 18301, 18304, 18307, 18310, 18314, 18318, 18322, 18326, 18330, 18334, 18338, 18341, 18345, 18349, 18353, 18357, 18361, 18365, 18370, 18375, 18380, 18385, 18390, 18395, 18400, 18404, 18409, 18414, 18419, 18424, 18429, -1, -1, -1, 18434, 18439, 18444, 18449, 18454, 18459, 18464, 18469, 18474, 18479, 18484, 18490, 18497, 18504, 18512, 18518, 18525, 18531, 18537, 18544, 18551, 18558, 18566, 18572, 18579, 18586, 18593, 18599, 18606, 18612, 18619, 18626, 18633, 18640, 18649, 18656, 18663, 18672, 18681, 18690, 18697, 18704, 18711, 18717, 18725, 18732, 18740, 18746, 18752, 18759, 18765, 18768, 18771, 18774, 18777, 18780, 18783, 18786, 18789, 18792, 18795, 18798, 18801, 18804, 18807, 18810, 18813, 18816, 18819, 18822, 18825, 18828, 18831, 18834, 18837, 18841, 18845, 18849, 18852, 18856, 18859, 18863, 18865, 18867, 18869, 18871, 18873, 18876, 18879, 18882, 18885, 18888, 18891, 18894, 18897, 18900, 18903, 18906, 18909, 18912, 18915, 18918, 18921, 18924, 18927, 18930, 18933, 18936, 18939, 18942, 18945, 18948, 18951, 18954, 18957, 18960, 18963, 18966, 18969, 18972, 18975, 18978, 18981, 18984, 18987, 18990, 18993, 18996, -1, 18999, 19009, 19015, 19022, 19026, 19033, 19038, 19042, 19049, 19054, 19060, 19064, 19071, 19077, 19085, 19092, 19098, 19103, 19110, 19116, 19124, 19129, 19138, 19148, 19157, 19162, 19171, 19180, 19186, 19191, 19198, 19204, 19210, 19218, 19227, 19233, 19238, 19244, 19249, 19256, 19260, 19265, 19270, 19278, 19286, 19292, 19299, 19307, 19313, 19318, 19327, 19333, 19338, 19345, 19351, 19359, 19364, 19372, 19378, 19384, 19389, 19394, 19400, 19405, 19409, 19415, 19420, 19425, 19431, 19436, 19441, 19446, 19454, 19461, 19467, 19476, 19481, 19489, 19495, 19500, 19505, 19510, 19516, 19521, 19527, 19533, 19537, 19546, 19551, 19554, 19557, 19560, 19563, 19566, 19569, 19572, 19575, 19578, 19581, 19585, 19589, 19593, 19597, 19601, 19605, 19609, 19613, 19617, 19621, 19625, 19629, 19633, 19637, 19641, 19645, 19648, 19651, 19655, 19658, 19661, 19664, 19669, 19674, 19677, 19684, 19691, 19699, 19705, 19710, 19713, 19716, 19719, 19722, 19725, 19728, 19731, 19734, 19738, 19743, 19746, 19749, 19752, 19755, 19758, 19761, 19764, 19768, 19772, 19776, 19780, 19783, 19786, 19789, 19792, 19795, 19798, 19801, 19804, 19807, 19810, 19815, 19820, 19824, 19829, 19834, 19839, 19843, 19848, 19852, 19858, 19861, 19865, 19869, 19873, 19877, 19883, 19891, 19894, 19897, 19900, 19903, 19906, 19909, 19912, 19915, 19918, 19921, 19924, 19927, 19930, 19933, 19936, 19939, 19944, 19949, 19954, 19957, 19960, 19963, 19968, 19972, 19975, 19978, 19981, 19984, 19987, 19992, 19995, 19998, 20001, 20004, 20008, 20011, 20014, 20018, 20022, 20025, 20030, 20034, 20037, 20040, 20043, 20046, 20050, 20054, 20057, 20060, 20063, 20066, 20069, 20072, 20075, 20078, 20081, 20085, 20089, 20093, 20097, 20101, 20105, 20109, 20113, 20117, 20121, 20125, 20129, 20133, 20137, 20141, 20145, 20149, 20153, 20157, 20161, 20165, 20169, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20173, 20177, 20183, 20188, 20192, 20199, -1, 20204, 20208, 20215, 20220, 20227, 20232, 20236, 20240, 20244, 20250, 20255, 20261, 20267, 20274, 20279, 20283, 20288, 20293, 20298, 20304, 20308, 20314, 20320, 20324, 20331, 20336, 20341, 20348, 20353, 20358, 20365, 20370, 20376, 20382, 20387, 20392, 20396, 20400, 20407, 20414, 20418, 20423, 20429, 20435, 20442, 20448, 20453, 20459, 20464, 20468, 20473, 20478, 20483, 20488, 20494, 20498, 20502, 20507, 20511, 20515, 20519, 20524, 20531, 20536, 20541, 20546, 20551, -1, 20555, 20560, 20564, 20569, 20573, 20577, 20581, 20588, 20594, 20600, 20606, 20610, 20616, 20623, 20630, 20634, -1, 20639, 20644, 20649, 20653, 20657, 20661, 20668, 20673, 20678, -1, 20683, 20688, 20694, 20699, 20703, 20709, 20714, 20719, -1, 20724, 20728, 20733, 20739, 20744, 20748, 20753, 20758, 20762, 20767, 20771, 20776, 20781, 20785, -1, 20791, 20796, 20801, 20806, 20811, 20817, 20822, 20826, 20831, 20837, 20841, 20845, 20852, 20857, 20862, 20866, 20871, 20875, 20879, 20883, 20888, 20892, 20896, 20900, 20906, 20910, 20915, 20920, 20925, 20929, 20934, 20938, 20942, 20946, 20950, 20955, 20961, 20967, 20971, 20977, 20982, 20986, 20992, 20998, -1, 21002, 21009, 21015, 21021, 21028, 21035, 21041, 21045, 21050, 21054, 21059, 21064, 21069, 21075, 21080, 21085, 21090, 21095, 21099, 21103, 21109, 21113, 21118, 21123, 21127, 21133, 21137, 21142, 21146, 21152, 21156, 21163, 21168, 21173, 21179, 21185, 21191, 21195, 21200, 21205, 21210, 21216, 21220, 21225, 21229, 21236, 21240, 21246, 21252, 21257, 21263, 21269, 21274, 21280, 21285, 21289, 21293, 21298, 21304, 21308, 21314, 21321, -1, 21325, 21329, 21333, 21338, 21343, 21348, 21354, 21360, 21366, 21373, 21377, 21382, 21386, 21392, 21397, 21402, 21408, 21414, 21419, 21425, 21430, 21434, 21440, 21447, 21451, 21456, 21460, 21466, 21471, 21476, 21480, 21485, 21491, 21495, 21499, 21503, 21507, 21511, 21515, 21519, 21524, 21529, 21534, 21539, 21543, 21549, 21556, 21561, 21566, 21571, 21575, 21580, 21587, 21592, 21597, 21604, 21609, 21613, 21619, 21626, 21633, 21638, 21644, 21649, 21654, 21659, -1, 21664, 21670, 21674, 21678, 21682, 21686, 21690, 21695, 21700, 21704, 21710, 21716, 21722, 21726, 21730, 21736, 21740, 21745, 21749, 21753, 21757, 21761, 21768, 21774, 21779, 21784, 21789, 21794, 21798, 21802, 21806, 21812, 21816, 21821, 21825, 21830, 21835, 21840, 21846, 21850, 21856, 21860, 21864, 21869, 21874, 21878, 21882, 21886, 21891, 21896, 21902, 21908, 21912, 21918, 21922, 21928, 21932, -1, 21938, -1, 21942, 21947, 21953, 21957, 21962, 21969, 21973, 21979, 21984, 21988, 21994, 21999, 22003, 22009, 22013, 22018, 22023, 22028, 22034, 22040, 22046, 22050, 22054, 22059, 22065, 22071, 22076, 22081, 22086, 22091, 22096, 22100, 22105, 22110, 22117, 22121, 22126, 22131, 22135, 22140, 22144, 22149, 22153, 22157, 22162, 22166, 22171, 22177, 22182, 22187, 22192, 22198, 22204, 22208, 22212, 22218, 22223, 22228, 22233, 22237, 22241, 22247, 22253, 22257, 22263, 22269, 22275, 22281, 22287, 22292, 22296, 22301, 22308, 22315, 22321, 22326, 22332, 22337, 22341, 22345, 22350, 22356, 22362, 22367, 22371, 22376, 22381, 22387, 22392, 22396, 22400, 22404, 22407, 22412, 22416, 22423, 22427, 22431, 22436, 22440, 22444, 22450, 22454, 22460, 22464, 22470, 22475, 22481, 22487, 22492, 22497, 22501, 22505, 22509, 22513, 22517, 22523, 22528, 22532, 22536, 22541, 22546, 22551, 22555, 22559, 22564, -1, 22570, 22575, 22580, 22584, -1, 22589, 22595, 22600, 22604, 22608, 22612, 22618, 22623, 22629, 22635, 22640, 22645, 22651, 22655, 22659, 22664, 22668, 22673, 22677, 22683, 22690, 22695, 22701, 22706, 22711, 22716, 22721, 22726, 22731, 22737, 22743, 22747, 22753, 22758, 22764, 22769, 22774, 22779, 22784, 22789, 22794, 22800, 22806, 22812, 22818, 22823, 22827, 22831, 22835, 22840, 22846, 22851, 22856, 22863, 22868, 22874, 22879, 22885, 22891, 22897, 22901, 22907, 22911, 22916, 22922, 22927, 22932, 22938, 22944, 22949, 22955, 22959, 22964, 22968, 22972, 22977, 22982, 22988, 22994, 22998, 23003, 23008, -1, 23014, 23020, 23027, 23033, 23038, 23044, 23051, 23057, 23062, 23067, 23072, 23076, 23082, 23087, 23091, 23096, 23102, 23107, 23113, 23119, 23123, 23126, 23131, 23136, 23143, 23148, 23152, 23157, 23162, 23168, 23173, 23177, 23184, 23189, 23195, 23201, 23206, 23211, 23217, 23221, 23226, 23230, 23234, 23238, 23243, 23249, 23255, 23259, 23263, 23268, 23273, 23277, 23283, 23287, 23293, 23297, 23302, 23307, 23312, 23316, 23320, 23325, 23330, 23335, 23342, 23347, 23352, 23357, 23361, 23366, 23370, 23376, 23382, 23386, 23390, 23395, 23400, 23404, 23410, 23416, 23422, 23427, 23432, 23436, 23442, 23448, 23453, 23459, 23464, 23469, 23474, 23480, 23486, 23491, 23496, 23501, 23507, 23511, 23517, 23522, 23527, 23532, -1, 23538, 23543, 23548, 23553, 23558, 23563, 23568, 23574, 23579, 23585, 23591, 23597, 23601, 23608, 23612, 23618, 23623, 23630, 23637, 23643, 23648, 23653, 23658, 23665, 23671, 23676, 23680, 23684, 23688, 23693, 23699, 23704, 23710, 23714, 23719, 23725, 23731, 23736, 23742, 23748, 23755, 23762, 23768, 23774, 23781, 23786, 23791, 23795, 23799, 23804, 23811, 23818, 23824, 23828, 23834, 23840, 23845, 23849, 23854, 23859, 23866, 23872, 23877, 23883, 23888, 23894, 23899, 23905, 23910, 23913, 23919, 23925, 23931, 23936, 23940, -1, 23944, 23948, 23954, 23961, 23966, 23970, 23975, 23980, 23986, 23990, 23996, 24002, 24006, 24011, 24015, 24020, 24026, 24032, 24036, 24042, 24048, 24054, 24060, 24066, 24071, 24076, 24082, 24087, -1, 24092, 24097, 24101, 24105, 24110, 24116, 24122, 24127, 24131, 24136, 24142, 24148, 24152, 24158, 24165, 24169, 24176, 24181, 24186, 24190, 24197, 24202, 24206, 24212, 24217, 24222, 24226, 24231, 24236, 24242, 24248, 24252, 24258, 24263, 24269, 24274, 24280, 24286, 24291, 24296, 24300, 24305, 24310, 24315, 24321, 24326, 24331, 24337, 24341, 24345, 24350, 24355, 24361, 24368, 24375, 24381, 24388, 24394, 24401, 24406, 24410, 24415, 24421, 24425, 24432, 24436, 24441, 24445, 24450, 24454, 24458, 24463, 24468, 24473, 24478, 24484, 24490, 24495, 24500, 24505, 24511, 24516, 24521, 24527, 24531, 24538, 24542, 24548, 24553, 24559, 24566, 24570, 24574, 24580, 24585, -1, 24589, 24594, 24600, 24606, 24612, 24618, 24624, 24628, 24632, 24638, 24642, 24649, 24655, 24661, 24667, 24671, 24675, 24679, 24685, 24692, 24697, 24702, 24707, 24713, 24718, 24724, 24729, 24733, 24740, 24744, 24749, 24754, 24761, 24766, 24772, 24777, 24782, 24786, 24792, 24796, 24802, 24807, 24812, 24817, 24822, 24828, 24832, 24836, 24841, 24847, 24853, 24860, 24864, 24870, 24876, 24881, 24886, 24890, 24895, 24899, 24905, 24911, 24916, 24922, 24928, 24934, 24938, 24945, 24950, 24954, 24961, 24965, 24971, 24976, 24980, 24985, 24991, 24997, 25002, 25007, 25013, 25019, 25024, 25029, 25033, 25037, 25041, 25047, 25053, 25059, 25066, 25072, 25078, 25084, 25090, 25095, 25101, 25106, 25111, 25115, 25119, 25125, 25131, 25138, 25143, 25147, 25152, 25157, 25162, 25167, 25173, 25177, 25181, 25185, 25190, 25195, 25200, 25206, 25210, 25215, 25221, 25227, 25232, 25236, 25240, 25246, 25252, 25258, 25263, 25270, 25275, 25280, 25286, 25292, 25296, 25303, 25309, 25313, 25317, 25322, 25326, 25332, 25337, 25342, 25347, 25352, 25358, 25363, 25368, 25373, 25381, 25386, 25391, 25395, 25399, 25404, 25410, 25415, 25420, 25425, 25429, 25434, 25440, 25445, 25450, 25455, 25459, 25464, 25469, 25474, 25478, 25484, 25492, 25496, 25501, 25505, 25509, 25515, 25520, 25526, 25533, 25538, 25543, 25548, 25553, 25558, 25562, 25568, 25573, 25579, 25585, 25590, 25595, 25600, 25608, 25613, 25617, 25622, 25626, 25631, 25637, 25643, 25648, 25652, 25656, 25661, 25666, 25670, 25675, 25680, 25685, 25689, 25693, 25699, 25704, 25709, 25713, 25719, 25724, 25729, 25733, 25737, 25743, 25748, 25756, 25761, 25767, 25772, 25776, 25780, 25785, 25790, 25796, 25800, 25808, 25812, 25818, 25823, 25827, 25831, 25836, 25842, 25847, 25853, 25859, 25863, 25867, 25872, 25876, 25881, 25888, 25894, 25899, 25905, 25909, 25914, 25918, 25925, 25931, 25935, 25940, 25945, 25953, 25959, 25965, 25971, 25975, 25979, 25984, 25990, 25996, 26001, 26007, 26012, 26018, 26023, 26028, 26033, 26039, 26045, 26049, 26053, 26058, 26063, 26069, 26074, 26080, 26086, 26092, 26097, 26101, 26107, 26111, 26117, 26122, 26128, 26134, 26138, 26142, 26147, 26151, 26155, 26161, 26166, 26172, 26177, 26181, 26186, 26191, 26196, 26202, 26207, 26212, 26218, 26223, 26227, 26232, 26236, 26242, 26246, 26251, 26257, 26261, 26267, 26272, 26277, 26283, 26288, 26294, 26298, 26304, 26309, 26316, 26321, 26326, 26330, 26335, 26339, 26345, 26350, 26354, 26359, 26364, 26370, 26376, 26382, 26388, 26392, 26397, 26403, 26409, 26413, 26418, 26424, 26429, 26433, 26438, 26444, 26450, 26454, 26458, 26463, 26467, 26471, 26476, 26482, 26489, 26494, 26498, 26502, 26508, 26513, 26517, 26522, 26529, 26535, 26541, 26547, 26551, 26556, 26561, 26567, 26573, 26577, 26582, 26587, 26592, 26597, 26602, 26606, 26610, 26615, 26621, 26627, 26632, 26638, 26643, 26648, 26653, 26658, 26662, 26667, 26673, 26678, 26683, 26688, 26693, -1, 26699, 26706, 26712, 26716, 26721, 26725, 26729, 26733, 26738, 26742, 26748, 26752, 26757, 26764, 26768, 26773, 26778, 26783, 26788, 26794, 26799, 26803, 26807, 26814, 26820, 26827, 26834, 26838, 26843, 26847, 26853, 26858, 26863, 26869, 26876, 26881, 26885, 26890, 26895, 26900, 26905, 26910, 26915, 26921, 26927, 26933, 26937, 26942, 26946, 26950, 26954, 26958, 26962, 26967, 26972, 26978, 26982, 26986, 26991, 26996, 27002, 27008, 27012, 27016, 27023, 27027, 27032, 27037, 27042, 27046, 27051, 27056, 27061, 27066, 27071, 27075, 27081, 27086, 27091, 27096, 27101, 27106, 27110, 27114, 27121, 27125, 27132, 27138, 27142, 27148, 27153, 27157, 27162, 27166, 27170, 27175, 27179, 27184, 27189, 27194, 27199, 27204, 27211, 27216, 27221, 27226, 27231, 27237, 27241, 27246, 27252, 27257, 27263, 27268, 27272, 27277, 27282, 27286, 27290, 27293, 27299, -1, 27303, 27308, 27314, 27317, 27323, 27327, 27332, 27337, 27341, 27345, 27349, 27354, 27359, 27364, 27369, -1, 27375, 27379, 27383, 27388, 27392, 27398, 27402, 27406, 27411, 27416, 27422, 27427, 27432, 27437, 27443, 27447, 27453, 27460, 27465, 27469, 27474, 27479, 27485, 27490, 27495, 27500, 27504, 27509, 27514, 27518, 27522, 27529, 27534, 27538, 27543, 27548, 27554, 27558, 27564, 27569, 27574, 27578, 27582, 27586, 27591, 27595, 27601, 27608, 27613, 27618, 27623, 27628, 27633, 27637, 27642, 27647, 27652, 27656, 27661, 27669, 27674, 27680, 27686, 27690, 27694, 27699, 27704, 27709, 27715, 27719, 27725, 27731, 27735, 27740, 27745, 27750, 27755, 27760, 27765, 27770, 27775, 27781, 27786, 27790, 27794, 27800, 27805, 27810, 27815, 27820, 27826, 27832, 27836, 27842, 27846, 27851, 27856, 27861, 27866, 27871, 27875, 27880, 27885, 27889, 27894, 27899, 27903, 27909, -1, 27913, 27919, 27924, 27928, 27934, 27939, 27943, 27949, 27954, 27958, 27962, 27966, 27972, 27977, 27983, 27989, 27994, 27998, 28002, 28009, 28014, 28019, 28023, 28027, 28030, 28034, 28038, 28043, 28047, 28052, 28058, 28063, 28068, 28073, 28078, 28082, 28087, 28092, 28097, 28101, 28106, 28110, 28115, 28120, 28123, 28128, 28134, 28140, 28146, 28150, 28156, 28161, 28167, 28171, 28175, 28181, 28185, 28190, 28194, 28200, 28205, 28210, 28215, 28219, 28223, 28228, 28232, 28237, 28241, 28244, 28248, 28253, 28257, 28261, 28268, 28272, 28277, 28281, 28287, 28293, 28298, 28305, 28309, 28314, 28318, 28322, 28327, 28331, 28335, 28340, 28346, -1, 28352, 28359, 28363, 28366, 28371, 28377, 28382, 28387, 28391, 28394, 28400, 28405, 28410, 28414, 28420, 28425, 28431, 28436, 28440, 28444, 28448, 28454, 28458, 28462, 28466, 28471, 28475, 28479, 28484, 28489, 28494, 28498, 28504, 28510, 28514, 28520, 28524, 28528, 28532, 28537, 28541, 28546, 28551, 28556, 28561, 28565, 28569, 28575, 28579, 28584, 28588, 28593, 28598, 28604, 28608, 28613, 28619, 28623, 28627, 28631, 28635, 28640, 28644, 28650, 28656, 28662, 28667, 28671, 28677, 28682, 28686, 28690, 28693, 28700, 28705, 28709, 28713, 28718, 28722, 28727, 28731, 28736, 28741, 28745, 28751, 28755, 28762, 28767, 28773, 28777, 28782, 28787, 28793, 28798, 28804, 28807, 28813, 28818, 28823, 28828, 28833, 28837, 28841, 28846, 28852, 28858, 28864, 28871, 28876, 28880, 28884, 28889, 28893, 28897, 28902, 28909, 28913, 28918, 28925, 28929, 28933, 28939, 28943, -1, 28948, 28953, 28960, 28966, -1, 28971, 28975, 28981, 28986, 28990, 28995, 29001, 29007, 29012, 29018, 29022, 29025, 29030, 29036, 29040, 29044, 29048, 29052, 29056, 29062, 29068, 29073, 29077, 29082, 29087, 29094, 29098, 29103, 29107, 29112, 29117, 29121, 29126, 29132, 29138, 29144, 29148, 29153, 29158, 29162, 29166, 29171, 29176, 29181, 29187, 29191, 29195, 29200, 29204, 29210, 29216, 29220, 29224, 29230, 29235, 29240, 29245, 29249, 29254, 29258, 29263, 29267, 29271, 29276, 29280, 29285, 29291, 29296, 29301, 29306, 29313, 29318, 29323, 29329, 29335, 29340, 29344, 29349, 29353, 29359, 29364, 29368, 29372, 29378, 29383, 29389, 29396, 29400, 29404, 29411, 29415, 29420, 29424, 29430, 29434, 29440, 29445, 29450, 29454, 29459, 29463, 29467, 29473, 29478, 29483, 29489, 29495, 29502, 29506, 29512, 29517, 29520, 29526, 29533, 29538, 29542, 29547, 29552, 29557, 29561, 29565, 29569, 29574, 29579, 29584, 29588, 29592, 29596, 29601, 29607, 29611, 29615, 29619, 29624, 29629, 29636, 29642, 29646, 29651, 29655, 29659, 29665, 29670, 29674, 29679, 29683, 29690, 29695, 29700, 29705, 29710, 29714, 29720, 29725, 29729, 29735, 29741, -1, 29747, 29753, 29758, 29762, 29766, 29771, 29776, 29780, 29786, 29791, 29796, 29802, 29806, 29811, 29815, 29820, 29825, 29830, 29835, 29841, 29847, 29852, 29856, 29860, 29865, 29870, 29875, 29879, 29885, 29889, 29894, 29901, 29906, 29912, 29918, 29922, 29926, 29930, 29935, 29942, 29947, 29952, 29956, 29963, 29967, 29972, 29978, 29985, 29989, 29995, 30000, 30006, 30011, 30016, 30021, 30026, 30030, 30034, 30039, 30044, 30050, 30056, 30061, 30067, 30072, 30076, 30080, 30085, 30090, 30094, 30099, 30104, 30108, 30113, 30117, 30120, 30125, 30132, 30136, 30142, 30146, 30152, 30157, 30161, 30166, 30170, 30175, 30180, 30184, 30188, 30194, 30200, 30204, 30209, 30213, 30217, 30223, 30227, 30233, 30238, 30242, 30246, 30251, 30256, 30262, 30266, 30270, 30275, 30280, 30285, 30290, 30295, 30300, 30305, 30310, 30314, 30319, 30324, 30328, 30332, 30336, 30341, -1, 30345, 30351, 30355, 30359, 30363, 30369, 30374, 30379, 30383, 30388, 30393, 30398, 30402, 30406, 30412, 30419, 30425, 30430, 30435, 30440, 30445, 30450, 30454, 30460, 30466, 30471, 30475, 30479, 30485, 30489, 30494, 30499, 30503, 30509, 30513, 30520, 30524, 30528, 30532, 30536, 30540, 30544, 30549, 30553, 30557, 30563, 30567, 30573, 30579, 30585, 30591, 30595, 30601, 30606, 30611, 30616, 30621, 30627, 30632, 30638, 30642, 30647, 30653, 30658, 30663, 30669, 30673, 30678, 30682, 30688, 30694, 30698, 30703, 30708, 30713, 30717, 30722, 30725, 30730, 30735, 30740, 30745, 30750, 30758, 30762, 30767, 30771, 30776, 30783, 30789, 30793, 30797, 30801, 30806, 30812, 30816, 30822, 30827, 30832, 30836, 30841, 30846, 30851, 30856, 30860, 30864, 30869, 30875, 30879, 30884, 30888, 30894, 30899, 30905, 30910, 30915, 30919, 30922, 30927, 30931, 30936, 30942, 30948, 30952, 30958, 30963, 30969, 30973, 30978, 30983, 30987, 30992, 30997, 31003, 31008, 31013, 31017, 31021, 31026, 31031, 31037, 31041, 31046, 31050, 31055, 31059, 31064, 31069, 31073, 31078, 31082, 31088, 31092, 31097, 31102, 31106, -1, -1, 31113, 31117, 31121, 31125, 31130, 31134, 31139, 31144, 31149, 31153, 31157, 31164, 31169, 31173, 31178, 31184, 31190, 31196, 31200, 31205, 31209, 31213, 31219, 31223, 31228, 31234, 31239, 31243, 31250, 31255, 31259, 31263, 31268, 31272, 31277, 31283, 31289, 31295, 31301, 31305, 31309, 31315, 31321, 31327, 31333, 31338, 31345, 31350, 31356, 31360, 31364, 31370, 31376, 31380, 31384, 31389, 31395, 31400, 31404, 31408, 31412, 31418, 31422, 31427, 31432, 31437, -1, -1, 31443, 31448, 31453, 31458, 31463, 31467, 31472, 31478, 31483, 31488, 31493, 31498, 31504, 31510, 31515, 31521, 31527, 31534, 31540, 31545, 31551, 31555, 31560, 31566, 31571, 31576, 31581, 31587, 31592, 31596, 31601, 31606, 31611, 31616, 31620, 31626, 31630, 31635, 31640, 31645, 31649, 31654, 31659, 31664, 31669, 31673, 31677, 31682, 31688, 31693, 31699, 31703, 31709, 31714, 31721, 31726, 31732, 31738, 31742, 31746, 31752, 31758, 31761, 31765, 31769, 31773, 31779, 31784, 31789, 31793, 31799, 31805, 31811, 31815, 31819, 31823, 31829, 31836, 31840, 31844, 31849, 31853, 31858, 31863, 31867, 31871, 31875, 31880, 31884, 31888, 31892, 31898, 31904, 31910, 31916, 31922, 31927, 31935, 31941, 31948, 31955, 31959, 31964, 31968, 31972, 31977, 31982, 31987, 31992, 31997, 32002, 32007, 32012, 32017, 32023, 32028, 32034, 32039, 32044, 32049, 32054, 32058, 32063, 32069, 32073, 32079, 32083, 32089, 32093, 32099, 32103, 32109, 32115, 32120, 32124, 32128, 32132, 32137, 32143, 32147, 32152, 32158, 32163, 32167, 32172, 32177, 32182, 32187, 32193, 32199, 32204, 32208, 32213, 32217, 32224, 32230, 32234, 32238, 32243, 32248, 32252, 32256, 32261, 32266, 32270, 32275, 32280, 32286, 32291, 32295, 32299, 32304, 32310, 32314, 32320, 32326, 32330, 32334, 32339, -1, 32344, 32350, 32356, 32360, 32364, 32368, 32372, 32377, 32382, 32387, 32392, 32397, 32402, 32408, 32412, 32419, 32424, 32429, 32434, 32439, 32444, 32450, 32455, 32459, 32464, 32470, 32475, 32480, 32485, 32492, 32498, 32501, 32505, 32511, 32517, 32521, -1, 32526, 32531, 32537, 32542, 32548, 32553, 32557, 32563, 32569, 32575, 32581, 32586, 32590, 32594, 32599, 32604, 32608, 32614, 32619, 32625, 32629, 32635, 32641, 32646, 32652, 32657, 32662, 32666, 32671, 32677, 32683, 32690, 32695, 32700, 32705, 32710, 32715, 32719, 32726, 32732, 32736, 32741, 32746, 32751, 32758, 32762, 32768, 32772, 32776, 32780, 32784, 32790, 32795, 32799, 32806, 32811, 32815, 32820, 32827, 32833, 32840, 32846, 32851, 32856, 32860, 32865, 32870, 32876, 32881, 32886, 32891, 32895, 32900, 32904, 32909, 32913, 32919, 32923, 32928, 32932, 32936, 32940, 32944, 32950, 32955, 32959, 32965, 32970, 32975, 32981, 32985, 32988, 32994, 32998, 33002, -1, 33008, 33012, -1, 33018, -1, 33022, 33027, 33032, 33036, 33043, 33048, 33053, 33057, 33063, 33068, 33073, 33080, 33085, 33090, 33095, 33099, 33103, 33108, 33113, 33119, 33122, 33128, 33133, 33139, 33143, 33150, 33153, 33158, 33163, 33168, 33172, 33177, 33184, 33188, 33193, 33198, 33204, 33211, 33216, 33222, 33228, 33234, 33241, 33247, 33254, 33262, 33269, 33276, 33282, -1, 33288, 33294, 33298, 33302, 33308, 33314, 33318, 33325, 33331, 33336, 33340, 33344, 33349, 33353, 33357, 33363, 33370, 33374, 33380, 33385, 33392, 33396, 33402, 33408, 33413, 33419, 33424, 33430, 33434, 33441, 33446, 33450, 33456, 33460, 33466, 33471, 33476, 33482, 33488, 33493, 33498, 33503, 33508, 33514, 33521, 33527, 33533, 33539, 33543, 33547, 33551, 33557, 33562, 33566, 33573, 33581, 33586, 33591, 33596, 33601, 33607, 33613, 33617, 33622, 33626, 33633, 33638, 33644, 33650, 33656, 33661, 33665, 33670, 33677, 33682, 33686, 33693, 33697, 33702, 33707, 33711, 33717, 33721, 33728, -1, 33735, 33741, 33747, 33753, 33757, 33763, 33769, 33773, 33777, 33783, 33789, 33794, 33799, 33803, 33808, 33813, 33818, 33822, 33829, 33834, 33839, 33844, 33850, 33854, 33859, 33866, 33871, 33875, 33879, 33884, 33890, 33894, 33901, 33905, 33911, 33916, 33920, 33924, 33928, 33934, 33941, 33945, 33951, 33955, 33960, 33965, 33969, 33975, 33981, 33987, 33993, 33998, 34003, 34007, 34011, 34015, 34019, 34024, 34029, 34035, 34041, 34046, 34053, 34057, 34062, 34067, 34072, 34078, 34084, 34090, 34095, 34099, 34104, 34110, 34115, 34120, 34125, 34130, -1, 34134, 34139, -1, 34144, 34152, 34160, 34167, 34171, 34176, 34180, 34185, 34193, 34197, 34201, 34206, 34210, 34214, 34218, 34223, 34229, 34235, 34240, 34246, 34250, 34255, 34259, 34264, 34271, 34277, 34282, 34287, 34293, 34298, 34303, 34309, 34313, 34318, 34323, -1, 34330, 34335, 34340, 34345, 34349, 34354, 34360, 34365, 34369, 34374, 34379, 34383, 34389, 34394, 34399, 34404, 34408, 34414, 34420, 34425, 34430, 34436, 34440, 34444, 34450, 34455, 34459, 34465, 34470, 34476, 34482, 34487, 34492, 34497, 34502, 34507, 34512, 34516, 34520, 34525, 34530, 34535, 34540, 34547, 34552, 34557, 34561, 34565, 34571, 34577, 34581, 34586, 34591, 34597, 34601, 34606, 34612, 34617, 34622, -1, 34628, 34633, 34638, 34644, 34648, 34653, 34658, 34663, 34667, 34674, 34679, 34685, 34690, 34694, 34701, 34706, 34712, 34717, 34723, 34729, 34733, 34738, 34744, 34749, 34753, 34757, 34761, 34768, 34774, 34779, 34784, 34791, 34796, 34801, 34806, 34810, 34816, 34821, 34825, 34829, 34835, 34840, 34846, 34852, 34856, 34861, 34866, 34871, 34876, 34882, 34887, 34891, 34897, 34901, 34906, 34912, 34918, 34926, 34930, 34934, 34939, 34944, 34948, 34954, 34959, 34964, 34969, 34976, 34980, 34984, 34988, 34994, 35001, 35006, 35011, 35016, 35022, 35027, 35032, 35037, 35045, 35050, 35055, 35059, 35064, 35069, 35073, 35077, 35082, 35088, 35094, 35100, 35104, 35108, 35113, 35117, 35121, 35125, 35131, 35137, 35143, 35147, 35152, 35158, 35163, 35169, 35174, 35177, 35182, 35186, 35190, 35194, 35200, 35205, 35208, 35212, 35216, 35220, 35227, 35232, 35237, 35241, 35245, 35251, 35255, 35259, 35264, 35269, 35275, 35281, 35286, 35291, 35295, 35299, 35305, 35310, 35314, 35318, 35324, 35329, 35334, 35339, 35345, 35352, 35357, 35361, 35366, 35373, 35378, 35384, 35390, 35395, 35399, 35405, 35411, 35415, 35421, 35426, 35430, 35434, 35440, 35446, 35453, 35458, 35463, 35468, 35474, 35479, 35484, 35489, 35494, 35499, 35504, 35510, 35515, 35520, 35525, 35531, 35535, 35541, 35546, 35552, 35556, 35561, 35565, 35570, 35576, 35582, 35588, 35594, 35600, 35604, 35611, 35617, 35623, 35627, 35632, 35636, 35641, 35645, 35650, 35656, 35662, 35669, 35675, 35680, 35684, 35689, 35694, 35699, 35705, 35711, 35716, 35721, 35725, 35733, 35736, 35741, 35746, 35751, 35757, 35761, 35766, 35770, 35774, 35779, 35783, 35787, 35791, -1, 35795, 35801, 35805, 35809, 35815, 35819, 35825, 35831, 35837, 35844, 35848, 35852, 35855, 35858, 35863, 35869, 35875, 35880, 35884, 35888, 35893, 35899, 35904, 35910, 35916, 35921, 35925, 35930, 35934, 35937, 35941, 35946, 35951, 35956, 35961, 35967, 35971, 35977, 35983, 35988, 35994, 36000, 36006, 36012, 36016, 36020, 36025, 36029, 36034, 36040, 36046, 36050, 36056, 36061, 36066, 36071, 36076, 36081, 36085, 36089, 36093, 36099, 36105, 36110, 36115, 36121, 36127, 36133, 36139, 36145, 36150, 36154, 36159, 36164, 36169, 36174, 36178, 36182, 36187, 36191, 36196, 36201, 36206, 36212, 36217, 36222, 36226, 36232, 36238, 36243, 36247, 36252, 36258, 36262, 36269, 36274, 36281, 36287, 36291, 36297, 36303, 36308, 36313, 36318, 36324, 36330, 36335, 36339, 36344, 36349, 36355, 36360, 36365, 36369, 36375, 36380, 36384, 36389, 36393, -1, 36397, 36402, 36406, 36411, 36416, 36421, 36426, 36430, 36434, 36440, 36446, 36452, 36456, 36461, 36466, 36471, 36476, 36480, 36484, 36489, 36494, 36499, 36504, 36509, 36515, 36521, 36526, 36532, 36538, 36544, 36548, 36552, 36558, 36564, 36569, 36575, 36581, 36586, 36591, 36595, 36599, 36604, 36608, 36614, 36618, 36623, 36629, 36634, 36638, 36645, 36651, 36657, 36661, 36665, 36669, 36674, 36679, 36684, 36691, 36698, 36702, 36707, 36712, 36717, 36721, 36726, 36730, 36734, 36738, 36743, 36750, 36754, 36759, 36763, 36767, 36773, 36778, 36784, 36789, 36795, 36801, 36805, 36811, 36817, 36822, 36827, 36833, 36838, 36842, 36846, 36851, 36855, 36860, 36865, 36869, 36874, 36880, 36886, 36891, 36896, 36901, 36907, 36911, 36916, 36922, 36926, 36931, 36935, 36941, 36946, 36953, 36959, 36965, 36970, 36976, 36982, 36986, 36991, 36995, 37002, 37008, 37012, 37018, 37024, 37029, 37033, 37037, 37042, 37048, 37052, 37057, 37062, 37067, 37073, 37078, 37084, 37088, 37094, 37100, 37106, 37110, 37116, 37122, 37126, 37130, 37135, 37141, 37146, 37151, 37159, 37165, 37171, 37178, 37183, 37189, 37195, 37203, 37210, 37216, 37220, 37224, 37230, 37235, 37240, 37245, 37249, 37254, 37259, 37264, 37270, 37275, 37279, 37283, 37288, 37293, 37297, 37302, 37306, 37312, 37317, 37323, 37327, 37332, 37337, 37341, 37345, 37349, -1, 37354, 37361, 37366, 37372, 37377, 37383, 37388, 37394, 37400, 37405, 37411, 37415, 37419, 37423, 37427, 37431, 37435, 37440, 37444, 37448, 37453, 37458, 37463, 37469, 37475, 37481, 37486, 37492, 37496, 37501, 37507, 37514, 37518, 37524, 37528, 37532, 37538, 37543, 37548, 37553, 37559, 37563, 37569, 37575, 37579, 37584, 37590, 37596, 37602, 37608, 37614, 37620, 37625, 37629, 37634, 37639, 37644, 37651, 37657, 37661, 37667, 37672, 37677, 37683, 37687, 37693, 37698, 37704, 37710, 37717, 37722, 37728, 37734, 37739, 37744, 37749, 37754, 37759, 37765, 37770, 37776, 37782, 37788, 37795, 37799, 37804, 37810, 37815, 37819, 37824, 37829, 37833, 37839, 37843, 37848, 37852, 37857, 37863, 37868, 37874, 37880, 37884, 37890, 37896, 37902, 37907, 37912, 37917, 37921, 37926, 37932, 37937, 37943, 37948, 37952, 37957, 37963, 37969, 37974, 37978, 37983, 37987, 37992, 37997, 38001, 38005, 38011, 38016, 38021, 38027, 38033, 38038, 38043, 38049, 38054, 38060, 38065, 38071, 38075, 38079, 38084, 38089, 38096, 38101, 38107, 38112, 38117, 38121, 38126, 38131, 38135, 38140, 38146, 38150, 38156, 38163, 38167, 38172, 38176, 38183, 38190, 38197, 38202, 38207, 38212, 38217, 38222, 38227, 38233, 38237, 38243, 38247, 38251, 38255, 38259, 38265, 38270, 38276, 38283, 38290, 38294, 38298, 38305, 38311, 38317, -1, 38323, 38329, 38335, 38340, 38346, 38352, 38357, 38363, 38369, 38375, 38381, 38385, 38390, 38395, 38400, 38407, 38412, 38417, 38421, 38426, 38431, 38436, 38441, 38446, 38451, 38456, 38461, 38465, 38470, 38475, 38481, 38485, 38489, 38495, 38499, 38503, 38507, 38512, 38518, 38522, 38526, 38531, 38535, 38541, 38546, 38551, 38557, 38561, 38566, 38572, 38576, 38580, 38586, -1, 38590, 38595, 38598, 38603, 38609, 38613, 38618, 38623, 38628, 38632, 38636, 38640, 38644, 38650, 38654, 38658, 38663, 38667, 38672, 38678, 38683, 38688, 38692, 38697, 38702, 38706, -1, 38712, 38718, 38722, 38727, -1, 38733, 38739, 38743, 38747, 38752, 38756, 38761, 38767, 38771, 38776, 38781, -1, 38785, 38790, 38795, 38800, 38805, 38809, 38813, 38818, 38821, 38825, 38831, 38836, 38842, 38846, 38851, 38857, 38861, 38866, 38871, 38875, 38881, 38887, 38891, 38896, 38901, 38905, 38910, 38915, 38921, 38925, 38931, 38935, 38940, 38945, 38950, 38954, 38960, 38964, 38969, 38973, 38978, 38983, 38989, 38994, 38999, 39004, 39009, 39016, 39021, 39025, 39029, 39033, 39038, 39042, 39048, 39054, 39059, 39065, 39071, 39076, 39081, 39086, 39091, 39097, 39102, 39106, 39112, 39116, 39120, 39125, 39128, 39132, 39137, 39142, 39146, 39150, 39154, 39159, 39165, 39171, 39175, 39179, 39184, 39188, 39193, 39197, 39202, 39206, 39210, 39214, 39220, 39225, 39230, 39236, 39241, 39245, 39250, 39256, 39263, 39269, 39275, 39278, 39281, 39285, 39289, 39293, 39299, 39304, 39310, 39316, 39321, 39325, 39330, 39336, 39342, 39347, 39353, 39360, 39364, 39370, 39375, 39380, 39385, 39390, 39394, 39400, 39405, 39410, 39415, 39421, 39426, 39432, 39439, 39446, 39450, 39455, 39460, 39464, 39469, 39473, 39478, 39483, 39488, 39492, 39496, 39501, 39505, 39509, 39515, 39520, 39525, 39531, 39536, 39541, 39548, 39553, 39558, 39564, 39569, 39576, 39581, 39586, 39590, 39595, 39601, 39606, 39612, 39616, 39621, 39627, 39633, 39637, -1, 39642, 39646, 39653, 39657, 39662, 39668, 39674, 39679, 39684, 39688, 39692, 39697, 39702, 39707, 39712, 39715, 39720, 39725, 39729, 39734, 39739, 39744, 39748, 39752, 39758, 39764, 39771, 39776, 39782, 39786, 39790, 39796, 39801, 39806, 39811, 39816, 39821, 39827, 39832, 39837, 39843, 39854, 39859, 39863, 39873, 39878, 39882, 39887, 39891, 39897, 39903, 39909, 39915, 39920, 39924, 39929, 39933, 39939, 39945, 39949, 39954, 39960, 39966, 39971, 39977, 39983, 39988, 39993, -1, 39997, 40002, 40008, 40014, 40021, 40027, 40033, 40039, 40044, 40049, 40055, 40059, 40064, 40071, 40077, 40083, 40087, 40092, 40096, 40103, 40108, 40113, 40118, 40123, 40127, 40131, 40135, 40141, 40148, 40154, 40158, 40163, 40169, 40174, 40179, 40185, 40190, 40196, 40202, 40207, 40213, 40218, 40223, 40229, 40234, 40239, 40245, 40250, 40255, 40261, 40265, 40270, 40275, 40279, 40283, 40287, 40290, 40296, 40300, 40305, 40309, 40313, 40317, 40321, -1, 40326, 40330, 40336, 40341, 40347, 40351, 40355, 40360, -1, 40365, 40370, 40374, 40379, 40385, 40391, 40397, 40403, 40407, 40411, 40417, 40423, 40428, 40433, 40438, 40443, 40449, 40455, 40461, 40467, 40473, -1, 40479, 40484, 40489, 40494, 40499, 40504, 40511, 40516, 40523, 40529, 40536, 40542, 40547, 40553, 40559, 40564, 40570, 40575, 40581, 40585, 40591, 40596, 40600, 40605, 40610, 40616, 40621, 40626, 40630, 40634, 40638, 40642, 40647, 40653, 40660, 40664, 40669, 40674, 40680, 40686, 40691, 40696, 40700, 40704, 40708, 40713, 40717, 40723, 40730, 40735, 40740, 40745, 40750, 40754, 40759, 40763, 40767, 40772, 40777, 40784, 40790, 40795, 40799, 40804, 40808, 40813, 40817, 40823, 40828, 40834, 40838, 40843, 40847, 40851, 40855, 40859, 40865, 40870, 40876, 40880, 40887, 40892, 40899, 40905, 40911, 40917, 40922, 40927, 40931, 40937, 40942, 40947, 40953, 40959, 40966, 40971, 40976, 40981, 40986, 40993, 40998, 41002, 41006, 41011, 41016, 41020, 41025, 41032, 41036, 41040, 41045, 41049, 41053, 41057, 41063, 41069, 41077, 41083, 41088, 41095, 41100, 41104, 41109, 41115, 41120, 41127, 41133, 41138, 41142, 41148, 41153, 41157, 41161, 41167, 41174, 41181, 41187, 41191, 41196, 41200, 41205, 41213, 41217, -1, 41222, 41226, 41232, 41238, 41243, 41249, 41255, 41261, 41266, 41271, 41276, 41282, 41287, 41292, 41298, 41304, 41310, 41316, 41322, 41328, 41333, 41338, 41344, 41349, 41354, 41358, 41363, 41367, 41373, 41377, 41384, 41392, 41396, 41402, 41406, 41411, 41416, 41424, 41429, 41433, 41438, 41443, 41447, 41451, -1, 41455, 41459, 41465, 41469, 41474, 41480, 41484, 41490, 41496, 41500, 41504, 41510, 41516, 41521, 41528, 41532, 41537, 41543, 41548, 41553, 41557, 41562, 41568, 41572, 41577, 41581, 41587, 41593, 41598, 41602, 41608, 41615, 41620, 41625, 41629, 41633, 41638, 41644, 41650, 41655, 41661, 41666, 41672, 41676, 41680, 41686, 41691, 41695, 41702, 41707, 41712, 41716, 41721, 41726, 41731, 41737, 41743, 41748, 41754, 41759, 41765, 41770, 41775, 41780, 41784, 41789, 41794, 41799, 41805, 41810, 41814, 41818, 41823, 41829, 41833, 41837, 41842, 41848, 41855, 41859, 41864, 41871, 41876, 41882, 41886, 41893, 41898, 41903, 41908, 41914, -1, 41918, 41924, 41930, 41936, 41942, 41946, 41952, 41957, 41962, 41967, 41973, 41977, 41981, 41987, 41992, 41997, 42002, 42008, 42014, 42019, 42025, 42029, 42033, 42039, 42044, 42048, 42053, 42057, 42063, 42067, 42071, 42075, 42079, 42084, 42089, 42093, 42098, 42103, 42109, 42115, 42120, 42124, 42128, 42134, 42138, 42143, 42148, 42155, 42159, 42165, 42169, 42176, 42181, 42186, 42190, 42194, 42198, 42204, 42208, 42214, 42218, 42224, 42230, 42234, 42238, 42244, 42249, 42255, 42260, 42266, 42272, 42277, 42284, 42291, 42298, 42304, 42309, 42316, 42320, 42324, 42329, 42334, 42340, 42345, 42350, 42354, 42358, 42363, 42369, 42374, 42380, 42385, 42390, 42397, 42403, 42407, 42412, 42417, 42422, 42426, 42430, 42435, 42441, 42445, 42449, 42455, 42460, 42465, 42470, 42475, 42479, 42483, 42487, 42491, 42496, 42501, 42507, 42513, 42518, 42524, 42529, 42534, 42538, 42543, 42548, 42554, 42560, 42565, 42571, 42577, 42583, 42590, 42596, 42601, 42606, 42612, 42617, 42621, 42627, 42634, 42638, 42644, 42649, 42653, 42658, 42664, 42668, 42674, 42681, 42685, 42691, 42697, 42702, 42706, 42711, 42716, 42722, 42728, 42732, 42737, 42741, 42748, 42753, 42757, 42763, 42767, -1, 42773, 42778, 42784, 42788, 42793, -1, 42797, 42801, 42808, 42813, 42819, 42825, 42830, 42834, 42839, 42844, 42850, 42855, 42860, 42866, 42873, 42877, 42882, 42887, 42893, 42898, 42903, 42907, 42914, 42920, 42925, 42929, 42936, 42943, 42948, 42952, 42959, 42964, 42970, 42975, 42981, 42986, 42991, 42997, 43004, 43009, 43013, 43018, 43023, 43027, 43031, 43035, 43040, 43045, 43051, 43056, 43060, 43065, 43070, 43076, 43081, 43085, 43089, 43094, 43098, 43103, 43108, 43113, 43119, 43125, 43129, 43134, 43140, 43146, 43151, 43156, 43163, 43170, 43174, 43178, 43182, 43186, 43190, 43195, 43200, 43206, 43213, 43219, 43223, 43229, 43234, 43238, 43243, 43249, 43254, 43259, 43265, 43271, 43276, 43283, 43288, 43294, 43300, 43305, 43311, 43315, 43320, 43325, 43331, 43336, 43342, 43346, 43350, 43357, 43365, 43369, 43373, 43378, 43384, 43389, 43394, 43399, 43404, 43410, 43415, 43420, 43424, 43429, 43436, 43440, 43444, 43449, 43453, 43457, 43461, 43465, 43471, 43475, 43481, 43485, 43490, 43494, 43498, 43503, 43507, 43511, 43517, 43523, 43529, 43533, 43539, 43543, 43547, 43551, 43556, 43561, 43567, 43573, 43579, 43586, 43590, 43595, 43599, 43603, 43607, 43612, 43621, 43627, -1, 43632, 43636, 43640, 43645, 43650, 43655, 43660, 43664, 43669, 43675, 43682, 43686, 43691, 43696, 43702, 43708, 43715, 43720, 43725, 43731, 43736, 43742, 43746, 43752, 43757, 43760, 43765, 43770, 43776, 43781, 43786, 43791, 43796, 43800, 43807, 43813, 43818, 43823, 43827, 43831, 43836, 43843, 43847, 43852, 43856, 43860, 43866, 43872, 43878, 43884, 43888, 43893, 43898, 43904, 43909, 43913, 43918, 43921, 43927, 43933, 43938, 43943, 43947, 43952, 43957, 43963, 43969, 43975, 43981, 43985, 43990, 43996, 44001, 44005, 44009, 44014, 44018, 44023, 44028, 44032, 44037, 44042, 44047, 44051, 44055, 44059, 44065, 44070, 44074, 44079, 44084, 44088, 44094, 44100, 44106, 44113, 44118, 44122, 44126, 44131, 44135, 44142, 44148, 44154, 44158, 44163, 44167, 44172, 44177, 44180, 44185, 44191, 44197, 44201, 44206, 44212, 44217, 44222, 44227, 44232, 44239, 44244, 44248, 44252, 44258, 44264, 44270, 44275, 44279, 44285, 44291, 44296, 44300, 44305, 44310, 44314, 44320, 44326, 44331, 44336, 44342, 44349, 44354, 44360, 44365, 44369, 44374, 44378, 44383, 44387, 44393, 44398, 44402, 44406, 44411, 44417, 44423, 44427, 44432, 44436, 44442, 44447, 44452, 44457, 44460, 44465, 44471, 44477, 44483, 44489, 44493, 44498, 44505, 44509, 44514, 44519, 44524, 44529, 44535, 44540, 44545, 44550, 44557, 44563, 44568, 44575, 44581, 44588, 44592, 44598, 44602, 44608, 44613, 44619, 44623, 44629, 44635, 44640, 44646, 44651, 44655, 44661, 44666, 44670, 44674, 44678, 44684, 44690, 44695, 44699, 44703, 44709, 44715, 44720, 44726, 44731, 44734, 44740, 44745, 44749, 44753, 44757, 44761, 44766, 44771, 44776, 44781, 44786, 44792, 44797, 44803, -1, 44808, 44813, 44818, 44823, 44829, 44834, 44838, 44842, 44846, 44851, 44857, 44864, 44868, 44872, 44876, 44884, 44888, 44893, 44898, 44905, 44911, 44916, 44921, 44927, 44931, 44936, 44942, 44947, 44952, 44958, 44964, 44968, 44973, 44978, 44983, 44987, 44991, 44997, 45002, 45009, 45014, 45020, -1, 45026, 45031, 45037, 45043, 45047, 45051, 45056, 45061, 45066, 45071, 45076, 45081, 45086, 45090, 45097, 45103, 45107, 45115, 45120, 45126, 45131, 45136, 45141, 45146, 45151, 45157, 45161, 45167, 45172, 45177, 45181, 45188, 45193, 45199, 45204, 45210, 45215, 45221, 45227, 45233, 45237, 45242, 45247, 45253, 45257, 45261, 45265, 45271, 45277, 45283, 45288, 45295, 45300, 45306, 45313, 45317, 45321, 45327, 45332, 45337, 45343, 45349, 45355, 45360, 45366, 45372, 45377, 45382, 45388, 45395, 45400, 45405, 45409, 45413, 45418, 45423, 45428, 45433, 45438, 45442, 45447, 45451, 45457, 45462, 45467, 45472, 45477, 45484, 45489, 45493, 45499, 45504, 45510, 45516, 45520, 45525, 45530, 45534, 45540, 45545, 45552, 45556, 45560, 45565, 45571, 45576, 45581, 45586, 45592, 45598, 45603, 45609, 45614, 45620, 45626, 45631, 45636, 45640, 45645, 45650, 45655, 45661, 45665, 45670, 45674, 45679, 45683, 45688, 45694, 45699, 45704, 45708, 45713, 45718, 45723, 45728, 45733, 45737, 45742, 45747, 45753, 45757, 45763, 45768, 45772, 45776, 45781, 45786, 45792, 45797, 45802, 45807, 45812, 45818, 45822, 45827, 45834, 45841, 45846, 45850, 45855, 45860, -1, 45867, 45873, 45879, 45884, 45890, 45896, 45902, 45908, 45912, 45916, 45922, 45927, 45931, 45937, 45942, 45946, 45952, 45957, 45963, 45969, 45975, 45979, 45984, 45988, 45994, 45998, 46003, 46009, 46013, 46020, 46024, 46029, 46033, 46039, 46046, 46051, 46058, 46064, 46070, 46074, 46079, 46084, 46089, 46094, 46098, 46103, 46108, 46112, 46117, 46122, 46128, 46134, 46142, 46146, 46152, 46157, 46161, 46167, 46172, 46176, 46180, 46186, 46190, 46194, 46200, 46205, 46209, 46213, 46217, 46221, 46224, 46229, 46233, 46238, 46242, 46246, 46252, 46257, 46263, 46269, 46276, 46283, 46287, 46291, 46297, 46301, 46306, 46311, 46317, 46320, 46325, 46330, 46335, 46339, 46343, 46347, 46351, 46357, 46361, 46369, 46374, 46379, 46386, 46392, 46398, 46402, 46406, 46411, 46417, 46422, 46426, 46430, 46435, 46439, 46444, 46450, 46455, 46460, 46465, 46470, 46475, 46481, 46486, 46491, 46496, 46501, 46505, 46511, 46516, 46521, 46525, 46529, 46533, 46537, 46541, 46546, 46550, 46553, 46558, 46564, 46571, 46575, 46580, 46587, 46593, 46599, 46603, 46608, 46612, 46617, 46622, 46626, 46631, 46637, 46644, 46649, 46654, 46658, 46662, 46667, 46673, 46678, 46683, 46688, 46694, 46699, 46704, 46708, 46713, 46717, 46721, 46725, 46731, 46736, 46741, -1, 46748, 46752, 46757, 46763, 46768, 46774, 46779, 46783, 46787, 46792, 46797, 46803, 46808, 46814, 46819, 46823, 46827, 46831, 46835, 46840, 46844, 46848, 46852, 46856, 46862, 46866, 46872, 46876, 46881, 46886, 46891, 46895, 46901, 46906, 46911, 46917, 46921, 46927, 46931, 46935, 46940, 46945, 46950, 46956, 46960, 46966, 46972, 46976, 46981, 46985, 46990, 46995, 46999, 47003, 47009, 47014, 47020, 47025, 47030, 47034, 47038, 47042, 47047, 47053, -1, 47059, 47065, 47070, 47076, 47080, 47084, 47090, 47095, 47100, 47105, 47110, 47117, 47122, 47128, 47134, 47140, 47147, 47152, 47157, 47162, 47167, 47172, 47176, 47181, 47186, 47193, 47198, 47202, 47206, 47211, 47216, 47221, 47226, 47231, 47236, 47241, 47246, 47250, 47256, 47262, 47266, 47272, 47276, 47282, 47286, 47292, 47297, 47302, 47306, 47311, 47315, 47320, 47329, 47333, 47338, 47344, 47348, 47354, 47358, 47363, 47368, 47374, 47380, 47387, 47391, 47396, 47401, 47405, 47409, 47414, 47419, 47424, 47428, 47434, 47438, 47444, 47451, 47456, 47461, 47467, 47472, 47478, 47482, 47488, 47494, 47498, 47504, 47510, 47515, 47520, 47525, 47530, 47536, 47542, 47546, 47551, 47556, 47562, 47567, 47572, 47576, 47582, 47587, 47591, 47595, 47600, 47606, 47611, 47617, 47621, 47627, 47631, 47636, 47640, 47646, 47650, 47655, 47659, 47665, 47669, 47674, 47679, 47684, 47689, 47695, 47701, 47707, -1, 47712, 47717, 47722, 47728, 47733, 47738, 47743, 47748, 47752, 47757, 47761, 47766, 47770, 47774, 47780, 47785, 47791, 47797, 47803, 47808, 47812, 47817, 47821, 47827, 47832, 47836, 47840, 47844, 47850, 47857, 47863, 47868, 47873, 47879, 47885, 47890, 47896, 47902, 47907, 47911, 47918, 47923, 47927, 47932, 47937, 47941, 47946, 47951, 47957, 47963, 47967, 47971, 47976, 47983, 47990, 47995, 47999, 48004, 48010, 48017, 48022, 48027, 48032, 48037, 48043, 48048, 48052, 48058, 48063, 48068, 48073, 48078, 48082, 48088, 48094, 48099, 48104, 48110, 48115, 48119, 48124, -1, 48130, 48135, 48140, 48146, 48152, 48157, 48163, 48169, 48175, 48180, 48186, 48192, 48197, 48203, 48207, 48212, 48217, 48222, 48228, 48233, 48237, 48242, 48247, 48252, 48258, 48264, 48268, 48273, 48278, 48283, 48289, 48295, 48299, 48305, 48311, 48317, 48323, 48329, 48334, 48340, 48344, 48348, 48352, 48356, 48360, 48367, 48371, 48375, 48379, 48383, 48390, 48395, 48400, 48405, 48409, 48414, 48419, 48425, 48432, 48438, 48443, 48448, 48454, 48460, 48464, 48469, 48474, 48479, -1, -1, 48484, 48489, 48494, 48499, 48505, 48509, 48514, 48520, 48526, 48532, 48537, 48542, 48548, 48553, 48559, 48564, 48570, 48575, 48580, 48584, 48589, 48595, 48601, 48606, 48611, 48615, 48620, 48625, 48630, 48634, 48639, 48645, 48650, 48655, 48660, 48666, 48672, 48678, 48683, 48688, 48691, 48697, 48702, 48708, 48712, 48717, 48723, 48728, 48733, 48737, 48741, 48746, 48750, 48755, 48759, 48764, 48770, 48775, 48782, 48788, 48794, 48797, 48801, 48806, 48812, 48817, 48822, 48826, 48830, 48834, 48839, 48845, 48850, 48855, 48860, 48865, 48870, 48875, 48880, 48884, 48890, 48895, 48901, 48908, 48916, 48921, 48927, 48933, 48940, 48944, 48948, 48953, 48959, 48965, 48971, 48976, 48982, 48986, 48991, 48996, 49002, 49007, 49011, 49016, 49024, 49030, 49035, 49040, 49045, 49049, 49056, 49061, 49067, 49072, 49076, 49081, 49086, 49091, 49097, 49102, 49107, 49112, 49118, 49124, 49128, 49132, 49137, 49143, 49149, 49155, 49162, 49167, 49172, 49178, 49183, 49187, 49193, 49198, 49203, 49208, 49213, 49218, 49224, 49230, 49235, 49240, 49244, 49249, 49256, 49263, 49267, 49272, 49278, 49282, 49288, 49295, 49299, 49304, 49310, 49315, 49322, 49327, 49335, 49341, 49345, 49350, 49355, 49360, 49365, 49369, 49374, 49379, 49385, 49391, 49396, 49400, 49406, 49410, 49415, 49421, 49428, 49433, 49437, 49442, 49447, -1, 49453, 49458, 49462, 49468, 49474, 49478, 49483, 49489, 49495, 49501, 49506, 49512, 49517, 49522, 49526, 49532, 49538, 49542, 49546, 49552, 49556, 49562, 49567, 49572, 49578, 49584, 49590, 49595, 49600, 49606, 49611, 49615, 49619, 49623, 49627, 49631, 49635, -1, 49639, 49645, 49650, 49654, 49658, 49663, 49669, 49674, 49680, 49685, 49689, 49693, 49697, 49701, 49705, 49709, 49713, 49717, 49721, 49726, 49732, 49736, 49741, 49746, 49751, 49755, 49761, 49766, 49771, 49776, 49781, 49786, 49790, 49795, 49800, 49805, 49810, 49816, 49821, 49825, 49830, 49835, 49841, 49847, 49852, 49857, 49861, 49865, 49870, 49876, 49880, 49886, 49892, 49898, 49903, 49909, 49914, 49919, 49925, 49930, 49936, -1, 49942, 49948, 49952, 49957, 49962, 49967, 49971, 49975, 49980, 49986, 49991, 49997, 50001, 50007, 50011, 50017, 50023, 50028, 50033, 50037, 50043, 50048, 50053, 50058, 50062, 50067, 50071, 50076, 50082, 50087, 50092, 50097, 50101, 50107, 50112, 50117, 50123, 50130, 50134, 50140, 50145, 50150, 50154, 50158, 50162, 50166, 50172, 50176, 50181, 50185, 50189, 50193, 50199, 50204, 50210, 50215, 50221, 50226, 50230, 50235, 50239, 50244, 50248, 50254, 50259, 50265, 50270, 50274, 50281, 50287, 50292, 50296, 50301, 50306, 50310, 50315, 50320, 50324, 50329, 50335, 50340, 50346, 50352, 50358, 50363, 50368, 50373, 50377, 50383, 50387, 50394, 50398, 50404, 50408, 50413, 50419, 50423, 50430, 50434, 50440, 50445, 50451, 50457, 50461, 50467, 50471, 50475, 50481, 50487, 50492, 50497, 50501, 50505, 50511, 50516, 50521, -1, 50527, 50532, 50537, 50542, 50547, 50551, 50556, 50561, 50566, 50573, 50579, 50584, 50588, 50593, 50598, 50602, 50608, 50614, 50618, 50623, 50628, 50633, 50638, 50643, 50647, 50654, 50660, 50664, 50670, 50676, 50682, 50688, 50692, 50697, 50703, 50709, 50714, 50719, 50725, 50730, 50736, 50741, 50747, 50752, 50758, 50762, 50767, 50772, 50777, 50782, 50788, 50792, 50798, 50803, 50807, 50812, 50816, 50821, 50825, 50831, 50837, 50843, 50849, 50853, 50857, 50863, 50867, 50872, 50878, 50884, 50888, 50892, 50896, 50901, 50906, 50912, 50917, 50923, 50929, 50934, 50938, 50942, 50946, 50950, 50954, 50959, 50963, 50968, 50973, 50978, 50983, 50988, 50994, 50999, 51003, 51007, 51011, 51016, 51021, 51026, 51030, 51034, 51040, 51045, 51052, 51058, 51063, 51069, 51074, 51079, 51084, 51090, 51094, 51099, 51104, 51109, 51113, 51118, 51123, 51128, 51135, 51139, 51145, 51150, 51155, 51162, 51168, 51174, 51179, 51184, 51189, 51193, 51197, 51201, 51206, 51211, 51215, 51221, 51226, 51232, 51236, 51242, 51247, 51253, 51259, 51265, 51271, 51276, 51282, 51288, 51294, 51299, 51304, 51309, 51313, 51319, 51323, 51328, 51334, 51340, 51345, 51350, 51354, 51359, 51364, 51369, 51373, 51380, 51385, 51391, 51395, 51401, 51406, 51412, 51418, 51424, 51431, 51437, 51443, 51448, 51455, 51462, 51468, 51473, 51477, 51483, 51488, 51493, 51498, 51505, 51511, 51517, 51522, 51527, 51534, 51540, 51546, 51550, 51555, 51560, 51565, 51570, 51575, 51580, 51586, 51591, 51597, 51601, 51608, 51615, 51619, 51624, 51629, 51633, 51638, 51643, 51648, 51654, 51659, 51665, 51671, 51676, 51682, 51686, 51692, 51696, 51702, 51706, 51710, 51716, 51720, 51726, 51731, 51737, 51741, 51746, 51750, 51755, 51760, 51767, 51774, 51780, 51786, 51791, 51795, 51801, 51807, 51811, 51816, 51821, 51826, 51830, 51835, 51840, 51844, 51850, 51854, 51859, 51864, 51870, 51875, 51880, 51886, 51892, 51896, 51902, 51908, 51913, 51918, 51923, 51929, 51935, 51940, 51945, 51951, 51958, 51962, 51967, 51972, 51976, 51980, 51984, 51989, 51994, 51999, 52004, 52009, 52013, 52017, 52023, 52027, 52034, 52039, 52044, 52049, 52055, 52062, 52068, 52074, 52079, 52085, 52090, 52095, 52100, 52104, 52108, 52112, 52119, 52124, 52128, 52132, 52136, 52141, 52147, 52153, 52158, 52163, 52169, 52174, 52178, 52185, 52191, 52196, 52202, 52207, 52213, 52219, 52223, 52227, 52231, 52236, 52242, 52247, 52252, 52256, 52260, 52266, 52273, -1, 52278, 52283, 52288, 52292, 52296, 52302, 52308, 52314, 52319, 52325, 52331, 52337, 52342, 52347, 52352, 52357, 52361, 52365, 52371, 52375, 52379, 52383, 52388, 52393, 52398, 52406, 52411, 52417, 52423, 52427, 52432, 52437, 52441, 52446, 52451, 52456, 52461, 52465, 52470, 52475, 52481, 52487, 52492, 52496, 52502, 52507, -1, 52511, 52515, 52521, 52527, 52533, 52539, 52545, 52551, 52557, 52564, 52570, 52575, 52581, 52585, 52589, 52595, 52601, 52607, 52613, -1, 52619, 52625, 52631, 52635, 52641, 52646, 52650, 52655, 52660, 52665, -1, 52670, 52675, 52680, 52684, 52688, 52693, 52698, 52703, 52707, 52712, 52716, 52721, 52725, 52730, 52736, 52740, 52745, 52752, 52756, 52762, 52768, 52772, 52777, 52781, 52786, 52792, 52797, 52802, 52806, 52810, 52814, 52820, 52825, 52830, 52835, 52841, 52846, 52850, 52857, 52863, 52868, 52872, 52876, 52882, 52886, 52890, 52894, 52899, 52905, 52911, 52917, 52923, 52930, 52935, 52941, 52947, 52953, 52957, 52963, 52967, 52973, 52979, 52984, 52989, 52994, 53000, 53005, 53010, 53016, 53021, 53026, 53030, 53035, 53040, 53045, 53051, 53056, 53062, 53068, 53073, 53079, 53083, 53088, 53093, 53098, 53102, 53107, 53111, 53115, 53121, 53126, 53132, 53137, 53141, 53145, 53150, 53154, 53158, 53162, 53167, 53172, 53178, 53183, 53188, 53193, 53196, 53201, 53207, 53212, 53217, 53223, 53228, 53234, 53239, 53244, -1, 53249, 53253, 53259, 53265, 53272, 53279, 53286, 53292, 53297, 53303, 53309, 53313, 53319, 53323, 53327, 53332, 53338, 53344, 53349, 53354, 53359, 53363, 53367, 53371, 53375, 53379, 53384, 53389, 53393, 53398, 53402, 53408, 53414, 53418, 53422, 53426, 53431, 53436, 53443, 53448, 53452, 53458, 53462, 53466, 53471, 53476, 53480, 53485, 53490, 53495, 53501, 53507, 53512, 53517, 53522, 53528, 53532, 53537, 53542, 53547, 53553, 53559, 53563, 53568, 53573, 53578, 53583, 53587, 53591, 53596, 53600, 53604, 53610, 53614, 53619, 53623, 53628, 53633, 53637, 53642, 53648, 53653, 53657, 53662, 53667, 53672, 53678, 53683, 53688, 53693, 53698, 53703, 53708, 53713, 53718, 53723, 53729, -1, 53734, 53740, 53746, 53751, 53757, 53763, 53767, 53774, 53778, 53783, 53789, 53794, 53799, 53806, 53810, 53816, 53820, 53824, 53828, 53835, 53841, 53845, 53849, 53854, 53859, 53865, 53870, 53876, 53880, 53885, 53891, 53895, 53901, 53905, 53910, 53914, 53919, 53925, 53930, 53934, 53938, 53943, 53947, 53953, 53958, 53963, 53969, 53973, 53978, 53984, 53988, 53993, 53998, 54003, 54007, 54012, 54018, 54022, 54027, 54033, 54038, 54043, 54050, 54055, 54062, 54066, 54070, 54074, 54080, 54084, 54090, 54094, 54099, 54106, 54112, 54118, 54124, 54130, 54135, 54140, 54145, 54150, 54156, 54160, 54165, 54172, 54178, -1, 54184, 54190, 54194, 54199, 54205, 54211, 54215, 54221, 54226, 54232, 54239, 54247, 54252, 54257, 54262, 54268, 54273, 54279, 54284, 54290, 54294, 54299, 54303, 54308, 54314, 54319, 54323, 54329, 54334, 54340, 54344, 54349, 54354, 54359, 54363, 54370, 54375, 54381, 54386, 54391, 54397, 54403, 54409, 54417, 54421, 54427, 54431, 54436, 54440, 54444, 54448, 54452, 54457, 54461, 54466, 54471, 54476, 54482, 54488, 54494, 54499, 54504, 54509, 54515, 54519, 54525, 54529, 54535, 54541, 54546, 54551, 54557, 54563, 54567, 54571, 54575, 54580, 54585, 54591, 54596, 54600, 54604, 54609, 54614, 54620, 54625, 54631, 54636, 54641, 54647, 54651, 54657, 54665, 54674, 54679, 54684, 54689, 54695, 54701, 54707, 54713, 54717, 54721, 54727, 54733, 54739, 54745, 54751, 54755, 54759, 54764, 54769, 54775, 54779, 54784, 54789, 54795, 54800, 54805, 54811, 54818, 54823, 54827, 54831, 54837, 54841, 54845, 54849, 54854, 54860, 54866, 54872, 54878, 54882, 54886, 54891, 54898, 54904, 54908, 54914, 54919, 54923, 54929, 54933, 54938, 54943, 54949, 54955, 54959, 54965, 54969, 54973, 54978, 54983, 54988, 54994, 55000, 55005, 55010, 55016, 55023, 55028, 55033, 55038, 55042, 55047, 55052, 55056, 55062, 55066, 55070, 55077, 55082, 55089, 55096, 55101, 55107, 55111, 55115, 55120, 55126, 55132, 55136, 55141, 55147, 55153, 55158, 55165, 55173, 55181, 55187, 55192, 55196, 55200, 55206, 55214, 55220, 55227, 55232, 55237, 55242, 55249, -1, 55255, 55261, -1, 55267, 55272, 55277, 55282, 55286, 55291, 55296, 55301, 55307, 55312, 55318, 55324, 55328, 55334, 55338, 55343, 55348, 55355, 55361, 55367, 55371, 55375, 55380, 55384, 55390, 55394, 55399, 55404, 55408, 55413, 55419, 55423, 55428, 55433, 55438, 55443, 55448, 55453, 55457, 55463, 55468, 55473, 55478, 55484, 55488, 55493, 55498, 55502, 55506, 55512, 55518, 55524, 55529, 55533, 55538, 55543, 55549, 55555, 55561, 55567, 55573, 55579, 55583, 55587, 55592, 55596, 55601, 55607, 55611, 55616, 55621, 55626, 55630, 55634, 55639, 55644, 55649, 55655, 55660, 55666, 55671, 55675, 55682, 55691, 55696, 55702, 55707, 55712, 55717, 55722, 55726, 55732, 55736, 55740, -1, 55748, 55752, 55757, 55762, 55766, 55772, 55776, 55781, 55785, 55791, 55797, 55801, 55807, 55811, 55815, 55820, 55826, 55832, 55837, 55843, 55847, 55853, 55857, 55862, 55867, 55872, 55879, 55884, 55889, 55894, 55900, 55904, 55909, 55915, 55920, 55926, 55931, 55936, 55941, 55946, 55952, 55957, 55963, 55969, 55974, 55980, 55984, 55991, 55995, 55999, 56003, 56007, 56011, 56016, 56021, 56026, 56031, 56036, 56040, 56045, 56051, 56056, 56060, 56066, 56071, 56077, 56084, 56089, 56095, 56101, 56106, 56110, 56116, 56121, 56127, 56132, 56139, 56145, 56151, 56156, 56162, 56167, 56174, 56179, 56184, -1, 56189, 56193, 56197, 56203, 56208, 56214, 56220, 56225, 56230, 56235, 56241, 56246, 56250, 56255, 56260, 56266, 56271, 56275, 56282, 56286, 56292, 56297, 56301, 56306, 56311, 56317, 56322, 56327, 56332, 56337, 56342, 56346, 56354, 56358, 56364, 56370, 56376, 56380, 56385, 56391, 56399, 56404, 56410, 56416, 56420, 56425, 56430, 56434, 56441, 56445, 56450, 56456, 56460, 56464, 56469, 56475, 56481, 56485, 56490, 56495, 56500, 56505, 56512, 56517, 56521, 56527, 56533, 56539, 56545, 56550, 56555, 56559, 56565, 56571, 56577, -1, 56583, 56591, 56598, 56604, 56610, 56614, 56619, 56624, 56630, 56635, 56641, 56645, 56650, 56655, 56660, 56666, 56671, 56676, 56682, 56686, 56691, 56697, 56701, 56706, 56710, 56714, 56720, 56725, 56730, 56735, 56741, 56747, 56752, 56757, 56763, 56768, 56773, 56778, 56784, 56789, 56796, 56802, 56808, 56812, 56819, 56823, 56828, 56833, 56838, 56843, 56847, 56852, 56859, 56864, 56870, 56875, 56880, 56888, 56894, 56899, 56906, 56911, 56917, 56922, 56926, 56931, 56936, 56941, 56946, 56952, 56958, 56962, 56967, 56971, 56976, 56982, -1, -1, 56986, 56992, 56996, 57001, 57008, 57013, 57018, 57024, 57029, 57033, 57038, 57044, 57049, 57055, 57062, 57067, 57071, 57076, 57080, 57085, 57089, 57094, 57099, 57105, 57110, 57116, 57120, 57125, 57129, 57133, 57139, 57144, 57150, 57156, 57160, 57165, 57170, 57176, 57181, 57187, 57194, 57199, 57203, 57209, 57215, 57220, 57225, 57233, 57238, 57244, 57249, 57254, 57259, 57265, 57269, 57275, 57280, 57285, 57289, 57295, 57299, 57305, 57309, 57314, 57320, 57325, 57329, 57335, 57340, 57344, 57348, 57354, 57359, 57365, 57369, 57374, 57378, 57384, -1, 57389, 57395, 57400, 57405, 57412, 57418, 57423, 57428, 57432, 57436, 57440, 57446, 57450, 57455, 57460, 57464, 57468, 57473, 57478, 57482, 57488, 57492, 57497, 57503, 57508, 57514, 57520, -1, 57525, 57530, 57534, 57539, 57543, 57548, 57554, 57559, 57562, 57566, 57572, 57577, 57581, 57587, -1, 57592, 57598, 57603, 57607, 57613, 57619, 57625, 57631, 57636, 57641, 57647, 57654, 57660, 57664, 57670, 57675, 57679, 57687, 57692, 57697, 57703, 57709, 57713, -1, 57719, 57723, 57728, 57732, 57737, 57743, 57749, 57754, 57758, 57763, 57768, 57773, 57778, 57782, 57786, 57792, 57796, 57802, 57809, 57815, 57819, 57825, 57830, 57834, 57838, 57844, 57848, 57852, 57858, 57863, 57868, 57873, 57877, 57882, 57886, 57890, 57895, 57899, 57905, 57911, 57917, 57923, 57927, 57931, 57935, 57939, 57943, 57948, 57953, 57959, 57964, 57970, 57975, 57982, 57987, 57992, 57997, 58002, 58007, 58011, 58017, 58023, 58027, 58031, 58035, 58040, 58045, 58049, 58053, 58057, 58063, 58067, 58072, 58076, 58082, 58086, 58090, 58095, 58101, 58106, 58110, 58115, 58119, 58125, 58131, 58136, 58143, 58147, 58151, 58155, 58159, 58163, 58167, 58172, 58176, 58182, 58187, 58191, 58196, 58200, 58207, 58212, 58217, 58221, 58226, 58230, 58234, 58239, 58244, 58249, 58253, 58259, 58264, 58268, 58272, 58277, 58281, 58285, 58291, 58297, 58304, 58309, 58316, 58320, 58325, 58330, 58335, 58340, 58346, 58351, 58356, 58360, 58366, 58371, 58377, 58381, 58386, 58391, 58395, 58400, 58405, 58410, 58414, 58418, 58424, 58429, 58434, 58440, 58445, 58449, 58454, 58461, 58466, 58472, 58476, 58481, 58487, 58491, 58496, 58500, 58507, 58513, 58518, 58522, 58531, 58537, 58542, 58546, 58552, 58557, 58562, 58568, 58572, 58577, 58582, 58586, 58591, 58596, 58602, 58607, 58612, 58616, 58621, 58625, 58629, 58633, 58638, 58644, 58648, 58654, 58658, 58664, 58668, 58673, 58678, 58682, 58687, 58691, 58695, 58699, 58703, 58707, 58711, 58715, 58719, 58725, -1, -1, 58730, 58734, 58743, 58748, 58754, 58759, 58763, 58768, 58773, 58777, 58783, 58789, 58793, 58797, 58802, 58807, 58812, 58821, 58826, 58831, 58835, 58840, 58845, 58849, -1, 58854, 58859, 58864, 58868, 58872, 58877, 58881, 58887, 58891, 58896, 58900, 58904, 58908, 58914, 58920, 58927, 58931, 58936, 58942, 58947, 58953, 58959, 58964, 58968, 58973, 58978, 58982, 58987, 58992, 58998, 59002, 59007, 59012, 59016, 59021, 59027, 59034, 59039, 59043, -1, 59048, 59052, 59058, 59064, 59070, 59074, 59079, 59083, 59088, 59094, 59098, 59102, 59106, 59112, 59116, 59122, 59127, 59131, 59137, 59143, 59148, 59153, 59159, 59164, 59171, 59177, 59183, 59189, 59200, 59204, 59208, 59213, 59218, 59223, 59229, 59234, 59239, 59244, 59248, 59254, 59260, 59265, 59271, 59275, 59280, 59286, 59293, 59298, 59303, 59308, 59312, 59317, 59323, 59328, 59332, 59338, 59343, 59348, 59354, 59358, 59362, 59367, 59371, 59375, 59381, 59388, 59393, 59397, -1, 59405, 59411, 59416, 59421, 59427, 59431, 59435, 59441, 59447, 59453, 59458, 59463, 59469, 59474, 59480, 59484, 59490, 59496, 59501, 59506, 59513, 59519, 59526, 59531, 59537, 59543, 59547, 59552, 59556, 59560, 59565, 59569, 59573, 59578, 59584, 59590, 59595, 59601, 59607, 59612, 59617, 59622, 59626, 59631, 59636, 59640, 59645, 59650, 59654, 59660, 59664, 59671, 59677, 59681, 59686, 59691, 59696, 59701, 59707, 59711, 59716, 59721, 59726, 59730, 59736, 59740, 59744, 59749, 59755, 59761, 59766, 59770, 59774, 59779, 59784, 59788, 59793, 59798, 59803, 59808, 59812, 59816, 59820, 59824, 59828, 59833, 59838, 59844, 59849, 59855, 59859, 59865, 59870, 59874, 59881, 59888, 59892, 59897, 59902, 59906, 59911, 59918, 59924, 59928, 59933, 59937, 59942, 59948, 59953, 59957, 59962, 59966, 59972, 59977, 59981, 59986, 59990, 59994, 60000, 60004, 60009, 60014, 60018, 60024, 60031, 60037, 60042, 60046, 60050, 60054, 60058, 60062, 60067, 60072, 60079, 60084, 60090, 60095, 60099, 60104, 60109, 60114, 60120, 60124, 60130, 60136, 60142, 60147, 60153, -1, 60157, 60161, 60166, 60170, 60174, 60180, 60185, 60191, 60195, 60199, 60204, 60209, 60214, 60221, 60226, 60231, 60236, 60242, 60248, 60253, 60257, 60261, 60265, 60271, 60275, 60279, 60284, 60289, 60294, 60298, 60302, 60307, 60312, 60319, -1, 60324, 60328, 60334, 60338, 60343, 60348, 60352, 60356, 60362, 60367, 60371, 60376, 60382, 60387, 60393, 60397, 60403, 60410, 60415, 60420, 60424, 60428, 60434, 60438, 60444, 60449, 60456, 60461, 60468, 60474, 60480, 60485, 60489, 60494, 60499, 60503, 60507, 60512, 60516, 60521, 60527, 60533, 60540, 60546, 60553, 60558, 60564, 60568, 60573, 60579, 60583, 60588, 60594, 60599, 60603, 60609, 60614, 60619, 60624, 60629, 60634, 60639, 60644, 60649, 60655, 60661, 60667, 60672, 60676, 60680, 60685, 60690, 60696, 60700, 60704, 60710, 60715, 60720, 60726, 60731, 60735, 60741, 60745, 60749, 60755, 60761, 60767, 60771, 60775, 60781, 60786, 60791, 60796, 60801, 60808, 60814, 60819, 60824, 60831, 60836, 60842, 60848, 60852, 60857, 60862, 60867, 60872, 60878, 60884, 60889, 60895, 60899, 60905, 60911, 60917, 60923, 60926, 60930, 60935, 60941, 60946, 60950, 60954, 60960, 60964, 60969, 60975, 60980, 60984, 60989, 60994, 61000, 61005, 61009, 61014, 61020, -1, 61024, 61029, 61035, 61042, 61046, 61050, 61056, 61062, 61068, 61075, 61079, 61085, 61092, 61096, 61102, 61106, 61111, 61116, 61122, 61126, 61130, 61134, 61139, 61146, 61151, 61155, 61161, 61167, 61172, 61176, 61182, 61186, 61190, 61195, 61199, 61203, 61208, 61213, 61218, 61224, 61230, 61236, 61241, 61248, 61253, 61257, 61263, 61268, 61272, 61277, 61281, 61286, 61292, 61297, 61302, 61308, 61313, 61319, 61325, 61329, 61334, 61338, 61342, 61346, 61350, 61355, 61359, 61365, 61371, 61376, 61381, 61386, 61390, 61396, 61400, 61406, 61412, 61418, 61424, 61428, 61434, 61439, 61444, 61450, 61455, 61461, 61467, 61473, 61478, 61483, 61487, 61492, 61498, 61503, 61507, 61512, 61518, 61524, 61528, 61532, 61537, 61543, 61551, 61555, 61559, -1, 61563, 61569, 61574, 61578, 61584, 61588, 61594, 61600, 61606, 61611, 61617, 61622, 61628, 61634, 61638, 61643, 61649, 61653, 61657, 61663, 61668, 61672, 61676, 61680, 61684, 61689, 61694, 61698, 61703, 61707, 61712, 61716, 61722, 61727, 61733, 61739, 61743, 61747, 61752, 61758, 61763, 61768, 61774, 61780, 61786, 61791, 61796, 61801, 61806, 61811, 61816, 61819, 61824, 61829, 61835, 61839, 61843, 61848, 61854, 61859, 61864, 61869, 61875, 61881, 61886, 61890, 61894, 61898, 61903, 61909, 61915, 61919, 61925, 61932, 61936, 61941, 61947, 61952, 61957, 61964, 61971, 61976, 61980, 61984, 61989, 61994, 61998, 62005, 62011, 62015, 62022, 62028, 62033, 62039, 62045, 62050, 62056, 62062, 62067, 62073, 62078, 62083, 62088, 62094, 62100, 62107, 62113, 62118, 62124, 62129, 62133, 62138, 62143, 62148, 62154, 62161, -1, 62166, 62172, 62176, 62180, 62185, -1, -1, 62190, 62194, 62199, 62204, 62210, 62216, 62221, 62227, 62233, 62238, 62244, 62250, 62257, 62261, 62266, 62270, 62274, 62279, 62284, 62289, 62295, 62300, 62305, 62309, 62314, 62318, 62322, 62327, 62331, 62336, 62340, 62344, 62349, 62356, 62360, 62365, 62369, 62373, 62379, 62384, 62389, 62394, 62399, 62405, 62410, 62414, 62418, 62422, 62426, 62431, 62435, 62440, 62445, 62450, 62455, 62461, 62467, 62473, 62478, 62482, 62488, 62493, 62500, 62504, 62508, 62512, 62517, 62523, 62527, 62532, 62537, 62541, 62545, 62550, 62556, 62561, 62565, 62571, 62576, 62581, 62586, 62591, 62597, 62602, 62607, 62612, 62617, 62623, 62629, 62633, 62638, -1, 62644, 62649, 62654, 62658, 62663, 62667, 62671, 62677, 62682, 62689, 62694, 62700, 62707, 62711, 62715, 62719, 62723, 62727, 62731, 62736, 62742, 62747, 62753, 62758, 62763, 62769, 62773, 62779, 62783, 62787, 62793, 62797, 62801, 62805, 62809, 62813, 62819, 62824, 62829, 62835, 62840, 62845, 62850, 62857, 62861, 62866, 62871, 62877, 62883, 62888, 62894, 62898, 62904, 62908, 62912, 62916, 62922, 62926, 62933, 62938, 62944, 62949, 62953, 62957, 62963, 62969, 62975, 62979, 62984, 62988, 62994, 63000, 63005, 63011, 63016, 63023, 63030, 63037, 63041, 63047, 63052, 63058, 63063, 63071, 63077, 63082, 63086, 63092, 63099, 63105, 63111, 63117, 63122, 63127, 63133, 63139, -1, -1, 63145, 63149, 63155, 63160, 63165, 63169, 63174, 63180, 63184, 63190, 63195, 63200, 63204, 63208, 63212, 63217, 63222, 63228, 63234, 63240, 63244, 63248, 63252, 63258, 63263, 63270, 63275, 63280, 63284, 63290, 63296, 63303, 63307, 63311, 63316, 63321, 63326, 63332, 63337, 63342, 63347, 63353, 63357, 63362, 63367, 63372, 63376, 63382, 63388, 63394, 63399, 63405, 63409, 63414, 63419, 63423, 63427, 63434, 63441, 63448, 63453, 63459, 63464, 63469, 63474, 63479, 63485, 63489, 63494, 63500, 63505, 63510, 63515, 63521, 63525, 63530, 63534, 63540, 63546, 63552, 63556, -1, 63561, -1, 63566, 63570, 63575, 63580, 63585, 63591, 63596, 63600, 63605, 63609, 63613, 63618, 63623, 63629, 63634, 63638, 63644, 63650, 63655, 63661, 63667, 63671, 63675, 63681, 63687, 63693, 63698, 63703, 63708, 63712, 63717, 63721, 63725, 63729, 63734, 63738, 63744, 63750, 63756, 63761, 63766, 63771, 63775, 63779, 63784, 63789, 63794, 63798, 63804, -1, 63810, 63815, 63820, 63825, 63831, 63835, 63840, 63845, 63849, 63855, 63861, 63867, 63873, 63878, 63882, 63886, 63890, 63895, 63899, 63904, 63908, 63913, 63918, 63923, 63928, 63932, 63937, 63943, 63948, 63953, 63957, 63961, 63967, 63972, 63977, 63981, 63987, 63993, 63999, 64004, -1, 64009, 64015, 64021, 64026, 64031, 64036, 64040, 64044, 64049, 64055, 64059, 64063, 64068, 64074, 64078, 64084, 64089, 64094, 64099, 64105, 64111, 64117, 64121, 64126, 64132, 64136, 64140, 64147, 64151, 64156, 64161, 64167, 64171, 64176, 64181, 64187, 64193, 64197, 64203, 64209, 64215, 64220, 64225, 64230, 64236, 64241, 64246, 64252, 64257, 64262, 64267, 64271, -1, -1, 64276, 64282, 64286, 64290, 64296, 64302, 64308, 64313, 64318, 64322, 64328, 64333, 64339, 64344, 64350, 64356, 64361, 64366, 64374, 64380, 64386, 64392, 64397, 64402, 64407, 64413, 64417, 64423, 64429, 64433, 64439, 64444, 64449, 64454, 64461, 64465, 64470, 64476, 64481, 64485, 64489, 64495, 64500, 64506, 64512, -1, 64518, 64523, 64527, 64532, 64537, 64542, 64548, 64553, 64559, 64564, 64570, 64575, 64580, 64585, 64589, 64594, 64598, 64603, 64610, 64616, 64621, 64627, 64633, 64637, 64643, 64649, 64654, 64661, 64666, 64671, 64676, 64681, 64687, 64692, 64697, 64702, 64708, 64712, 64719, 64724, 64729, 64736, 64741, 64745, 64749, 64753, 64759, 64763, 64768, 64773, 64778, 64783, 64789, 64793, 64799, 64805, 64810, 64816, 64821, 64828, 64833, 64838, 64845, 64852, 64857, -1, 64864, 64868, 64873, 64880, 64885, 64889, 64895, 64899, 64903, 64908, 64913, 64919, 64925, 64931, 64935, 64940, 64945, 64952, 64957, 64962, 64967, 64973, 64979, 64985, 64990, 64995, 65000, 65006, 65011, 65016, 65022, 65027, -1, 65034, 65038, 65044, 65049, 65055, 65061, 65065, 65071, 65077, 65082, 65088, 65094, 65100, 65105, 65111, 65116, 65120, 65126, 65131, 65136, 65141, 65147, 65152, 65157, 65162, 65168, 65173, 65178, 65183, 65189, 65196, 65200, 65205, 65210, 65217, 65222, 65227, -1, 65232, 65237, 65243, 65247, -1, 65252, 65258, 65263, -1, 65267, 65271, 65275, 65282, 65287, 65291, 65297, 65303, 65309, 65314, 65319, 65325, 65331, 65337, 65341, 65347, 65352, 65358, 65362, 65366, 65371, 65375, 65380, 65384, 65389, 65395, 65399, 65404, 65409, 65417, 65422, 65426, 65431, 65435, -1, -1, 65439, 65444, 65449, 65455, 65460, 65464, 65470, 65475, 65480, 65485, 65490, 65495, 65500, 65504, 65509, 65513, 65519, 65523, 65527, 65531, 65537, 65543, 65549, 65555, 65562, 65567, 65571, 65578, 65583, 65589, 65594, 65599, 65603, 65608, 65612, 65618, 65623, 65627, -1, 65631, 65638, 65645, -1, -1, -1, -1, 65651, 65657, 65661, 65666, 65673, 65679, 65684, 65689, 65695, 65701, 65707, 65713, 65720, 65726, 65732, 65736, 65742, 65747, 65752, 65758, 65764, 65768, 65774, 65780, 65786, 65791, 65798, 65805, 65809, 65814, 65819, 65824, 65828, 65833, 65840, 65845, 65850, 65856, 65860, 65866, 65871, 65876, 65881, 65886, 65892, 65897, 65902, 65907, 65912, 65917, 65922, 65926, 65931, -1, -1, 65936, 65942, 65947, 65952, 65958, 65964, 65970, 65973, 65977, 65984, 65989, 65993, 65997, 66001, 66006, 66010, 66014, 66018, 66023, 66030, 66035, 66041, 66048, 66053, 66058, 66062, 66068, 66074, 66079, 66085, -1, 66094, 66101, 66106, 66110, 66114, 66120, 66126, 66130, 66136, 66142, 66146, 66151, 66157, 66162, 66166, 66172, 66177, 66183, 66188, 66192, 66196, 66201, 66205, 66210, 66216, 66221, 66225, 66229, 66236, -1, 66241, 66248, 66254, 66260, 66266, 66270, 66274, 66278, 66282, 66288, 66293, 66300, 66306, 66310, 66316, 66321, 66326, 66332, 66338, 66343, 66349, 66354, 66360, 66366, 66371, 66375, 66381, 66385, 66390, 66396, 66402, 66407, 66412, 66417, 66422, 66427, 66432, 66438, 66442, 66448, -1, -1, 66453, 66459, 66463, 66467, 66472, 66477, 66482, 66487, 66492, 66497, 66501, 66506, 66512, 66518, 66523, 66528, 66533, 66539, 66544, 66548, 66553, 66559, 66564, 66571, 66577, 66582, 66586, 66592, 66597, 66602, 66607, 66613, 66619, 66624, 66628, 66633, 66639, 66645, 66649, 66653, 66658, 66663, 66667, 66671, 66675, 66680, 66687, -1, 66693, 66697, 66701, 66706, 66712, 66717, 66721, 66726, 66732, -1, 66736, 66742, 66747, 66752, 66758, 66763, 66769, -1, 66775, 66780, 66784, 66790, 66795, -1, 66800, 66806, 66812, 66816, 66822, 66836, 66840, 66847, 66852, 66859, 66865, 66869, -1, 66874, 66879, 66884, 66888, 66892, 66896, 66901, 66905, 66910, 66914, 66922, 66926, 66933, 66941, 66945, 66951, 66956, 66963, 66969, 66976, 66982, 66987, 66992, 66998, 67004, 67009, 67013, 67021, 67026, 67031, 67037, 67042, 67048, 67052, 67060, -1, 67065, 67069, 67073, 67080, 67085, 67094, 67099, 67104, 67109, 67114, 67118, 67123, 67128, 67134, 67140, 67145, 67149, 67155, 67159, 67164, 67168, 67173, 67177, 67183, 67187, 67192, 67196, 67203, 67207, 67211, 67217, 67223, 67229, 67233, 67237, 67241, 67247, 67253, 67259, 67263, 67267, 67271, 67275, 67279, 67284, 67288, 67294, 67299, 67304, 67310, 67315, 67319, 67323, 67328, 67334, 67340, 67346, 67350, 67354, 67359, 67364, 67368, 67373, 67378, 67383, 67387, 67392, 67397, 67401, 67406, -1, 67412, 67419, 67427, 67431, 67435, 67440, 67444, 67450, 67455, 67459, 67465, 67470, 67475, 67481, 67487, 67492, 67496, 67501, 67506, 67510, 67515, 67521, 67525, 67530, 67538, 67545, 67549, 67554, 67560, 67564, 67569, 67573, 67578, 67584, 67592, 67597, 67604, 67609, 67613, 67619, 67626, 67630, 67635, 67639, 67643, 67647, 67654, 67659, 67664, 67669, 67673, 67679, 67684, 67688, 67692, 67696, 67701, 67706, 67711, 67715, 67720, 67724, 67728, 67734, 67740, 67746, 67751, 67757, 67761, 67767, 67771, 67776, 67782, 67786, 67792, 67798, 67804, 67809, 67813, 67818, 67823, 67828, 67835, 67839, 67844, 67848, 67852, 67858, 67862, 67868, 67872, 67877, 67882, 67888, 67894, 67899, 67904, 67909, 67914, 67918, 67923, 67929, 67935, 67940, 67945, 67950, 67954, 67958, 67962, 67968, 67973, 67978, 67982, 67988, 67995, 68000, 68005, 68010, 68016, 68020, 68027, 68031, 68036, 68043, 68047, 68053, 68058, 68062, 68067, 68073, 68078, 68083, 68087, 68093, 68097, 68102, 68108, 68112, 68118, 68124, 68129, 68134, 68139, 68145, 68151, 68157, 68161, 68166, 68171, 68176, 68181, 68187, 68192, 68197, 68202, 68207, 68212, 68217, 68221, 68227, 68232, 68238, 68243, 68247, 68253, 68258, 68262, 68267, -1, 68272, 68276, 68282, 68290, 68295, 68300, 68306, 68313, 68317, 68324, 68330, 68334, 68338, 68343, 68348, 68353, 68358, 68362, 68366, 68373, 68377, 68382, 68386, 68392, 68397, 68403, 68409, 68415, 68420, 68425, 68429, 68433, 68439, 68443, 68448, 68454, 68460, 68465, 68469, 68475, 68480, 68486, 68491, 68496, 68501, 68507, 68512, 68517, 68524, 68530, 68534, 68538, 68544, 68548, 68554, 68560, 68565, 68570, 68576, 68580, 68585, 68591, 68597, 68601, 68605, 68609, 68613, 68617, 68623, 68628, 68632, 68638, 68642, 68646, 68650, 68656, 68660, 68666, 68671, 68676, 68680, 68684, 68688, 68694, 68698, 68704, 68708, 68712, 68717, 68722, 68726, 68731, 68737, 68743, 68748, 68753, 68758, 68763, 68768, 68774, 68779, 68784, 68788, 68793, 68799, 68805, 68812, 68818, 68823, 68827, 68831, 68837, 68843, 68847, 68853, 68857, 68861, 68865, 68870, 68875, 68881, 68885, 68889, 68893, 68898, 68905, 68911, 68915, 68919, 68924, 68929, 68935, 68940, 68944, 68950, 68956, 68961, 68965, 68971, 68976, 68982, 68988, 68992, 68999, 69005, 69011, 69017, 69022, 69027, 69033, 69037, 69042, 69046, 69051, 69056, 69061, 69066, 69071, 69075, 69082, 69087, 69092, 69098, 69103, 69110, 69114, 69119, -1, 69124, 69130, 69134, 69139, 69144, 69147, 69154, 69158, 69162, 69166, 69173, 69178, 69183, 69188, 69194, 69200, 69206, 69211, 69217, 69222, 69227, 69233, 69239, 69243, 69248, 69252, 69257, 69261, 69265, 69271, 69275, 69280, 69286, 69291, -1, 69300, 69305, 69311, 69316, 69322, 69327, 69332, 69336, 69340, 69346, 69351, 69356, 69363, 69368, 69374, 69379, 69385, 69390, 69397, 69401, 69405, 69408, 69413, 69420, 69424, 69430, 69435, 69439, 69445, 69451, 69456, 69462, 69467, 69472, 69477, 69481, 69485, 69490, 69496, 69501, -1, 69505, 69512, 69516, 69521, 69526, 69530, 69535, 69540, 69546, 69552, 69556, 69562, 69567, 69572, 69577, 69583, 69588, 69594, 69600, 69605, 69612, 69618, 69625, 69631, 69637, 69643, 69648, 69654, 69660, 69664, 69669, 69673, 69679, 69683, 69690, 69695, 69699, 69704, 69709, 69715, 69720, 69725, 69730, 69734, 69739, 69744, 69750, 69754, 69759, 69764, 69770, 69774, 69780, 69785, 69791, 69798, 69803, 69808, 69814, 69819, 69823, 69828, 69832, 69839, 69844, 69851, 69857, 69862, 69866, 69871, 69877, 69881, 69885, 69891, 69896, 69901, 69907, 69911, 69917, 69922, 69929, -1, 69934, 69940, 69945, 69949, 69953, 69959, 69965, 69971, 69976, 69980, 69986, 69991, 69997, 70004, 70008, 70015, 70020, 70024, 70030, 70035, 70040, 70045, -1, 70049, 70055, 70059, 70063, 70068, 70072, 70077, 70083, 70089, 70094, 70099, 70104, 70110, 70114, 70119, -1, 70125, 70129, 70134, 70138, 70143, 70149, 70154, 70159, 70164, 70168, 70172, 70178, 70184, 70189, 70194, 70199, 70203, 70207, 70212, 70217, 70221, 70226, 70233, 70238, 70243, 70248, 70252, 70258, 70262, 70266, 70271, 70276, 70282, 70286, 70293, 70297, 70303, 70308, 70313, 70319, 70324, 70328, 70333, 70338, 70342, 70347, 70353, 70358, 70364, 70368, 70372, 70384, 70391, 70397, 70402, 70407, 70413, 70418, 70424, 70428, 70441, 70453, 70459, 70463, 70469, 70473, 70479, 70483, 70495, 70501, 70508, 70513, 70521, 70527, 70533, 70538, 70544, 70550, 70556, 70562, 70568, 70580, 70584, 70590, 70594, 70600, 70605, 70609, 70613, 70619, 70626, 70632, 70637, 70643, 70647, 70651, 70656, 70662, 70668, 70673, 70678, 70683, 70689, 70695, 70701, 70706, 70713, 70720, 70726, 70733, 70739, 70745, 70750, 70757, 70761, 70766, 70772, 70779, 70783, 70787, 70793, 70799, 70805, 70811, 70817, 70822, 70827, 70833, 70838, 70844, 70848, 70853, 70859, 70865, 70871, 70876, 70882, 70888, 70892, 70898, 70902, 70906, 70911, 70916, 70921, 70928, 70932, 70937, 70942, 70946, 70952, 70958, 70963, 70968, 70974, 70979, 70983, 70989, 70993, 70998, 71003, 71010, 71014, 71018, 71023, 71028, 71033, 71039, 71044, 71048, 71052, 71056, 71061, 71066, 71070, 71074, 71079, 71084, 71088, 71093, 71098, 71104, 71109, 71114, 71118, 71122, 71126, 71131, 71135, 71140, 71144, 71149, 71155, 71160, 71166, 71172, 71176, 71181, 71188, 71195, 71202, 71208, 71213, 71217, 71222, 71227, 71235, 71241, 71246, 71253, 71260, 71266, 71270, 71275, 71280, 71284, 71289, 71294, 71299, 71304, 71309, 71313, 71321, 71326, 71332, 71336, 71341, 71347, 71353, 71357, 71362, 71368, 71373, 71379, 71383, 71388, 71392, 71398, 71404, 71409, 71413, 71418, 71423, 71428, 71433, 71438, 71442, 71446, 71450, 71456, 71464, 71470, 71475, 71480, 71484, 71489, 71493, 71497, 71502, 71506, 71511, 71517, 71521, 71526, 71532, 71536, 71540, 71545, 71549, 71555, 71560, 71566, 71571, 71577, 71581, 71588, 71594, 71600, 71606, 71613, 71619, 71623, 71628, 71633, 71638, 71643, 71649, 71654, 71659, 71664, 71668, 71673, 71678, 71684, 71690, 71696, 71700, 71706, 71710, 71716, 71722, 71726, 71730, 71735, 71740, 71745, 71749, 71754, 71759, 71765, 71771, 71777, 71781, 71787, 71794, 71800, 71805, 71810, 71814, 71819, 71824, 71828, 71834, 71838, 71843, 71847, 71852, 71857, 71861, 71866, 71869, 71874, 71878, 71883, 71887, 71892, 71896, 71901, 71907, 71914, 71918, 71922, 71927, 71933, 71937, 71943, 71949, 71953, 71957, 71962, 71967, 71973, 71977, 71982, 71987, 71991, 71995, 72000, 72005, 72010, 72014, 72020, 72024, 72029, 72033, 72041, 72046, 72051, 72056, 72062, 72068, 72073, 72079, 72083, 72088, 72093, 72100, 72106, 72112, 72116, 72121, 72125, 72131, 72137, 72144, 72150, 72155, 72160, 72165, 72171, 72176, 72180, 72184, 72189, 72194, 72200, 72207, 72211, 72217, 72223, 72229, 72234, 72239, 72245, 72250, 72255, 72260, 72264, 72269, 72274, 72280, 72286, 72292, 72298, 72302, 72307, 72311, 72317, 72321, 72326, 72330, 72335, 72340, 72345, 72351, 72356, 72361, 72366, 72370, 72375, 72381, 72387, 72392, -1, 72399, 72403, 72408, 72413, 72420, 72426, 72432, 72438, 72443, 72447, 72453, 72458, 72464, 72469, 72475, 72481, -1, 72485, 72490, 72494, 72498, 72504, 72508, 72513, 72518, 72523, 72527, 72532, 72537, 72542, 72546, 72550, 72555, 72562, 72567, 72571, 72577, 72582, 72586, 72590, 72596, 72602, 72607, 72611, 72614, 72619, 72624, 72628, 72633, 72639, 72645, 72649, 72653, 72660, 72665, 72672, 72677, 72681, 72686, 72691, 72697, 72701, 72705, 72710, 72716, 72720, 72726, 72733, 72737, 72743, 72747, 72753, 72757, 72762, 72767, 72773, 72778, 72783, 72788, 72793, 72798, 72802, 72807, 72812, 72818, 72823, 72827, 72833, 72837, 72842, 72846, 72852, 72856, 72861, 72867, 72874, 72879, 72883, 72889, 72893, 72897, 72901, 72906, 72910, 72915, 72921, 72926, 72932, 72936, 72940, 72945, 72950, 72955, 72960, 72965, 72969, 72974, 72981, 72986, 72990, 72996, 73002, 73006, 73011, 73015, 73021, 73026, 73032, 73036, 73040, 73045, 73051, 73057, 73061, 73065, 73069, 73073, 73080, 73085, 73089, 73095, 73101, 73106, 73110, 73116, 73122, 73129, 73134, 73139, 73143, 73148, 73154, 73159, 73164, 73170, 73177, 73182, 73187, 73193, 73198, 73204, 73210, 73215, 73220, 73225, 73230, 73236, 73240, 73245, 73251, 73258, 73263, 73269, 73274, 73278, 73284, 73291, 73295, 73301, 73306, 73313, 73318, 73322, 73327, 73333, 73339, 73345, 73349, 73355, 73360, 73364, 73368, 73372, 73378, 73383, 73389, 73395, 73399, 73405, 73410, 73416, 73420, 73425, 73429, 73433, 73439, 73445, 73450, 73457, 73463, 73468, 73474, 73480, 73486, 73491, 73495, 73502, 73507, 73513, 73520, 73525, 73530, 73536, 73541, 73547, 73551, 73558, 73563, 73569, 73572, 73577, 73583, 73587, 73592, 73597, 73603, 73609, 73615, 73620, 73625, 73631, 73636, 73643, 73648, 73653, 73659, 73666, 73670, 73675, 73680, 73686, 73692, 73697, 73701, 73705, 73709, 73713, 73718, 73722, 73726, 73730, 73735, 73740, 73746, 73750, 73755, 73759, 73764, 73770, 73774, 73779, 73784, 73790, 73796, 73801, 73805, 73810, 73816, 73820, 73825, 73830, 73835, 73840, 73844, 73848, 73853, 73859, 73865, 73870, 73874, 73880, 73885, 73891, 73897, 73901, 73906, 73911, 73918, 73923, 73929, 73934, 73940, 73944, 73951, 73955, 73961, 73965, 73969, 73975, 73981, 73986, 73991, 73996, 74002, 74009, 74013, -1, 74019, 74024, 74029, 74033, 74039, 74043, 74048, 74054, 74060, 74066, 74072, 74077, 74083, 74088, 74092, 74096, 74102, 74107, 74112, 74117, 74123, 74127, 74131, 74136, 74142, 74148, 74152, 74158, 74162, 74167, 74173, 74178, 74184, 74189, 74194, 74199, 74205, 74211, 74216, 74222, 74226, 74233, 74238, 74244, 74250, 74255, 74259, 74265, 74271, 74277, 74282, 74286, 74291, 74297, 74302, 74307, 74312, 74317, 74322, 74326, 74332, 74336, 74341, 74346, 74350, 74356, 74361, 74366, 74372, 74378, 74382, 74388, 74394, 74399, 74405, 74409, 74415, 74421, 74426, 74431, 74436, 74442, 74446, 74450, 74454, 74459, 74463, 74468, 74472, 74479, 74483, 74488, 74495, 74501, 74505, 74510, 74515, 74520, 74524, 74528, 74533, 74538, 74543, 74549, 74554, 74558, 74563, 74568, 74573, 74576, 74580, 74584, 74589, 74594, 74599, 74606, 74611, 74616, 74621, -1, 74626, 74632, 74636, 74640, 74645, 74649, 74653, 74658, 74663, 74668, 74672, 74678, 74684, 74688, 74693, 74697, 74702, 74706, 74712, 74716, 74722, 74728, 74734, 74739, 74743, 74747, 74751, 74755, 74761, 74765, 74770, 74774, 74780, -1, 74786, 74790, 74799, 74804, 74810, 74816, 74821, 74828, 74833, 74836, 74841, 74846, 74850, 74855, 74859, 74864, 74869, 74875, 74880, 74886, 74892, -1, 74896, 74902, 74908, 74913, -1, 74919, 74924, -1, 74930, 74936, 74942, 74947, 74953, 74959, 74965, 74969, 74975, 74980, 74986, 74992, 74998, 75003, 75008, 75011, 75016, 75022, 75028, 75033, 75038, 75043, 75048, -1, 75052, 75058, 75062, 75068, 75074, 75079, 75085, 75091, 75097, 75103, 75108, 75114, 75120, 75126, 75130, 75136, 75142, 75147, 75152, 75156, 75162, 75167, 75173, 75179, 75183, 75187, 75191, 75196, 75201, 75207, 75212, 75217, 75222, 75226, 75230, 75235, 75240, 75246, 75252, 75257, 75261, 75267, 75273, 75278, 75283, 75289, 75293, 75298, 75303, 75309, 75315, 75319, 75323, 75328, 75334, 75340, 75346, 75351, 75357, 75361, 75366, 75372, 75378, 75382, 75387, 75392, 75398, -1, 75402, 75408, 75414, 75419, 75424, 75428, 75434, 75440, 75444, 75447, 75451, 75456, 75460, 75466, 75472, 75477, 75481, 75486, 75492, 75497, 75502, 75508, 75513, 75517, 75523, 75528, 75533, 75538, 75543, 75548, 75552, -1, 75556, 75562, 75567, 75574, 75580, 75584, 75588, 75594, 75598, 75602, 75607, 75614, 75620, 75625, 75630, 75636, 75640, 75644, 75648, 75653, 75659, 75665, -1, 75671, 75675, 75681, 75686, 75690, 75696, 75702, 75708, 75712, 75717, 75723, 75729, 75736, 75741, 75745, 75751, 75755, 75759, 75765, -1, 75771, 75778, 75784, 75789, 75795, 75799, 75805, 75809, 75814, 75820, 75825, 75829, 75834, 75838, 75843, 75849, 75853, 75860, 75864, 75868, 75872, 75877, 75881, 75885, 75890, 75896, 75900, 75906, 75912, 75917, -1, -1, 75921, 75926, 75930, 75936, 75943, 75948, 75953, 75958, 75962, 75966, 75971, 75976, 75981, 75987, 75991, 75997, 76003, 76007, 76011, 76019, 76025, 76030, 76035, 76040, 76045, 76050, 76054, 76060, 76065, 76070, 76074, 76078, 76082, 76086, 76091, 76097, 76103, 76108, 76112, 76117, 76123, 76128, -1, 76135, 76139, 76144, 76149, 76154, 76160, 76164, 76168, 76172, 76176, 76181, 76187, 76192, 76197, 76201, 76205, 76210, 76216, 76221, 76225, 76231, 76235, 76239, 76243, 76250, 76254, 76260, 76266, 76271, 76276, 76281, 76286, 76290, 76295, 76301, 76306, 76312, 76317, 76323, 76328, 76333, 76337, 76342, 76347, 76352, 76356, 76360, 76366, 76371, 76377, 76381, 76387, 76392, 76397, 76402, 76406, 76412, 76417, 76422, 76427, 76432, 76436, 76441, 76445, 76450, 76456, 76460, 76466, 76470, 76476, 76482, 76486, 76490, 76495, 76499, -1, 76503, 76509, 76515, 76521, 76525, 76530, 76536, 76540, 76544, -1, 76548, 76554, 76558, 76562, 76566, 76570, 76574, 76580, 76585, 76591, 76596, 76600, 76606, 76610, 76615, 76619, 76625, 76630, 76634, 76639, 76644, 76649, 76653, 76657, 76662, 76667, 76672, 76676, 76680, 76685, 76689, 76694, 76698, 76702, 76707, 76712, 76716, 76722, 76728, 76734, 76739, 76744, 76751, 76756, 76761, 76766, 76770, 76776, 76781, 76787, 76791, 76796, 76800, 76804, 76808, 76813, 76817, 76821, 76825, 76830, 76834, 76838, 76842, 76848, 76852, 76859, 76865, 76870, 76876, 76881, 76886, 76891, 76896, 76900, 76904, 76909, 76913, 76920, 76926, 76931, 76936, 76940, 76945, 76949, 76954, 76959, 76964, 76968, 76972, 76977, 76982, 76988, 76992, 76996, 77001, 77007, 77011, 77015, 77021, 77025, 77030, 77035, 77041, 77045, 77052, 77056, 77062, 77068, 77072, 77077, 77081, 77085, 77090, 77095, 77101, 77107, 77112, 77116, 77121, 77126, 77131, 77137, 77143, 77147, 77153, 77159, 77163, 77167, 77171, -1, 77176, 77180, 77184, 77190, 77194, 77198, 77202, 77207, 77212, 77219, 77225, 77229, 77236, 77241, 77246, 77252, 77256, 77260, 77264, 77268, 77274, 77279, 77284, 77289, 77293, 77298, 77303, 77307, 77313, 77318, 77323, 77327, 77333, 77337, 77343, 77348, 77353, 77357, 77361, 77365, 77369, 77375, 77380, 77385, -1, 77389, 77393, 77400, 77405, 77409, 77414, 77420, 77424, 77430, 77436, 77442, 77447, 77451, 77456, 77462, 77466, 77471, 77477, 77482, 77486, 77491, 77495, 77500, 77505, 77512, 77517, 77523, 77527, -1, 77533, 77539, 77545, 77549, 77554, 77559, 77563, 77568, 77575, 77579, 77586, 77592, 77596, 77601, 77607, 77612, 77619, 77625, 77629, 77634, 77639, 77645, 77650, 77656, 77661, 77666, 77672, 77676, 77681, 77687, 77693, 77699, 77703, 77708, 77713, 77718, 77726, 77731, 77737, 77743, 77751, 77758, 77764, 77771, 77776, 77782, 77786, 77791, 77795, 77799, 77805, 77809, 77813, 77819, 77824, -1, 77829, 77834, 77838, 77842, 77846, 77850, 77854, 77861, 77866, 77871, 77877, 77883, 77887, 77893, 77899, 77903, 77909, 77913, 77917, 77922, 77930, -1, 77936, 77942, 77948, 77955, 77960, 77966, 77971, 77977, 77983, 77990, 77995, 78000, 78006, 78011, 78015, 78020, 78025, 78030, 78036, 78041, 78047, 78051, 78057, 78063, 78068, 78073, 78079, 78083, 78089, 78094, 78100, 78106, 78112, 78118, 78124, 78131, 78135, 78139, 78144, 78150, 78156, 78162, 78168, 78174, 78178, 78183, 78189, 78193, 78198, 78204, 78210, 78216, 78223, 78229, 78235, 78240, 78246, 78252, 78257, 78263, 78268, 78273, 78277, 78283, 78287, 78292, 78297, 78303, 78308, 78316, 78320, 78324, 78330, 78334, 78340, 78344, 78350, 78356, 78361, 78365, 78371, 78377, 78381, 78387, 78393, 78398, 78402, 78406, 78412, 78416, 78422, 78428, 78435, 78440, 78444, 78449, 78453, 78458, 78462, 78466, 78471, 78476, 78481, 78487, 78491, 78495, 78499, 78504, 78509, 78513, 78517, 78521, 78527, 78531, 78535, 78539, 78544, 78549, 78554, 78558, 78563, 78568, 78573, 78577, 78582, 78588, 78595, 78601, 78608, 78614, 78619, 78624, 78628, 78633, 78638, 78643, 78649, 78653, 78660, 78665, 78671, 78677, 78682, 78688, 78693, 78697, 78701, 78708, 78713, 78719, 78723, 78727, 78733, 78737, 78744, 78749, 78754, 78758, 78764, 78770, 78777, 78781, 78785, 78790, 78794, 78798, 78802, 78808, 78812, 78818, 78824, 78829, 78835, 78840, 78845, 78852, 78858, 78863, 78868, 78873, 78879, 78885, 78891, 78895, 78900, 78905, 78911, 78916, 78922, 78928, 78934, 78939, 78942, 78948, 78954, 78960, 78964, 78969, 78974, 78978, 78982, 78986, 78990, 78995, 79001, 79005, 79011, 79017, 79021, 79026, 79033, 79039, 79044, 79050, 79054, 79058, 79062, 79067, 79073, 79078, 79082, 79087, 79091, 79097, 79103, 79109, 79114, 79120, 79126, 79132, 79136, 79140, 79144, 79148, 79153, 79158, 79163, 79168, 79174, 79179, 79185, 79191, 79197, 79202, 79209, 79215, 79221, 79227, 79234, 79238, 79243, 79248, 79253, 79259, 79263, 79267, 79273, 79279, 79283, 79288, 79295, 79301, 79306, 79311, 79317, 79324, 79330, 79336, 79341, 79347, 79352, 79357, 79362, 79368, -1, 79374, 79379, 79384, 79389, 79394, 79398, 79404, 79409, 79415, 79420, 79425, 79430, 79437, 79442, 79447, 79453, 79459, 79465, 79471, 79477, 79481, 79485, 79489, 79495, 79500, 79506, 79511, 79516, 79523, 79529, 79534, 79540, 79544, 79548, 79553, 79557, 79561, 79567, 79572, 79578, 79583, 79590, 79595, 79601, 79606, 79610, 79615, 79622, 79626, 79630, 79635, 79639, 79643, 79649, 79654, 79658, 79664, 79670, 79674, 79679, 79683, 79688, 79693, 79697, 79703, 79708, 79714, 79722, 79727, 79731, 79737, 79743, 79749, 79753, 79757, 79761, 79767, 79773, 79778, 79784, 79788, 79794, 79799, 79804, 79809, 79815, 79821, 79828, 79833, 79838, 79843, 79849, 79853, 79858, -1, 79863, 79868, 79874, 79879, 79884, 79888, 79892, 79896, 79901, 79905, 79911, 79916, 79920, 79926, 79932, 79938, 79942, 79948, -1, 79953, 79958, 79963, 79967, 79972, 79977, 79983, 79988, 79992, 79996, 80002, -1, 80006, 80012, 80018, 80025, 80031, 80036, 80041, 80047, 80053, 80059, 80065, 80069, 80073, 80079, 80084, 80090, 80094, 80099, 80105, 80114, 80120, 80125, 80131, 80136, 80143, 80147, 80153, 80159, 80165, 80171, 80175, 80179, 80184, 80190, 80195, 80201, 80205, 80209, 80213, 80218, 80224, 80229, 80235, 80239, 80244, 80249, 80255, 80259, 80263, -1, 80268, 80274, 80280, 80284, 80289, 80293, 80298, 80304, 80309, 80314, 80318, -1, 80323, 80327, 80332, 80342, 80346, 80350, 80354, 80359, 80363, 80367, 80371, 80375, 80381, 80387, 80391, 80395, 80401, 80405, 80409, 80413, 80419, 80425, 80429, 80433, 80438, 80444, 80449, 80457, -1, 80462, 80467, -1, 80471, 80479, 80486, 80492, 80496, 80503, 80508, 80514, 80518, 80523, 80527, 80531, 80535, 80540, 80545, 80552, 80557, 80563, 80569, 80574, 80581, 80586, 80591, 80597, 80603, 80608, 80614, 80619, 80623, 80629, 80633, 80639, 80644, 80648, 80652, 80657, 80661, 80665, 80670, 80674, 80679, 80684, 80690, 80695, 80703, 80708, 80716, 80722, 80726, 80731, 80736, 80741, 80747, 80754, 80758, 80763, 80768, 80773, 80777, 80784, 80791, 80797, 80801, -1, 80807, 80813, 80819, 80824, 80830, 80835, 80839, 80844, 80848, 80853, 80859, 80864, 80868, 80874, 80879, 80883, 80889, 80896, 80901, 80906, 80910, 80915, 80921, 80926, 80931, 80937, 80941, 80945, 80950, 80955, 80960, 80965, 80970, 80974, 80978, 80983, 80988, 80993, 80998, 81003, 81009, 81013, 81018, 81023, 81029, 81034, 81038, 81043, 81048, 81053, 81058, 81063, 81067, 81073, 81078, 81083, 81088, 81093, 81099, 81104, 81108, 81113, 81117, 81121, 81127, 81133, 81138, 81143, 81147, 81151, 81156, 81162, 81167, 81172, 81176, 81182, 81187, 81193, 81198, 81204, 81208, 81213, 81219, 81224, 81230, 81235, 81242, 81248, 81252, 81259, 81264, 81268, 81272, 81277, 81282, 81288, 81294, 81299, 81305, 81310, 81315, 81320, 81326, 81331, 81336, 81341, 81348, 81352, 81356, 81362, 81368, 81373, 81378, 81382, 81388, 81394, 81399, 81404, 81410, 81416, 81422, 81426, 81431, 81437, 81443, 81449, 81454, 81459, 81464, 81470, 81474, 81479, 81484, 81490, 81494, 81501, 81508, 81513, 81518, 81523, 81529, 81535, 81540, 81546, 81552, 81556, 81563, 81568, 81573, 81579, 81585, 81591, 81596, 81601, 81607, 81612, 81616, 81621, 81626, 81632, 81636, 81640, 81646, 81651, 81656, 81661, 81665, 81671, 81675, 81680, 81685, 81692, 81698, 81702, 81707, 81713, 81719, 81724, 81729, 81733, 81737, 81744, 81750, 81756, 81762, 81766, 81770, 81776, 81780, 81785, 81791, 81797, 81803, 81808, 81812, 81817, 81822, 81828, 81834, 81840, 81846, 81851, 81856, 81861, 81866, 81871, 81875, 81881, 81886, 81892, 81898, 81904, 81908, 81913, 81918, 81924, 81929, 81934, 81938, 81942, 81948, 81955, 81960, 81965, 81970, 81975, 81979, 81985, 81990, 81994, 81998, 82005, 82012, 82020, 82024, 82031, 82037, 82041, 82047, 82053, 82059, 82063, 82069, 82076, 82080, 82085, 82091, 82097, 82102, 82107, 82111, 82116, 82122, 82128, 82134, 82140, 82146, 82151, 82155, 82160, 82164, 82169, 82175, 82180, 82186, 82192, 82198, 82203, 82208, 82212, 82217, 82222, 82227, 82234, 82240, 82245, 82250, 82256, 82262, 82266, 82272, 82280, 82286, 82291, 82297, 82302, 82306, 82312, 82316, 82322, 82326, 82331, 82337, 82343, 82348, 82354, 82362, 82367, 82372, 82379, 82383, 82389, 82394, 82398, 82403, 82409, 82414, 82418, 82422, 82427, 82433, 82439, 82443, 82449, 82455, 82460, 82466, 82471, 82475, 82481, 82485, 82489, 82494, 82499, 82503, 82509, 82514, 82521, 82527, 82532, 82537, 82541, 82545, 82551, 82557, 82561, 82567, 82573, 82577, 82583, 82588, 82593, 82600, 82606, 82610, 82615, 82620, 82626, 82633, 82638, 82643, 82647, 82653, 82658, 82663, 82669, 82674, 82680, 82686, 82691, 82696, 82702, 82707, 82712, 82716, 82721, 82727, 82733, 82738, 82744, 82749, 82755, 82760, 82765, 82770, 82775, 82781, 82785, 82792, 82796, 82800, 82807, 82812, 82816, 82820, 82826, 82833, 82839, 82844, 82850, 82855, 82861, 82865, 82871, 82875, 82880, 82885, 82889, 82895, 82899, 82903, 82908, 82914, 82919, 82923, 82928, 82934, 82938, 82944, 82948, 82952, 82957, 82962, 82968, 82975, 82980, 82984, 82989, 82995, 83001, 83006, 83010, 83016, 83022, 83027, 83034, 83040, 83045, 83051, 83056, 83060, 83065, 83070, 83075, 83081, 83085, 83090, 83094, 83100, 83106, 83112, 83116, 83121, 83125, 83130, 83137, 83141, 83146, 83151, 83156, 83162, 83168, 83172, 83177, 83183, 83187, 83192, 83198, 83203, 83208, 83213, 83218, 83224, 83229, 83234, 83239, 83244, 83250, 83255, 83260, 83264, 83270, 83274, 83280, 83284, 83289, 83296, 83302, 83307, 83311, 83317, 83323, 83327, 83333, 83338, 83344, 83350, 83355, 83359, 83364, 83369, 83375, 83380, 83385, 83391, 83398, 83403, 83408, 83414, 83420, 83426, 83432, 83438, 83443, 83447, 83452, 83457, 83461, 83465, 83469, 83473, -1, 83479, 83483, 83487, 83492, 83498, 83505, 83510, 83517, 83522, 83528, 83534, 83540, 83546, 83551, 83556, 83562, 83568, 83574, 83579, 83583, 83589, 83593, 83597, 83604, 83610, 83616, 83621, 83625, 83631, 83635, 83640, 83645, 83649, 83654, 83660, 83666, 83672, 83677, 83683, 83689, 83693, 83697, 83703, 83708, 83714, 83719, 83723, 83727, 83733, 83739, 83746, 83751, 83757, 83761, 83765, 83771, 83776, 83782, 83787, 83792, 83798, 83803, 83808, 83813, 83818, 83824, 83830, 83836, 83843, 83849, 83854, 83860, 83866, 83872, 83877, 83882, 83888, 83893, 83898, 83903, 83912, 83916, 83922, -1, 83927, 83933, 83939, 83945, 83951, 83956, 83962, 83967, 83972, 83979, 83983, 83989, 83995, 84000, 84005, 84009, 84015, 84021, 84027, 84033, 84039, -1, 84044, 84049, 84053, 84057, 84061, 84065, 84070, 84074, 84079, 84083, 84088, 84094, 84098, 84103, 84107, 84113, 84117, 84122, 84127, 84133, 84138, 84143, 84149, 84153, 84158, 84162, 84166, 84171, 84176, 84180, 84184, 84188, 84193, 84197, 84201, 84205, 84211, 84216, 84220, 84224, 84230, 84236, 84241, 84245, 84251, 84255, 84261, 84266, 84270, 84274, 84278, 84284, 84290, 84295, 84302, 84306, 84311, 84317, 84322, 84327, 84332, 84336, 84341, 84347, 84351, 84358, 84364, 84369, 84375, 84379, 84384, 84388, 84393, 84399, 84403, 84409, 84415, 84420, 84425, 84431, 84437, 84442, 84448, 84452, 84462, 84469, 84475, 84479, 84485, 84490, 84496, 84502, 84506, 84511, 84517, 84522, 84528, 84534, 84539, 84545, 84550, 84557, 84563, 84567, 84573, 84577, 84584, 84590, 84595, 84601, 84606, 84611, 84616, 84620, 84625, 84630, 84634, 84638, 84642, 84646, 84652, 84657, 84662, 84666, 84670, 84675, 84682, 84686, 84690, 84694, 84700, 84705, 84710, 84716, 84720, 84726, 84733, 84737, 84742, 84747, 84752, 84757, 84762, 84767, 84773, 84779, 84784, 84790, 84796, 84801, 84806, 84811, 84815, 84819, 84824, 84828, 84834, 84838, 84844, -1, 84848, 84853, 84858, 84864, 84868, 84873, 84877, 84882, 84888, 84893, 84898, -1, 84903, 84908, 84913, 84918, 84922, 84927, 84932, 84937, 84942, 84947, 84951, 84957, 84963, 84967, 84972, 84979, 84984, 84990, 84994, 85000, 85006, 85011, 85016, 85020, 85024, 85029, 85033, 85038, 85043, 85047, 85051, 85056, 85061, 85066, 85070, 85076, 85080, 85085, 85090, 85095, 85101, 85105, 85110, 85114, 85119, 85124, 85129, 85133, 85139, 85143, 85148, 85154, 85158, 85162, 85168, 85173, 85178, 85183, 85188, 85193, 85199, 85205, -1, 85210, 85215, 85220, 85226, 85231, 85237, 85244, 85249, 85253, 85259, 85265, 85270, 85276, 85282, 85286, 85290, 85295, -1, 85300, 85306, 85311, 85318, 85323, 85328, 85334, 85338, 85342, 85346, 85351, 85356, 85360, 85366, 85372, -1, 85381, 85387, 85391, 85397, 85402, 85413, 85418, 85424, 85430, 85436, 85441, 85447, 85453, 85459, 85463, 85470, 85476, 85482, 85487, 85492, 85497, 85502, 85508, 85513, 85517, 85523, 85529, 85535, 85539, 85543, 85549, 85553, 85557, 85561, 85565, 85569, 85575, 85581, 85586, 85590, 85594, 85598, 85603, 85608, 85613, 85617, 85621, 85627, 85634, 85638, 85643, 85649, 85653, 85659, 85665, 85669, 85675, 85681, 85686, 85691, 85695, 85702, 85706, 85711, 85716, 85720, 85725, 85730, 85735, 85741, 85747, 85753, 85759, 85764, 85768, 85774, 85779, 85784, 85790, 85794, 85799, 85804, 85809, 85813, 85819, 85823, 85827, 85832, 85837, 85843, 85848, 85854, 85861, 85868, 85873, 85879, 85884, 85890, 85895, 85900, 85905, 85909, 85913, 85917, 85923, 85928, 85933, 85938, 85942, 85946, 85951, 85955, 85961, 85965, 85969, 85975, 85981, 85987, 85992, 85997, 86002, 86009, 86014, 86019, 86023, 86027, 86031, 86035, 86039, 86044, 86048, 86054, 86060, 86066, 86070, 86074, 86080, 86084, 86089, 86095, 86100, 86104, 86111, 86116, 86120, 86126, 86131, 86137, 86144, 86151, 86155, 86158, 86164, 86170, 86176, 86180, 86185, 86192, 86198, 86203, 86208, 86213, 86218, 86223, 86228, 86232, 86237, 86241, -1, 86253, 86259, 86263, 86269, 86273, 86278, 86282, 86288, 86294, 86299, 86303, 86308, 86314, 86319, 86325, 86331, 86336, 86342, 86347, 86352, 86358, 86364, 86369, 86375, 86381, 86386, 86390, 86395, 86399, 86404, 86409, 86414, 86419, 86426, 86431, 86435, 86440, 86445, 86451, 86456, 86460, 86464, 86469, 86473, 86479, 86486, 86491, 86496, 86503, 86509, 86513, 86519, 86524, 86530, 86535, 86540, 86546, 86551, 86557, 86562, 86568, 86573, 86577, 86581, 86585, 86590, 86596, 86602, 86606, 86610, 86614, 86619, 86626, 86631, 86637, 86641, 86646, 86652, 86658, 86662, 86667, 86673, 86680, 86685, 86690, 86695, 86699, 86703, 86707, 86713, 86718, 86722, 86729, 86734, 86739, 86746, 86751, 86754, 86759, 86763, 86768, 86774, 86779, 86785, 86789, 86794, 86800, 86804, 86811, 86815, 86821, 86825, 86831, 86835, 86841, 86846, 86852, 86858, 86862, 86866, 86871, 86877, 86881, 86887, 86891, 86895, 86899, 86905, 86909, 86913, 86918, 86923, 86927, 86932, 86936, 86943, 86947, 86952, 86958, 86965, 86971, 86978, 86982, 86988, 86992, 86996, 87003, 87007, 87013, 87019, 87023, 87028, 87034, 87040, 87046, 87052, 87058, 87062, 87067, 87073, 87078, 87083, 87089, 87095, 87100, 87105, 87111, 87117, 87121, 87126, 87131, 87138, 87143, 87148, 87154, 87159, 87165, 87170, 87176, 87182, 87187, 87193, 87197, 87203, 87208, 87213, 87217, 87223, 87227, 87233, 87238, 87243, 87247, 87251, 87256, 87261, 87266, 87270, 87275, 87281, 87287, 87293, 87299, 87305, 87309, 87314, 87318, 87323, 87329, 87334, 87338, 87344, 87350, 87354, 87360, 87366, 87372, 87376, 87383, 87389, 87394, 87401, 87405, 87411, 87416, 87422, 87426, 87431, 87437, 87443, 87448, 87453, 87458, 87462, 87468, 87473, 87478, 87483, 87488, 87494, 87499, 87505, 87509, 87514, 87519, 87523, 87530, 87534, 87538, 87543, 87547, 87551, 87557, 87561, 87566, 87571, 87576, 87581, 87589, 87594, 87599, 87604, 87609, 87614, 87620, 87625, 87629, 87633, 87639, 87644, 87649, 87656, 87662, 87667, 87671, 87677, 87682, 87688, 87694, -1, 87698, 87702, 87707, 87712, 87717, 87724, 87730, 87736, 87741, 87746, 87754, 87761, 87767, 87773, 87779, 87784, 87788, 87793, 87797, 87803, 87807, 87814, 87819, 87823, 87829, 87835, -1, 87839, 87843, 87848, 87854, 87858, 87864, 87868, 87874, -1, 87880, 87885, 87889, 87895, 87901, 87905, 87912, 87918, 87924, 87930, 87935, -1, 87940, 87946, 87951, 87955, 87960, 87966, 87971, 87976, 87981, 87987, 87992, 87998, 88006, 88012, 88017, 88021, 88025, 88030, 88036, 88041, 88047, 88051, 88055, 88059, 88065, 88073, 88078, 88085, 88091, 88097, 88101, 88106, 88110, 88116, 88121, 88126, 88131, 88136, 88140, 88144, 88150, 88155, 88159, 88164, 88170, 88176, 88181, 88187, 88192, 88196, 88202, 88208, 88213, 88218, 88224, 88228, 88232, 88238, 88245, 88249, 88254, 88258, 88264, 88268, 88273, 88278, 88283, 88290, 88294, 88298, 88303, 88308, 88312, 88317, 88321, 88327, 88332, 88338, 88343, 88348, 88353, 88358, 88362, 88366, 88370, 88375, 88379, 88385, 88390, 88394, 88399, 88404, 88408, 88413, 88418, 88424, 88428, 88433, 88438, 88443, 88448, 88453, 88457, 88462, 88467, 88471, 88476, 88482, 88488, 88494, 88499, 88504, 88510, 88514, 88520, 88525, 88529, 88533, 88536, 88542, 88549, 88555, 88561, 88565, 88569, 88575, 88580, 88586, 88591, 88597, 88601, 88607, 88614, 88618, 88624, 88628, 88632, 88637, 88642, 88647, 88652, 88656, 88660, 88664, 88668, 88673, 88677, 88682, 88686, 88690, 88696, 88702, 88707, 88712, 88718, 88723, 88729, 88735, 88740, 88746, 88750, 88755, 88760, 88765, 88769, 88775, 88780, 88784, 88791, 88795, 88799, 88804, 88808, 88814, 88819, 88824, 88829, 88834, 88839, 88843, 88847, 88851, 88855, 88859, 88864, 88868, 88874, -1, 88880, -1, 88886, 88891, 88897, 88904, 88908, 88914, 88918, 88924, 88929, 88934, 88940, 88946, 88952, 88956, 88961, 88965, 88970, 88974, 88978, 88983, 88987, 88994, 88998, 89003, 89010, 89016, 89021, 89027, 89033, 89037, 89041, 89046, 89050, 89057, 89062, 89067, 89072, 89076, 89082, 89086, 89093, 89099, 89105, -1, 89112, 89117, 89122, 89128, 89133, 89139, 89144, 89148, 89154, 89160, 89166, 89171, 89177, 89181, 89185, 89191, 89196, 89201, 89207, 89211, 89218, 89224, 89228, 89233, 89238, 89243, 89251, 89255, 89260, 89265, 89269, 89273, 89279, 89284, 89288, -1, 89294, 89300, 89305, 89311, 89316, 89322, 89327, 89332, 89337, 89342, 89347, 89353, 89359, 89364, 89368, 89373, 89378, 89383, 89387, 89392, 89397, 89401, 89405, 89409, 89414, 89418, 89422, 89427, 89432, 89439, 89445, 89449, 89454, 89458, 89464, 89468, 89472, 89477, 89481, 89485, 89493, 89497, 89502, 89507, 89512, 89517, 89523, 89529, 89533, 89538, 89544, 89550, 89556, 89561, 89566, 89571, 89576, 89582, 89588, 89593, 89598, 89603, 89608, 89613, 89618, 89624, 89629, 89634, 89640, 89646, 89652, 89656, 89659, 89663, 89668, 89673, 89678, 89682, 89687, 89692, 89698, 89703, 89707, 89714, 89720, 89725, 89730, 89736, 89742, 89747, 89753, 89759, 89765, 89769, 89774, 89780, 89784, 89788, 89794, 89800, 89805, 89809, 89813, 89817, 89821, 89826, 89831, 89836, 89841, 89845, 89849, 89853, 89858, 89863, 89867, 89872, 89879, 89885, 89891, 89897, 89903, 89908, 89913, 89917, 89921, 89925, 89929, 89934, 89939, 89944, 89950, 89954, 89959, 89963, 89968, 89972, 89978, 89983, 89989, 89994, 90000, 90005, 90009, 90015, 90020, 90025, 90029, 90035, 90041, 90047, 90052, 90056, 90062, 90067, 90072, 90077, 90083, 90088, 90092, 90096, 90100, 90105, 90110, 90116, 90121, 90128, 90134, 90139, 90144, 90148, 90154, 90160, 90165, 90170, 90175, 90181, 90186, 90190, 90196, 90200, 90205, 90209, 90214, 90226, 90231, 90236, 90241, -1, -1, 90246, -1, 90252, -1, 90258, 90264, 90270, 90276, 90282, 90286, 90291, 90295, 90302, 90307, 90311, 90315, 90319, 90325, 90331, 90337, 90342, 90346, 90350, 90356, 90362, 90366, 90372, 90377, 90381, 90384, 90389, 90395, 90400, 90405, 90412, 90418, 90423, 90428, 90432, 90437, 90442, 90446, 90451, 90455, 90459, 90465, 90469, 90473, 90479, 90484, 90490, 90496, 90502, 90507, 90512, 90516, 90521, 90525, 90532, 90538, 90542, 90547, 90553, 90557, 90564, 90570, 90574, 90579, 90585, 90591, 90597, 90602, 90606, 90611, 90615, 90619, 90623, 90629, 90634, 90640, 90645, 90650, 90656, 90662, 90667, 90673, 90678, 90684, 90689, 90693, 90698, 90702, 90707, 90713, 90718, 90724, 90729, 90734, 90739, 90743, 90750, 90756, 90764, 90769, 90775, 90780, -1, 90785, 90792, 90797, 90802, -1, 90807, 90812, 90817, 90822, 90828, 90833, 90838, 90844, 90850, 90854, 90860, 90864, 90869, 90875, 90881, 90885, 90889, 90893, 90899, 90904, 90908, 90912, 90917, 90921, 90927, 90933, 90937, 90941, 90946, 90952, 90957, 90961, 90967, 90972, 90976, 90980, 90984, 90990, 90994, 90999, 91004, 91011, 91017, 91021, 91026, 91032, 91036, 91040, 91045, 91050, 91056, 91062, 91067, 91071, 91076, 91080, 91084, 91090, 91096, 91102, 91107, 91112, 91117, 91123, 91128, 91132, 91137, 91143, 91148, 91153, 91158, 91162, 91168, 91173, 91177, 91182, 91186, 91191, -1, 91196, 91200, 91204, 91209, 91215, -1, 91219, 91225, 91229, 91235, 91241, 91246, 91252, 91257, 91263, 91267, 91273, 91279, 91283, 91289, 91294, 91299, 91305, 91310, 91315, 91320, 91325, 91329, 91333, 91337, 91343, 91347, 91351, 91355, 91359, 91366, 91371, 91378, 91383, 91388, 91394, 91398, 91404, 91409, 91414, 91418, 91422, 91426, 91431, 91438, 91442, 91447, 91452, 91457, 91461, 91465, 91470, 91475, 91480, 91486, 91491, 91495, 91499, 91503, 91508, 91512, 91519, 91524, 91528, 91535, 91539, 91545, 91551, 91556, 91561, 91566, 91572, 91577, 91582, 91587, 91592, 91598, 91602, 91607, 91612, 91618, 91622, 91628, 91636, 91643, 91648, 91654, 91659, 91664, 91668, 91672, 91676, 91681, 91685, 91690, 91697, 91702, 91708, 91712, 91718, 91724, 91729, 91735, 91740, 91745, 91750, 91754, 91760, 91765, 91770, 91776, 91781, 91786, 91791, 91796, 91800, 91804, 91809, 91814, 91817, 91823, 91828, 91833, 91838, 91842, 91846, 91851, 91856, 91862, 91867, 91871, 91875, 91879, 91884, 91890, 91894, 91900, 91904, 91910, 91914, 91920, -1, 91925, 91929, 91935, 91940, 91945, 91951, 91955, 91960, 91966, 91970, 91976, 91980, 91986, 91991, 91997, 92002, 92006, 92010, 92015, 92019, 92024, 92028, 92033, 92038, 92043, 92047, 92051, 92058, 92064, 92069, 92073, 92079, 92086, 92091, 92097, 92104, 92110, 92114, 92120, 92124, 92128, 92134, 92139, 92143, 92149, 92154, 92160, 92165, 92171, 92176, 92180, 92185, 92190, 92196, 92201, 92207, 92211, 92216, 92221, 92226, 92231, 92236, 92241, 92246, 92251, 92256, 92261, 92267, 92273, 92278, 92282, 92288, 92293, 92297, 92302, 92308, 92314, 92318, 92322, 92328, 92333, 92339, 92345, 92349, 92353, 92359, 92363, 92368, 92373, 92379, 92385, 92389, 92394, 92399, 92405, 92411, 92418, 92423, -1, 92429, 92433, 92439, 92443, 92447, 92451, 92455, 92460, 92464, 92468, 92472, 92477, 92483, 92487, 92492, 92497, 92503, 92508, 92512, 92518, 92524, 92529, 92534, 92539, 92544, 92551, 92557, 92562, 92567, -1, 92572, 92577, -1, 92582, 92586, 92591, 92596, 92600, 92605, 92610, 92616, 92622, 92627, 92632, 92637, 92641, 92646, 92651, 92655, 92661, 92665, 92669, 92674, 92680, 92685, 92690, 92694, 92699, 92703, 92710, 92716, 92720, 92726, 92730, -1, 92737, 92742, 92746, 92752, 92756, 92762, 92766, 92770, 92776, 92782, 92787, 92794, 92800, 92806, 92812, 92817, 92822, 92828, 92832, 92837, 92842, 92846, 92851, 92856, 92861, 92865, 92871, 92880, 92885, 92890, 92895, 92901, 92906, 92911, 92916, 92922, 92928, 92932, 92936, 92940, 92945, 92951, 92956, 92960, 92965, 92969, 92975, -1, 92980, 92985, 92991, 92997, 93001, 93007, 93012, 93017, 93021, 93025, 93029, 93034, 93038, 93042, 93048, 93054, 93059, 93063, 93067, 93072, 93076, 93080, 93084, 93088, 93092, 93096, 93101, 93107, 93111, 93116, 93121, 93126, 93132, 93138, 93143, 93148, 93152, 93157, 93164, 93169, 93175, 93179, 93184, 93191, -1, 93196, 93200, 93205, 93210, 93214, 93219, 93223, 93229, 93234, 93240, 93244, 93249, 93254, 93260, 93265, 93269, 93273, 93280, 93286, 93289, 93293, 93298, 93304, 93309, 93314, 93319, 93325, 93329, 93334, 93339, 93344, 93348, 93353, 93358, 93362, 93368, 93374, 93379, 93384, 93389, 93393, 93400, 93404, 93408, 93412, 93418, 93423, 93428, 93434, 93440, 93445, 93449, 93454, 93459, 93463, 93468, 93473, 93479, 93485, 93489, 93493, 93498, 93503, 93508, 93514, 93519, 93524, 93528, 93533, 93537, 93541, 93545, 93550, 93555, 93560, 93564, 93568, 93574, 93579, 93585, 93590, 93596, 93600, 93605, 93609, 93614, 93619, 93625, 93629, 93634, 93638, 93644, 93648, 93655, 93659, 93664, 93668, 93672, 93677, 93682, 93688, 93692, 93698, 93702, 93707, 93712, 93716, 93722, 93727, 93733, 93737, 93741, 93747, 93751, 93755, 93760, 93764, 93770, 93774, 93781, 93786, 93791, 93797, 93802, 93807, 93812, 93817, 93822, 93827, 93831, 93835, 93841, 93846, 93851, 93857, 93863, 93868, 93874, 93879, 93884, 93887, 93892, 93897, 93903, 93909, 93915, 93921, 93925, 93931, 93936, 93940, 93944, 93948, 93954, 93958, 93963, 93969, 93974, 93979, 93984, 93989, 93995, 94001, 94007, 94012, 94017, 94022, 94028, 94033, 94037, 94041, 94045, 94049, 94053, 94058, 94063, 94069, 94076, 94080, 94084, 94089, 94093, 94098, 94104, 94109, 94114, 94119, 94124, 94128, 94134, 94139, 94143, 94148, 94153, 94157, 94163, 94167, 94173, 94179, 94184, 94188, 94194, 94199, 94206, 94211, 94216, 94222, 94225, 94230, 94234, 94240, 94245, 94251, 94257, 94262, -1, 94268, 94272, 94276, 94280, 94284, 94290, 94295, 94299, 94305, 94309, 94314, 94319, 94325, 94332, 94337, 94343, 94348, 94353, 94357, 94363, 94368, 94373, 94377, 94383, 94388, 94393, 94398, 94403, 94408, 94414, 94419, 94426, 94432, 94437, 94443, 94447, 94451, 94457, 94462, 94468, 94472, 94476, 94480, 94485, 94490, 94494, 94499, 94504, 94508, 94513, 94518, 94523, 94529, 94535, -1, 94542, 94548, 94554, 94558, 94562, 94566, 94570, 94576, 94582, 94588, 94593, 94598, 94604, 94610, 94614, 94618, 94623, 94628, 94633, 94637, 94641, 94646, 94652, 94656, 94660, 94665, 94669, 94673, 94678, 94682, 94688, 94692, 94697, 94703, 94709, 94713, 94719, 94723, 94728, -1, 94733, 94740, 94745, 94750, 94755, 94759, 94763, 94767, 94772, 94777, 94783, 94789, 94795, 94799, 94803, 94807, 94813, 94818, 94823, 94828, 94835, 94840, 94847, 94854, 94859, 94865, 94870, 94875, 94880, 94884, 94888, 94893, 94898, 94903, 94907, 94913, 94917, 94922, 94928, 94938, 94945, 94951, 94958, 94962, 94967, 94971, 94976, 94980, 94985, 94991, 94997, 95003, 95007, 95012, 95018, 95023, 95028, 95032, 95036, 95043, 95050, 95055, 95060, 95065, 95070, 95075, 95080, 95086, 95092, 95098, 95103, 95109, 95114, 95121, 95126, -1, 95130, 95137, 95143, 95147, 95152, 95158, 95162, 95168, 95172, 95178, 95182, 95186, 95193, 95198, 95203, 95208, 95214, 95220, 95224, 95228, 95234, 95240, 95245, 95249, 95254, 95260, 95265, 95269, 95275, 95281, 95287, 95292, 95298, 95303, 95309, 95314, 95319, 95323, 95328, 95333, 95338, 95343, 95347, 95351, 95355, 95361, 95365, 95370, 95375, 95379, 95383, 95389, 95394, 95400, 95404, 95410, 95416, 95420, 95426, 95433, 95437, 95443, -1, 95449, 95453, 95458, 95462, 95468, 95472, 95477, 95482, 95487, 95492, 95497, 95502, 95507, 95514, 95519, 95524, 95528, 95533, 95540, 95544, 95548, 95552, 95557, 95561, 95567, 95572, 95577, -1, 95583, 95589, 95595, 95600, 95606, 95612, 95618, 95623, 95629, 95633, 95637, 95642, 95647, 95654, 95659, 95664, 95670, 95676, 95680, 95684, 95688, 95692, 95697, 95701, 95707, 95712, 95716, 95722, 95728, 95732, 95737, 95742, 95749, 95754, 95758, 95765, 95770, 95774, 95781, 95788, 95793, 95797, 95802, 95807, 95812, 95817, 95822, 95827, 95832, 95838, 95843, 95849, 95853, 95859, 95864, 95869, 95874, 95879, 95885, 95890, 95895, 95900, 95905, 95910, 95914, 95920, 95925, 95929, 95933, 95938, 95943, 95949, 95953, 95957, 95961, 95965, 95969, 95973, 95978, 95983, 95988, 95993, 95998, 96002, 96007, 96012, 96016, 96021, 96027, 96033, 96037, 96042, 96047, 96051, 96055, 96059, 96065, 96069, 96073, 96078, 96082, 96087, 96094, 96099, 96104, 96108, 96113, 96117, 96122, 96126, 96131, 96136, 96141, 96146, 96151, 96162, 96168, 96176, -1, 96182, 96187, 96192, 96198, 96203, 96208, 96213, 96220, 96224, 96230, 96236, 96241, 96245, 96249, 96253, 96259, 96264, 96269, 96274, 96278, 96282, 96286, 96294, 96300, 96305, 96310, 96314, 96320, 96326, 96330, 96336, 96341, 96347, 96351, 96356, 96361, 96367, 96373, 96378, 96385, 96391, 96396, 96402, 96409, 96416, 96421, 96426, 96431, 96437, 96442, 96447, 96452, 96456, 96460, 96465, 96469, 96473, 96477, 96482, 96487, 96492, 96497, 96501, 96505, 96509, 96516, 96521, 96527, 96532, 96537, 96543, 96548, 96553, 96557, 96563, 96568, 96573, 96577, 96581, 96587, 96592, 96597, 96602, 96607, 96611, 96616, 96623, 96628, 96632, 96637, 96641, 96647, 96653, 96659, 96663, 96668, 96675, 96680, 96685, 96690, 96695, 96701, 96707, 96713, 96718, 96724, 96730, 96734, 96740, 96745, 96749, 96754, 96759, 96763, 96767, 96772, 96777, 96783, 96788, 96794, 96799, 96803, 96810, 96815, 96820, 96827, 96836, 96840, 96846, 96853, 96859, 96864, 96868, 96873, 96877, 96882, 96886, 96893, 96898, 96903, 96908, 96913, 96918, 96922, 96927, 96932, 96937, 96942, 96948, 96954, 96960, 96964, 96969, 96975, 96980, 96985, 96989, 96994, 96998, 97002, -1, 97007, 97012, 97016, 97021, 97026, 97031, 97035, 97041, 97046, 97052, 97056, 97062, 97067, 97072, 97077, 97085, 97090, 97095, 97101, 97106, 97110, 97115, 97119, 97123, 97127, 97132, 97138, -1, 97143, 97149, 97153, 97157, 97161, 97165, 97169, 97175, 97181, 97187, 97192, 97197, 97202, 97208, 97213, 97217, 97221, 97226, 97231, 97235, 97241, 97246, 97251, 97255, 97261, 97267, 97272, 97277, 97282, 97286, 97292, 97297, 97301, 97307, 97311, 97316, 97319, 97323, 97328, 97334, 97338, 97344, 97350, 97355, 97359, 97365, 97370, 97376, 97382, 97388, 97393, 97397, 97403, 97408, 97413, 97417, 97422, 97427, 97433, 97437, 97443, 97449, 97455, 97460, 97465, 97469, 97474, 97480, 97485, 97490, 97494, 97498, 97502, 97508, 97512, 97517, 97522, 97526, 97532, 97537, 97542, 97546, 97551, 97556, 97562, 97566, 97570, 97575, 97580, 97584, 97591, 97596, 97602, 97606, 97611, 97616, 97621, 97627, 97633, 97638, 97643, 97648, 97654, 97658, 97662, 97666, 97670, 97675, 97680, 97684, 97690, 97694, 97701, 97707, 97712, 97717, 97722, 97726, 97730, 97734, 97739, 97743, 97748, 97752, 97757, 97762, 97768, 97772, 97777, 97782, 97788, 97794, 97798, 97803, 97808, 97814, 97820, 97825, 97830, 97834, 97839, 97843, 97848, 97853, 97858, 97864, 97868, 97873, 97877, 97882, 97887, 97890, 97895, 97899, 97904, 97910, 97916, 97921, 97926, 97931, 97937, 97941, 97947, 97952, 97957, 97964, 97970, 97975, 97981, 97986, 97992, 97997, 98002, 98006, 98010, 98014, 98018, 98023, 98027, 98033, 98037, 98041, 98047, 98052, 98059, 98064, 98068, 98072, 98078, 98082, 98086, 98092, 98097, 98103, 98107, 98113, 98117, 98122, 98127, 98133, 98138, 98142, 98146, 98150, 98155, 98160, 98164, 98168, 98174, 98180, 98184, 98191, 98195, 98199, 98203, 98207, 98212, 98217, 98221, 98226, 98232, 98236, 98241, 98245, 98252, 98256, 98261, 98266, 98272, 98277, 98282, 98287, 98292, 98297, 98303, 98308, 98313, 98318, 98323, 98330, 98335, 98341, 98347, 98353, 98357, 98363, 98369, 98372, 98377, 98382, 98389, 98394, 98398, 98404, 98410, 98415, 98420, 98425, 98432, 98437, 98441, 98445, 98451, 98455, 98460, 98465, 98469, 98475, 98478, 98485, 98488, 98493, 98499, 98504, 98508, 98514, 98519, 98525, 98531, 98536, 98542, 98546, 98550, 98556, 98563, 98568, 98574, 98578, 98582, 98587, 98593, 98597, 98602, 98608, 98614, 98620, 98626, 98630, 98639, 98646, 98652, 98657, 98661, 98665, 98671, 98677, 98682, 98688, 98694, 98699, 98704, 98708, 98712, 98716, 98721, 98727, 98731, 98737, 98743, 98749, 98755, 98759, 98763, 98768, 98774, 98779, 98783, 98789, 98795, 98802, 98806, 98811, 98817, 98823, 98830, 98836, 98841, 98846, 98851, 98857, 98863, 98869, 98875, 98879, 98884, 98888, 98894, 98899, 98905, 98910, 98915, 98920, 98923, 98930, 98934, 98939, 98943, 98947, 98953, 98959, 98963, 98967, 98971, 98978, 98982, 98987, 98992, 98996, 99002, 99007, 99013, 99019, 99024, 99030, 99035, 99041, 99047, 99051, 99056, 99060, 99065, 99069, -1, 99074, 99080, 99085, 99091, 99097, 99101, 99105, 99112, 99117, 99121, 99127, 99131, 99137, 99141, 99145, 99152, 99158, 99163, 99167, 99171, 99177, 99182, 99188, 99193, 99200, 99206, 99211, 99216, 99221, 99226, -1, 99231, 99235, 99241, 99247, 99253, 99257, 99261, 99265, 99272, 99277, 99282, 99288, 99292, 99297, 99303, 99308, 99313, 99317, 99323, 99327, 99333, 99337, 99341, 99346, 99351, 99355, 99359, 99366, 99371, 99377, 99382, 99387, 99393, 99397, 99403, 99407, 99411, 99416, 99421, 99428, 99433, 99438, 99441, 99447, 99452, 99456, 99461, 99467, 99471, 99476, 99483, 99487, 99492, 99497, 99502, 99508, 99513, 99518, 99522, 99529, 99535, 99540, 99545, 99551, 99556, 99562, 99566, 99572, 99578, 99584, 99589, 99593, 99597, 99603, 99607, 99612, 99617, 99621, 99625, 99631, 99637, 99642, 99648, 99654, 99658, 99662, 99668, 99673, 99677, 99683, 99689, 99693, 99699, 99704, 99708, 99713, 99719, 99724, 99729, 99735, 99740, 99746, 99750, 99754, 99760, 99765, 99770, 99773, 99779, 99784, 99790, 99795, 99801, 99807, 99812, 99817, 99823, 99828, 99833, 99839, 99844, 99848, 99854, 99860, 99865, 99869, 99874, 99878, 99884, 99888, 99893, 99897, 99902, 99908, 99913, 99919, 99925, 99929, 99934, 99939, 99943, 99948, 99952, 99957, 99964, 99969, 99973, 99977, 99981, 99985, 99989, 99992, 99997, 100004, 100010, 100016, 100021, 100027, 100032, 100039, 100043, 100047, 100053, 100057, 100062, 100069, 100074, 100078, 100084, 100088, 100093, 100097, 100101, 100107, 100111, 100115, 100119, 100126, 100131, 100136, 100141, 100146, 100151, 100156, 100163, 100168, 100174, 100179, 100184, 100189, 100195, 100200, 100205, 100209, 100216, 100221, 100228, 100233, 100238, 100242, 100248, 100253, 100257, 100261, 100267, 100271, 100276, 100281, 100286, 100293, 100299, 100305, 100309, 100315, 100320, 100325, 100330, 100334, 100340, 100345, 100349, 100354, 100358, 100364, 100370, 100376, 100382, 100389, 100395, 100400, 100405, 100411, 100415, 100420, 100426, 100431, 100438, 100444, 100449, 100454, 100458, 100463, 100466, 100470, 100476, 100482, 100486, 100490, 100495, 100499, 100503, 100509, 100513, 100517, 100523, 100527, 100532, 100537, 100543, 100548, 100554, 100558, 100563, 100568, 100573, 100579, 100584, 100589, 100594, 100600, 100605, 100609, 100614, 100619, 100625, 100631, 100637, 100641, 100647, 100653, 100658, 100663, 100669, 100674, 100680, 100684, 100688, 100693, 100699, 100704, 100708, 100714, 100719, 100726, 100730, 100735, 100739, 100745, 100750, 100754, 100759, 100765, 100771, 100776, 100781, 100786, 100791, 100796, 100801, 100806, 100811, 100815, 100820, 100824, 100830, 100834, 100839, 100842, 100846, 100853, 100859, 100865, 100870, 100875, 100879, 100883, 100887, 100892, 100897, 100901, 100906, -1, 100911, 100915, 100919, 100924, 100930, 100935, 100939, 100945, 100950, 100954, 100959, 100964, 100970, 100975, 100979, 100983, 100987, 100992, 100996, 101001, 101007, 101011, 101015, 101020, 101026, 101031, 101035, 101039, 101043, 101048, 101053, 101057, 101061, 101065, 101069, 101074, 101080, 101085, 101089, 101093, 101096, 101100, 101104, 101109, 101114, 101120, 101125, 101130, 101136, 101142, 101146, 101151, 101157, 101161, 101165, 101171, 101176, 101181, 101186, 101191, 101196, 101202, 101206, 101211, 101215, 101220, 101225, 101229, 101233, 101237, 101242, 101248, 101254, 101259, 101264, 101271, 101278, 101283, 101288, 101292, 101297, 101302, 101306, 101310, 101314, 101319, 101324, 101329, 101335, 101339, 101344, 101348, 101353, 101359, 101364, 101370, 101376, 101382, 101387, 101393, 101398, 101403, 101408, 101413, 101418, 101425, 101431, 101437, 101442, 101447, 101451, 101457, 101464, 101470, 101475, 101481, 101487, 101492, 101498, 101503, 101507, 101512, 101518, 101524, 101529, 101533, 101540, 101544, 101549, 101556, 101562, 101567, 101572, 101577, 101582, 101588, 101594, 101598, 101605, 101609, 101616, 101620, 101625, 101630, 101634, 101640, 101645, 101650, 101656, 101663, 101668, 101674, 101680, 101685, 101691, 101696, 101701, -1, 101706, 101712, 101717, 101723, 101728, 101733, 101739, 101745, 101749, 101753, 101758, -1, 101763, 101769, 101775, 101780, 101786, 101791, 101797, 101801, 101807, 101813, 101818, 101822, 101828, 101833, 101840, 101845, 101850, 101855, 101860, 101865, 101871, 101876, 101881, 101887, 101891, 101897, 101901, 101906, 101911, 101916, 101923, 101928, 101933, 101938, 101942, 101946, 101951, 101956, 101961, 101966, 101970, 101975, 101979, 101985, 101989, 101994, 101999, 102004, 102010, 102015, 102020, 102024, 102028, 102032, 102037, 102044, 102048, 102052, 102058, 102064, 102069, 102074, 102079, 102085, 102091, 102095, 102102, 102107, 102111, 102116, 102121, 102126, 102132, 102138, 102144, 102149, 102154, 102158, 102163, 102168, 102175, 102179, 102186, 102190, 102197, 102202, 102207, 102213, 102218, 102223, 102227, 102232, 102236, 102242, 102247, 102251, 102257, 102264, 102269, 102275, 102279, 102284, 102289, 102294, 102298, 102304, 102310, 102315, 102319, 102325, 102329, 102333, 102339, 102344, 102349, 102353, 102358, 102363, 102368, 102373, 102378, 102382, 102388, 102393, 102398, 102403, 102408, 102412, 102416, 102422, 102426, 102431, 102435, 102441, 102446, 102452, 102458, 102463, 102467, 102471, 102477, 102482, 102486, 102490, 102494, 102499, 102506, 102512, 102518, 102523, 102528, -1, 102532, 102537, 102542, 102546, 102550, 102555, 102559, 102563, 102568, 102573, 102577, 102583, 102589, 102595, 102600, 102604, 102609, 102613, 102617, 102622, 102629, 102634, 102639, 102643, 102649, 102655, 102660, 102664, 102669, 102673, 102678, 102683, 102687, 102692, 102697, 102702, 102706, 102711, 102716, 102720, 102725, 102729, 102735, 102739, 102743, 102747, 102751, 102756, 102760, 102764, 102769, 102775, 102781, 102786, 102791, 102798, 102803, 102810, 102815, 102822, 102827, 102834, 102839, 102843, 102849, 102854, 102859, 102865, 102870, 102876, 102880, 102886, 102890, 102896, 102901, 102905, 102909, 102913, 102918, 102922, 102927, 102933, 102938, 102944, 102948, 102953, 102958, 102963, 102968, 102974, 102980, 102986, 102992, -1, 102998, 103002, 103008, 103012, 103016, 103021, 103027, 103032, 103036, 103041, 103045, 103049, 103054, 103058, 103064, 103070, 103074, 103079, 103084, 103090, 103094, 103098, 103102, 103107, 103111, 103115, 103121, 103126, 103132, 103138, 103143, 103150, 103156, 103161, 103165, 103170, 103175, 103181, 103187, 103194, 103198, 103203, 103209, 103216, 103222, 103227, 103233, 103237, 103241, 103245, 103250, 103256, 103261, 103266, 103270, 103275, 103280, 103286, 103291, 103296, 103300, 103304, 103311, 103317, 103323, 103327, 103331, 103336, 103341, 103346, 103352, 103356, 103363, 103367, 103373, 103377, 103383, 103388, 103393, 103397, 103402, 103406, 103411, 103418, 103422, 103427, 103433, 103439, 103445, 103450, 103456, 103461, 103466, 103470, 103476, 103482, 103488, 103493, 103498, 103505, 103510, 103514, 103518, 103522, 103527, 103532, 103537, 103541, 103547, 103553, 103557, 103563, 103568, 103574, 103581, 103586, 103590, 103594, 103598, 103603, 103607, 103612, 103618, 103623, 103629, 103633, 103637, 103642, 103648, 103653, 103658, 103663, 103667, 103672, 103678, 103683, 103689, 103694, 103700, 103705, 103711, 103716, 103722, 103727, 103732, 103738, 103743, 103748, 103752, 103756, 103761, 103767, 103773, 103777, 103782, 103787, 103792, 103798, 103804, 103809, 103817, 103821, 103825, 103830, 103835, 103841, 103847, 103854, 103859, 103863, 103867, 103871, 103877, -1, 103885, 103890, 103900, 103906, 103910, 103915, 103920, 103925, 103930, 103938, 103942, 103947, 103955, 103959, 103964, 103968, 103973, 103978, 103983, 103988, 103993, 103997, 104003, 104008, 104013, 104019, 104026, 104031, 104036, 104042, 104047, 104050, 104054, 104058, 104063, 104069, 104074, 104079, 104086, 104092, 104096, 104100, 104107, 104111, 104117, 104122, 104126, 104132, 104137, 104144, 104149, 104155, 104160, 104164, 104168, 104173, 104178, 104184, 104187, 104191, 104197, 104202, 104207, 104211, 104215, 104221, 104226, 104232, 104236, 104243, 104247, 104253, 104260, 104264, 104269, 104275, 104281, 104286, 104291, 104296, 104303, 104307, 104313, 104318, 104324, 104329, 104334, 104339, 104343, 104349, 104355, 104359, 104365, 104370, 104376, 104383, 104387, 104392, 104398, 104404, 104409, 104414, 104418, 104424, 104430, 104435, 104441, 104447, 104453, 104458, 104463, 104468, 104475, 104481, 104486, 104490, 104496, 104502, 104509, 104514, 104519, 104523, 104528, 104534, 104539, 104543, 104547, 104551, 104556, 104561, 104567, 104571, 104576, 104581, 104585, 104591, 104596, 104602, 104606, 104611, 104617, 104624, 104629, 104634, 104640, 104645, 104651, 104657, 104661, 104666, 104671, 104676, 104681, 104685, 104689, 104694, 104700, 104704, 104708, 104713, 104717, 104721, 104727, 104733, 104738, 104743, 104747, 104751, 104755, 104760, 104765, 104769, 104774, 104780, 104784, 104789, 104796, 104799, 104804, 104810, 104816, 104820, 104824, 104828, 104834, 104839, 104843, 104847, 104853, 104857, 104862, 104868, 104873, 104878, 104883, 104889, 104895, 104901, 104905, 104911, 104916, 104920, 104927, 104933, 104938, 104943, 104948, 104954, 104961, 104967, 104971, 104976, 104980, 104984, 104989, 104994, 104999, 105005, 105010, 105016, 105020, 105025, 105030, 105035, 105039, 105043, 105047, 105051, 105056, 105062, 105066, 105070, 105074, 105079, 105084, 105090, 105096, -1, 105102, 105108, 105113, 105117, 105123, 105129, 105135, 105139, 105145, 105151, 105157, 105163, 105169, 105177, 105183, 105189, 105195, 105200, 105204, 105210, 105214, 105220, 105225, 105231, 105235, 105239, 105243, 105248, 105252, 105257, 105262, 105266, 105270, 105276, 105281, 105287, 105293, 105297, 105302, 105307, 105313, 105317, 105322, 105326, 105330, 105333, 105339, 105344, 105352, 105357, 105363, 105368, 105374, 105379, 105384, 105388, 105394, 105399, 105403, 105410, 105415, 105421, 105426, 105430, 105434, 105438, 105444, 105449, 105453, 105458, 105463, 105468, 105473, 105479, 105484, 105490, 105495, 105499, 105505, 105509, 105514, 105518, 105523, 105529, 105534, 105539, 105544, 105550, 105555, 105560, 105566, 105571, 105575, 105580, 105587, 105593, 105598, 105602, 105607, 105613, 105618, 105623, 105628, 105633, 105637, 105641, 105645, 105651, 105655, 105660, 105664, 105669, 105675, 105682, 105686, 105691, 105698, 105702, 105707, 105712, 105718, 105724, 105729, 105734, 105738, 105744, 105749, 105754, 105759, 105764, 105770, 105776, 105781, 105785, 105790, 105796, 105801, 105805, 105811, 105816, 105821, 105825, 105829, 105833, 105839, 105844, 105848, 105853, 105857, 105863, 105868, 105873, 105878, 105883, 105890, 105895, 105899, 105903, 105908, 105914, 105919, 105924, 105927, 105933, 105938, 105941, 105946, 105953, 105958, 105963, 105967, 105972, 105980, 105984, 105989, 105994, 105999, 106004, 106009, 106013, 106017, 106022, 106028, 106032, 106036, -1, 106042, 106047, 106053, 106060, 106064, 106069, 106073, 106078, 106082, 106087, 106092, 106097, 106101, 106106, 106111, 106116, 106121, 106126, 106131, 106137, 106143, 106147, 106151, 106155, 106161, 106165, 106170, 106174, 106179, 106184, 106189, 106194, 106200, 106206, 106212, 106216, 106222, 106228, 106234, 106238, 106242, 106248, 106253, 106258, 106262, 106266, 106272, 106278, 106282, 106288, 106294, 106299, 106303, 106309, 106313, -1, 106320, 106327, 106331, 106337, 106342, 106348, 106354, 106358, 106363, 106369, 106375, 106381, 106386, 106391, 106396, 106402, 106406, 106410, 106415, 106420, 106425, 106430, 106434, 106439, 106445, 106451, 106456, 106460, 106464, 106469, 106473, 106478, 106485, 106490, 106495, 106500, 106504, 106508, 106513, 106517, 106521, 106526, 106530, 106535, 106540, 106546, 106552, 106556, 106561, 106566, 106572, 106577, 106583, 106590, 106597, 106602, 106607, 106614, 106619, 106624, 106628, 106632, 106636, 106640, 106645, 106650, 106656, 106661, 106667, 106672, 106678, 106682, 106686, 106691, 106695, 106700, 106704, 106710, 106714, 106718, 106724, 106729, 106735, 106740, 106745, 106751, 106756, 106760, 106766, 106771, 106775, 106782, 106787, 106791, 106797, 106803, 106807, 106811, 106816, 106821, 106826, 106831, 106834, 106838, 106844, 106848, 106853, 106858, 106863, 106870, 106877, 106882, 106888, 106894, 106898, 106902, 106907, 106911, 106916, 106920, 106924, 106931, 106936, 106941, 106947, 106951, 106955, 106961, 106965, 106971, 106976, 106983, 106987, 106993, 106998, 107005, 107010, 107016, 107020, 107026, 107030, 107035, 107039, 107045, 107050, 107057, 107062, 107068, 107073, 107077, 107082, 107088, 107092, 107097, 107103, 107109, 107115, 107120, 107127, 107133, 107138, 107144, 107149, 107153, 107158, 107164, 107169, 107175, 107181, 107185, 107191, 107196, 107200, 107205, 107211, 107216, 107222, 107227, 107233, 107237, 107243, 107247, 107252, 107257, 107262, 107267, 107272, 107276, 107281, 107287, 107292, -1, 107304, 107309, 107314, 107320, 107325, 107330, 107335, 107340, 107344, 107348, 107352, 107358, 107363, 107369, 107374, 107380, 107386, 107391, 107397, 107402, 107408, 107415, 107422, 107427, 107431, 107437, 107442, 107446, 107452, 107457, 107461, 107466, 107471, 107476, 107480, 107487, 107492, 107496, 107501, 107506, 107511, 107516, 107522, 107528, 107533, 107538, 107544, 107548, 107553, 107557, 107563, 107567, 107571, 107575, 107581, 107586, 107591, 107597, 107602, 107606, 107610, 107615, 107619, 107625, 107631, 107636, 107641, 107647, 107652, 107657, 107662, 107668, 107675, 107681, 107687, 107691, 107695, 107700, 107705, 107709, 107716, 107720, 107726, 107730, 107735, 107739, 107745, 107749, 107753, 107757, 107763, 107767, 107774, 107778, 107783, 107789, 107794, 107800, 107804, 107808, 107815, 107820, 107826, 107830, 107834, 107839, 107845, 107850, 107855, 107860, 107865, 107870, 107874, 107881, 107885, 107892, 107896, 107901, 107906, 107911, 107915, 107921, 107926, 107932, 107938, 107942, 107947, 107951, 107955, 107961, 107966, 107970, 107976, 107980, 107985, 107991, 107997, 108003, 108008, 108015, 108019, 108024, 108028, 108033, 108038, 108044, 108048, 108054, 108058, 108062, 108066, 108070, 108074, 108080, 108085, 108089, 108093, 108097, 108103, 108113, 108119, 108123, 108127, 108132, 108136, 108142, 108148, 108154, 108159, 108164, 108169, 108173, 108177, 108181, 108186, 108189, 108194, 108199, 108204, 108209, 108215, 108220, 108224, 108229, 108235, 108240, 108245, 108250, 108254, 108259, 108263, 108268, 108274, 108279, 108284, 108289, 108293, 108300, 108305, 108310, 108314, 108319, 108324, 108330, 108338, 108345, -1, 108352, 108357, 108361, 108365, 108369, 108374, 108379, 108383, 108386, 108392, 108398, 108402, 108406, 108410, 108414, 108418, 108422, 108427, 108431, 108436, 108442, 108447, 108453, 108458, 108463, 108468, 108472, 108478, 108483, 108488, 108494, 108500, 108505, 108509, 108513, 108520, 108525, 108530, 108534, 108539, 108544, 108548, 108552, 108558, 108564, 108568, 108574, 108579, 108585, 108589, 108593, 108598, 108602, 108608, 108613, 108617, 108622, 108627, 108632, 108639, 108643, 108647, 108652, 108656, 108661, 108665, 108670, 108676, 108680, 108684, 108691, 108695, 108700, 108706, 108712, 108718, 108724, 108730, 108735, 108739, 108743, 108749, 108754, 108759, 108764, 108769, 108774, 108780, 108787, 108794, 108800, 108804, 108809, 108813, 108817, 108821, 108826, 108831, 108836, 108843, 108849, 108854, 108860, 108866, 108872, 108876, 108881, 108886, 108891, 108897, 108902, 108907, 108913, 108919, 108924, 108929, 108934, 108939, 108943, 108947, 108951, 108955, 108959, 108964, 108971, 108975, 108981, 108986, 108990, 108995, 109001, 109007, 109016, 109020, 109026, 109031, 109036, 109041, 109047, 109052, 109058, 109063, 109068, 109074, 109078, 109083, 109088, 109094, 109101, 109106, 109110, 109115, 109121, 109126, 109131, 109136, 109141, 109145, 109149, 109153, 109159, 109165, 109169, 109174, 109179, 109185, 109191, 109197, 109203, 109208, 109213, 109217, 109223, 109227, 109231, 109237, 109243, 109249, 109254, 109260, 109266, 109272, 109277, 109282, 109287, 109292, 109299, 109303, 109309, 109314, 109320, 109324, 109328, 109333, 109338, 109345, 109350, 109354, 109358, 109365, -1, 109370, 109374, 109379, 109384, 109388, 109395, 109401, 109407, 109413, 109419, 109424, 109431, 109436, 109441, 109447, 109452, 109456, 109460, 109467, 109472, 109478, 109483, 109488, 109494, 109498, 109502, 109508, 109512, 109518, 109523, 109526, 109532, 109536, 109541, 109545, 109550, 109556, 109560, 109567, 109572, 109577, 109583, 109588, 109593, 109599, 109603, 109609, 109615, 109619, 109623, 109628, 109634, 109639, 109646, 109652, 109656, 109662, 109667, 109671, 109676, 109681, 109687, 109691, 109697, 109701, 109706, 109712, 109716, 109721, 109726, 109734, 109738, 109743, 109748, -1, 109753, 109757, -1, 109763, 109768, -1, 109775, 109780, 109785, 109791, 109795, 109801, 109806, 109812, 109816, 109820, 109825, 109831, 109835, 109840, 109844, 109847, 109852, 109858, 109862, 109867, 109873, 109879, 109885, 109890, 109894, 109900, 109906, 109913, 109918, 109922, 109928, 109933, 109938, 109943, 109949, 109954, 109960, 109965, 109971, 109977, 109982, 109987, 109993, 109999, 110003, 110008, 110014, 110020, 110026, 110032, 110037, 110041, 110047, 110052, 110057, 110063, 110069, 110076, 110080, 110085, 110089, 110094, 110099, 110103, -1, 110108, 110113, 110119, 110123, 110129, 110134, 110140, 110145, 110149, 110154, 110158, 110162, 110167, 110173, 110179, 110185, 110190, 110197, 110201, 110207, 110213, 110217, 110222, 110226, 110230, 110236, 110242, 110246, 110250, 110256, 110263, 110269, 110274, 110279, 110284, 110289, 110294, 110299, 110304, 110310, 110316, 110321, 110325, 110331, 110337, 110342, 110346, 110351, 110355, 110359, 110365, 110374, 110382, -1, -1, -1, 110387, 110391, 110395, 110400, 110404, 110408, 110414, 110419, 110425, 110431, 110437, 110443, 110447, 110452, 110456, 110461, 110465, 110470, 110475, 110479, 110485, 110491, 110495, 110499, 110503, 110509, 110516, 110521, 110525, 110532, 110538, 110543, 110549, 110555, 110561, 110567, 110573, 110578, 110583, 110588, 110594, 110600, 110605, 110611, 110616, 110620, 110625, 110629, -1, 110635, -1, -1, 110641, 110648, 110652, 110657, 110661, 110665, 110670, 110677, 110681, 110686, 110691, 110696, 110701, 110708, 110713, 110717, 110722, 110727, 110733, 110738, 110743, 110748, 110754, 110760, 110766, 110772, 110779, 110784, 110790, 110795, 110801, 110806, 110811, 110816, 110821, 110826, 110830, 110836, 110843, 110849, 110853, 110859, 110864, 110869, 110874, 110878, 110882, -1, -1, 110887, 110893, 110899, 110904, 110910, 110915, 110920, 110924, 110930, 110935, 110939, 110945, 110951, 110957, 110963, 110969, 110974, 110978, 110983, 110989, 110993, 110998, 111003, 111009, 111013, 111018, 111022, 111027, 111031, 111035, 111041, 111046, 111052, 111057, 111063, 111069, 111073, 111078, 111082, 111087, 111093, 111098, 111104, 111109, 111115, 111119, 111125, 111131, 111137, 111142, 111147, 111152, 111156, 111161, 111165, 111171, 111178, 111185, 111191, 111195, 111199, 111205, 111211, 111215, 111221, 111226, -1, -1, 111230, 111236, 111239, 111243, 111248, 111254, 111259, 111263, 111269, 111274, 111280, 111287, 111293, 111297, 111303, 111309, 111314, 111319, 111325, 111329, 111334, 111339, 111345, 111351, 111356, 111361, 111366, 111372, 111377, 111382, 111387, 111392, 111396, 111402, 111408, 111414, 111418, 111424, 111428, 111434, 111441, 111447, 111451, 111456, 111462, 111467, 111471, 111475, 111481, 111487, 111492, 111496, 111501, 111505, 111510, 111516, 111523, 111527, 111532, 111538, 111543, 111549, 111554, 111559, 111564, 111568, 111573, 111579, 111585, 111590, 111595, 111600, 111604, 111608, 111614, 111621, 111627, 111631, 111635, 111638, 111642, 111646, 111650, 111655, 111661, 111665, 111670, 111675, 111681, 111686, 111691, 111695, 111701, 111707, 111713, 111718, 111723, 111728, 111734, 111739, 111743, 111747, 111751, 111756, 111762, 111767, 111772, 111776, 111782, 111786, 111791, 111798, 111803, 111807, 111812, 111817, 111823, 111829, 111833, 111839, 111844, 111849, 111854, 111859, 111865, 111871, 111876, 111882, 111887, 111893, 111898, 111903, 111908, 111912, 111918, 111925, 111929, 111935, 111939, 111945, 111952, 111958, 111962, 111967, 111971, 111976, 111981, 111985, 111989, 111994, 111998, 112004, 112010, 112016, 112021, 112025, 112032, 112037, 112042, 112047, 112052, 112057, 112062, 112067, 112073, 112078, 112083, 112088, 112094, 112099, 112103, 112109, 112115, 112119, 112122, 112129, 112134, 112140, 112145, 112150, 112155, 112159, 112163, 112168, 112173, 112180, 112184, 112188, 112193, 112199, 112205, 112210, 112215, 112221, 112227, 112232, 112237, 112242, 112248, 112254, 112258, 112264, 112268, 112273, 112279, 112284, 112291, 112297, 112300, 112305, 112311, 112318, 112324, 112329, 112336, 112342, 112346, 112350, 112355, 112360, 112364, 112369, 112374, 112378, 112384, 112388, 112392, 112397, 112403, 112409, 112414, 112418, 112423, 112428, 112434, 112438, 112443, 112448, 112454, 112460, 112466, 112471, 112476, 112482, 112488, 112494, 112498, 112502, 112508, 112513, 112518, 112523, 112529, 112533, 112537, 112542, 112547, 112551, 112557, 112564, 112570, 112575, 112580, 112586, 112592, 112598, 112602, 112607, 112613, 112617, 112623, 112630, 112637, 112644, 112649, 112653, 112658, 112662, 112668, 112672, 112679, 112684, 112688, 112695, 112701, 112706, 112711, 112716, 112720, 112725, 112729, 112734, 112739, 112745, 112751, 112757, 112762, 112767, 112773, 112779, 112785, 112790, 112795, 112801, 112806, 112811, 112816, 112822, 112828, 112833, 112839, 112845, 112849, 112854, 112858, 112864, 112868, 112872, 112876, 112881, 112887, 112892, 112897, 112901, 112906, 112912, 112916, 112922, 112927, 112931, 112936, 112941, 112947, 112951, 112956, 112963, 112969, 112974, 112979, 112984, 112989, 112992, 112997, 113001, 113006, 113013, 113018, 113025, 113029, 113034, 113039, 113044, 113048, 113053, 113058, 113063, 113068, 113073, -1, 113077, 113085, 113091, 113096, 113100, 113105, 113109, 113114, 113122, 113128, 113133, 113137, 113142, 113148, 113154, 113160, 113165, 113169, 113174, 113180, 113184, 113190, 113196, 113200, -1, 113205, 113210, 113217, 113223, 113228, 113233, 113237, 113242, 113250, 113255, 113260, 113266, 113272, 113278, 113283, 113289, 113294, 113299, 113304, 113309, 113314, 113318, 113323, 113327, 113332, 113336, 113340, 113344, 113349, 113354, 113359, 113365, 113369, 113373, 113378, 113385, 113389, 113394, 113399, 113404, 113407, 113413, 113418, 113422, 113427, 113432, 113437, 113441, 113447, 113451, 113456, 113461, 113467, 113471, 113475, 113479, 113484, 113489, 113495, 113499, 113503, 113508, 113513, 113519, 113524, 113527, 113534, 113539, 113544, 113550, 113555, 113561, 113566, 113570, 113576, 113582, 113588, 113593, 113599, 113604, 113611, 113614, 113618, 113622, 113626, 113631, 113637, 113643, 113646, 113651, 113656, 113660, 113666, 113670, 113674, 113678, 113684, 113690, 113696, 113701, 113706, 113710, 113717, 113722, 113727, 113733, 113737, 113742, 113746, 113751, 113757, 113762, 113768, 113774, 113780, 113784, 113788, 113793, 113799, 113806, 113811, 113815, 113820, 113826, 113832, 113837, 113843, 113848, 113853, 113858, 113864, 113869, 113874, 113879, 113883, 113888, 113893, 113898, 113902, 113908, 113914, 113918, 113924, 113929, 113935, 113939, 113946, 113952, 113957, 113962, 113968, 113974, 113980, 113987, 113992, 113997, 114001, 114005, 114009, 114015, 114020, 114025, 114030, 114035, 114040, 114044, 114051, 114056, 114061, 114066, 114071, 114076, 114081, 114085, 114090, 114094, 114099, 114103, 114107, 114113, 114117, 114124, 114129, 114133, 114137, -1, 114142, 114147, 114152, 114157, 114163, 114167, 114172, 114177, 114181, 114187, 114192, 114196, 114200, 114204, 114209, 114213, 114218, 114221, 114226, 114232, 114236, 114240, 114244, 114248, 114254, 114258, 114263, 114269, 114274, 114279, 114283, 114288, 114293, 114299, 114303, 114310, 114314, 114318, 114322, 114328, 114333, 114338, 114343, 114347, 114353, 114357, 114362, 114366, 114370, 114375, 114379, 114385, 114391, 114396, 114401, 114406, 114414, 114420, 114425, 114429, 114435, 114439, 114443, 114449, 114454, 114458, 114463, 114468, 114472, 114476, 114480, 114484, 114488, 114493, 114497, 114502, 114506, 114510, 114515, 114520, 114526, 114531, 114535, 114539, 114544, 114550, 114555, 114559, 114564, 114570, 114576, 114582, 114588, 114592, 114598, 114602, 114606, 114610, 114616, 114622, 114627, 114633, 114639, 114644, 114649, 114655, 114659, 114665, 114670, 114675, 114680, 114686, 114692, 114697, 114701, 114707, 114712, -1, 114717, 114723, 114729, 114733, 114739, 114747, 114753, 114758, 114764, 114769, 114773, 114778, 114783, 114788, 114794, 114799, 114803, 114808, 114813, 114818, 114822, 114826, 114830, 114835, 114841, 114847, 114851, 114855, 114861, 114866, 114870, 114876, 114882, 114886, 114890, -1, 114895, 114899, 114903, 114908, 114914, 114920, 114925, 114929, 114934, 114938, 114943, 114948, 114954, 114960, 114964, 114970, 114974, -1, 114979, 114983, 114987, 114993, 114999, 115005, 115011, 115017, 115023, 115029, 115036, 115042, 115048, 115054, 115060, 115066, 115072, 115077, 115082, 115087, 115091, 115097, 115103, 115108, 115112, 115118, 115123, 115127, 115131, 115137, 115142, 115148, 115153, 115157, 115161, 115165, 115170, 115175, 115180, 115185, 115190, 115194, 115199, 115203, 115207, 115211, 115215, 115219, 115224, 115228, 115233, 115238, 115243, 115248, 115254, 115259, 115265, 115271, 115276, 115281, 115286, 115290, 115295, 115299, 115303, 115308, 115314, 115322, 115326, 115332, 115338, 115343, 115349, 115354, 115360, 115366, 115372, 115378, 115384, 115388, 115395, 115401, 115406, 115410, 115414, 115419, 115424, 115430, 115434, 115439, 115444, 115448, 115454, 115458, 115462, 115468, 115474, 115478, 115484, 115488, 115493, 115498, 115502, 115507, 115512, 115517, 115521, 115525, 115530, 115536, 115541, 115546, 115552, 115557, 115561, 115567, 115574, 115580, 115584, 115589, 115595, 115601, 115605, 115609, 115615, 115620, 115625, 115630, 115634, 115639, 115645, 115649, 115654, 115660, 115665, -1, 115672, 115677, 115682, 115687, 115692, 115696, 115701, 115706, 115711, -1, 115716, 115720, 115725, 115730, 115734, 115738, 115742, 115747, 115752, 115756, 115761, 115766, 115771, 115776, 115781, 115786, 115792, 115797, 115803, 115807, 115812, 115816, 115821, 115827, 115831, 115837, 115843, 115849, 115854, 115860, 115865, 115870, 115877, 115881, 115885, 115891, 115897, 115902, 115909, 115915, 115920, 115924, 115928, 115932, 115936, 115942, 115947, 115951, 115957, 115961, 115966, 115971, 115976, 115980, 115985, 115990, 115994, 116000, 116004, 116010, 116015, 116019, 116025, 116028, 116031, 116036, 116041, 116046, 116052, 116056, 116062, 116067, 116072, 116078, 116084, 116089, 116093, 116098, 116103, 116108, 116113, 116118, 116122, 116128, 116135, 116141, 116146, 116150, 116155, 116161, 116166, 116171, 116176, 116181, 116186, 116190, 116194, 116200, 116206, 116211, 116216, 116221, 116227, 116231, 116236, 116243, 116248, 116252, 116257, 116261, 116264, 116267, 116272, 116277, 116282, 116288, 116295, 116300, 116306, 116311, 116315, 116321, 116327, 116333, 116339, 116346, 116350, 116355, 116361, 116367, 116371, 116376, 116380, 116385, 116390, 116396, 116400, 116405, 116411, 116416, 116422, 116426, 116432, 116437, 116443, 116448, 116452, 116457, 116462, 116468, 116472, 116478, 116484, 116489, 116496, 116502, 116506, 116510, 116515, 116519, 116524, 116528, 116533, 116539, 116545, 116549, 116553, 116559, 116563, 116569, 116574, 116579, 116585, 116590, 116596, 116603, 116608, 116612, 116617, 116622, 116627, 116632, 116638, 116644, 116648, 116652, 116658, 116661, 116668, 116673, 116676, 116681, 116686, 116692, 116698, 116703, 116708, 116714, 116718, 116723, 116729, 116735, 116741, 116749, 116753, 116758, 116764, 116770, 116774, 116778, 116783, 116788, 116793, 116799, 116805, 116809, 116813, 116817, 116822, 116828, 116833, 116838, 116843, 116848, 116853, 116858, 116862, 116868, 116874, 116880, 116885, 116891, 116897, 116903, -1, 116909, 116913, 116919, 116925, 116931, 116937, 116943, 116949, 116953, 116957, 116961, 116966, 116971, 116976, 116982, 116988, 116994, 116999, 117004, 117009, 117014, 117019, 117024, 117029, 117033, 117039, 117043, 117048, 117054, 117059, 117066, 117071, 117076, 117080, 117086, 117091, 117096, 117101, 117106, 117111, 117116, 117121, 117125, 117131, 117135, 117140, 117145, 117150, 117154, 117159, 117163, 117168, 117173, 117178, 117183, 117188, 117194, 117200, 117205, 117211, 117216, 117222, 117226, 117233, 117239, 117245, 117249, 117254, 117258, 117262, 117267, 117271, 117276, 117279, 117283, 117288, 117293, 117297, 117301, 117306, 117311, 117316, 117321, 117326, 117332, 117338, 117344, 117350, 117354, 117358, 117363, 117368, 117375, 117380, 117386, 117389, 117395, 117400, 117404, 117411, 117416, 117421, 117427, 117432, 117436, 117442, 117447, 117452, 117456, 117461, 117467, 117473, 117477, 117482, 117486, 117491, 117496, 117501, 117506, 117510, 117515, 117519, 117525, 117530, 117534, 117538, 117543, 117548, 117553, 117558, 117565, 117571, 117576, 117581, 117585, 117589, 117594, 117601, 117607, 117612, 117617, 117624, 117630, 117635, 117640, 117646, 117651, 117655, 117661, 117668, 117673, 117679, 117685, 117690, 117696, 117700, 117705, 117711, 117716, 117720, 117725, 117729, 117734, 117739, 117744, 117750, 117755, 117760, 117764, 117769, 117773, 117777, 117782, 117789, 117794, 117798, 117804, 117808, 117814, 117818, 117823, 117826, 117830, 117835, 117840, 117845, 117850, 117856, 117862, 117867, 117872, 117876, 117881, 117887, 117891, 117895, 117899, 117904, 117909, 117914, 117919, 117924, 117931, 117937, 117943, 117948, 117953, 117960, 117965, 117969, 117973, 117977, 117981, 117985, 117990, 117995, 118001, 118005, 118009, 118013, 118019, 118024, 118029, 118034, 118039, 118045, 118049, 118053, 118059, 118064, 118068, 118073, 118078, 118083, 118088, 118093, 118098, 118103, 118108, 118112, 118116, 118121, 118126, 118131, 118136, 118140, 118145, 118149, 118154, 118160, 118165, 118169, -1, 118173, 118177, 118184, 118188, 118194, 118200, 118206, 118212, 118216, 118221, 118225, 118229, 118233, 118239, 118244, 118250, 118256, 118261, 118265, 118271, 118276, 118280, 118285, 118290, 118294, 118299, 118303, 118309, 118314, 118319, 118325, 118331, 118337, 118342, 118348, 118354, 118361, 118365, 118370, 118374, 118379, 118384, 118389, 118395, 118400, 118405, 118410, 118414, 118420, 118425, 118431, 118438, 118443, 118447, 118453, 118458, 118463, 118466, 118473, 118478, 118482, 118486, 118492, 118498, 118503, 118509, 118514, 118519, 118524, 118530, 118534, 118538, 118542, 118547, 118552, 118557, 118562, 118567, 118572, 118576, 118582, 118588, 118594, 118600, 118605, 118612, 118618, 118623, 118627, 118631, 118637, 118642, 118648, 118653, 118658, 118662, 118667, 118672, 118677, 118682, 118688, 118695, 118700, 118705, 118711, 118717, 118721, 118726, 118730, 118735, 118741, 118746, 118751, 118757, 118761, 118766, 118774, 118778, 118782, 118787, 118794, 118798, 118802, 118807, 118813, 118819, 118823, 118827, 118832, 118836, 118840, 118845, 118849, 118853, 118859, 118864, 118870, 118875, 118880, 118885, 118891, 118896, 118902, 118907, 118912, 118917, 118923, 118929, 118933, 118937, 118942, 118947, 118952, 118957, 118963, 118967, 118973, 118980, 118984, 118992, 118996, 119000, 119006, 119010, 119016, 119020, 119024, 119029, 119034, 119039, 119043, 119047, 119051, 119055, 119061, 119066, 119070, 119074, 119078, 119083, 119088, 119093, 119097, 119102, 119106, 119111, 119117, 119121, 119126, 119132, 119137, 119142, 119147, 119153, 119159, 119163, 119170, 119175, 119180, 119185, 119190, 119194, 119198, 119202, 119208, 119214, 119218, 119223, 119229, 119234, 119239, 119244, 119248, 119252, 119257, 119263, 119269, 119275, 119280, 119286, 119292, 119297, 119301, 119309, 119316, 119320, 119325, 119330, 119335, 119339, 119344, 119348, 119353, 119358, 119363, 119368, 119372, 119377, 119381, 119385, 119389, 119394, 119400, 119405, 119410, 119414, 119419, 119425, 119431, 119435, 119439, 119443, 119447, 119452, 119457, 119461, 119467, 119473, 119477, 119481, 119487, 119492, 119496, 119502, 119507, 119512, 119516, 119522, 119527, 119531, 119536, 119542, 119546, 119551, 119556, 119562, 119567, 119573, 119578, 119583, 119589, 119594, 119599, 119603, 119609, 119614, 119619, 119624, 119629, 119634, 119639, 119643, 119649, 119655, 119659, 119663, 119668, 119672, 119677, 119681, 119686, 119690, 119694, 119700, 119704, 119710, 119715, 119720, 119724, 119730, 119736, 119742, 119747, 119751, 119755, 119760, 119766, 119770, 119776, 119782, 119789, 119795, 119801, 119807, 119813, 119818, 119822, 119826, 119831, 119835, 119841, 119847, 119852, 119858, 119862, 119867, 119872, 119877, 119883, 119887, 119892, 119898, 119904, 119910, 119916, 119922, 119928, 119933, 119938, 119944, 119949, 119954, 119959, 119965, 119969, 119974, 119979, 119984, 119989, 119994, 120001, 120005, 120009, 120013, 120019, 120023, 120029, 120034, 120040, 120045, 120050, 120057, 120061, 120066, 120071, 120075, 120079, 120084, 120089, 120094, 120098, 120102, 120107, 120111, 120116, 120122, 120129, 120133, 120138, 120142, 120148, 120155, 120160, 120166, 120171, 120177, 120181, 120185, 120189, 120193, 120199, 120204, 120210, 120214, 120219, 120224, 120228, 120233, 120239, 120244, 120250, 120254, 120258, 120261, 120264, 120269, 120275, 120280, 120284, 120289, 120295, 120300, 120306, 120310, 120314, 120319, 120323, 120327, 120331, 120337, 120342, 120346, 120351, 120359, 120365, 120369, 120374, 120378, 120383, 120387, 120393, 120398, 120402, 120407, 120413, 120417, 120421, 120425, 120430, 120434, 120440, 120444, 120449, 120454, 120458, 120464, 120470, 120475, 120480, 120484, 120489, 120493, 120497, 120505, -1, 120511, 120515, 120520, 120525, 120530, 120537, 120541, 120545, 120550, 120556, 120561, 120566, 120571, 120576, 120582, 120586, 120590, 120596, 120601, 120607, 120611, 120616, 120622, 120626, 120631, 120637, 120643, 120648, 120654, 120659, 120664, 120668, 120673, 120679, 120683, 120688, 120693, 120697, 120702, 120707, 120712, 120718, 120722, 120726, 120731, 120737, 120741, 120746, 120751, 120755, 120760, 120765, 120770, 120776, 120782, 120789, 120800, 120810, 120816, 120820, 120824, 120828, 120834, 120841, 120846, 120852, 120856, 120862, 120867, 120871, 120877, 120883, 120888, 120893, 120897, 120901, 120906, 120910, 120915, 120922, 120928, 120933, 120939, 120944, 120948, 120954, 120960, 120965, 120971, 120979, 120986, 120995, 121000, 121006, 121011, 121016, 121021, 121027, 121032, 121036, 121042, 121046, 121052, 121058, 121064, 121070, 121074, 121079, 121084, 121088, 121093, 121098, 121103, 121110, 121116, 121121, 121126, 121131, 121137, 121141, 121144, 121150, 121154, 121159, 121165, 121170, 121175, 121179, 121188, 121193, 121201, 121206, 121212, 121217, 121221, 121227, 121232, 121237, 121241, 121246, 121251, 121256, 121259, 121265, 121269, 121274, 121278, 121284, 121290, 121294, 121299, 121304, 121314, 121320, 121324, 121328, 121333, 121338, 121342, 121348, 121352, 121358, 121363, 121368, 121372, 121377, 121383, 121387, 121391, 121396, 121403, 121408, 121415, 121421, 121428, 121434, 121439, 121444, 121449, 121453, 121460, 121464, 121470, 121475, 121479, 121486, 121491, 121497, 121503, 121508, 121513, 121518, 121523, 121529, 121533, 121538, 121544, 121549, 121555, 121560, 121566, 121571, 121576, 121582, 121587, 121592, 121599, 121603, 121610, 121620, 121628, 121635, 121639, 121643, 121647, 121652, 121660, 121664, 121669, 121673, 121678, 121684, 121691, 121694, 121698, 121704, 121708, 121714, 121718, 121723, 121727, 121732, 121737, 121741, 121747, 121751, 121755, 121759, 121765, 121771, 121775, 121780, 121785, 121789, 121793, 121798, 121803, 121807, 121812, 121817, 121822, 121827, 121832, 121836, 121842, 121846, 121851, 121857, 121861, 121867, 121873, 121877, 121884, 121889, 121895, 121899, 121905, 121911, 121915, 121920, 121926, 121931, 121936, 121941, 121946, 121950, 121956, 121962, 121968, 121972, 121977, 121982, 121987, 121994, 121998, 122002, 122008, 122014, 122020, 122026, 122031, 122035, 122040, 122045, 122049, 122056, 122061, 122066, 122071, 122076, 122079, 122084, 122088, 122095, 122101, 122108, 122114, 122119, 122123, 122127, 122131, 122136, 122141, 122147, 122153, 122157, 122163, 122168, 122173, 122178, 122183, 122189, 122194, 122198, 122203, 122209, 122214, 122219, 122224, 122229, 122233, 122239, 122245, 122251, 122255, 122259, 122263, 122268, 122272, 122277, 122281, 122287, 122291, 122297, 122302, 122307, 122312, 122318, 122324, 122329, 122335, 122340, 122344, 122349, 122353, 122358, 122363, 122369, 122374, 122378, 122383, 122389, 122394, 122399, 122403, 122409, 122415, 122420, 122425, 122429, 122436, 122442, 122448, 122453, 122457, 122461, 122466, 122470, 122476, 122481, 122485, 122490, 122495, 122499, 122505, 122510, 122514, 122520, 122524, 122528, 122534, 122539, 122544, 122548, 122553, 122557, 122564, 122568, 122574, 122580, 122584, 122589, 122593, 122600, 122606, 122612, 122616, 122620, 122625, 122629, 122634, 122639, 122645, 122651, 122655, 122660, 122665, 122670, 122674, 122680, 122685, 122689, 122694, 122698, 122703, 122709, 122714, 122720, 122725, 122730, 122739, 122745, 122750, 122756, 122761, 122765, 122769, 122775, 122780, 122784, 122788, 122794, 122798, 122802, 122807, 122812, 122816, 122820, 122825, 122829, 122833, 122839, 122843, 122846, 122849, 122856, 122860, 122864, 122870, 122875, 122884, 122892, 122896, 122902, 122907, 122911, 122915, 122921, 122927, 122932, 122938, 122943, 122949, 122953, 122958, 122964, 122968, 122972, 122976, 122982, 122986, 122990, 122994, 123000, 123006, 123012, 123017, 123024, 123028, 123034, 123038, 123042, 123048, 123052, 123057, 123063, 123067, 123073, 123079, 123083, 123087, 123094, 123107, 123111, -1, 123116, 123121, 123127, 123132, 123136, 123141, 123145, 123149, 123153, 123156, 123161, 123166, 123170, 123176, 123180, 123185, 123189, 123195, 123201, 123206, 123211, 123215, 123221, 123226, 123230, 123234, 123243, 123249, 123255, 123259, 123265, 123271, 123277, 123283, 123288, 123292, 123297, 123303, 123308, 123313, 123318, 123322, 123326, 123332, 123338, 123343, 123347, 123351, 123355, 123360, 123365, 123369, 123373, 123379, 123384, 123388, 123392, 123396, 123400, 123404, 123410, 123415, 123421, 123427, 123431, 123438, 123443, 123447, 123452, 123456, 123460, 123465, 123470, 123476, 123482, 123487, 123491, 123499, 123505, 123509, 123513, 123518, 123523, 123529, 123533, 123539, 123543, 123548, 123552, 123558, 123562, 123569, 123574, 123580, 123586, 123591, 123596, 123601, 123607, 123613, 123617, 123622, 123627, 123631, 123637, 123641, 123647, 123653, 123658, 123662, 123666, 123671, 123676, 123680, 123684, 123688, 123693, 123697, 123703, 123707, 123713, 123717, 123723, 123728, 123732, 123738, 123744, 123748, 123753, 123757, 123762, 123767, 123771, 123775, 123781, 123789, 123794, 123800, 123806, 123810, 123814, 123820, 123826, 123831, 123835, 123841, 123847, 123852, 123856, 123860, 123866, 123871, 123877, 123881, 123887, 123891, 123895, 123901, 123907, 123913, 123918, 123922, 123928, 123933, 123938, 123942, 123947, 123951, 123956, 123961, 123967, 123973, 123977, 123983, 123989, 123993, 123997, 124001, 124007, 124011, 124014, 124018, 124024, 124028, 124032, 124037, 124043, 124047, 124052, 124057, 124063, 124069, 124075, 124081, 124087, 124091, 124095, 124099, 124102, 124106, 124111, 124115, 124120, 124124, 124128, 124133, 124139, 124144, 124148, 124152, 124158, 124162, 124166, 124172, 124177, 124183, 124189, 124195, 124200, 124204, 124208, 124214, 124220, 124226, 124231, 124237, 124243, 124251, 124255, 124260, 124266, 124272, 124278, 124283, 124289, 124295, 124300, 124305, 124309, 124314, 124318, 124322, 124328, 124332, 124338, 124343, 124348, 124353, 124359, 124363, 124367, 124371, 124376, 124382, 124387, 124392, 124396, 124400, 124404, 124409, 124414, 124420, 124424, 124431, 124436, 124441, 124445, 124449, 124454, 124461, 124466, 124472, 124476, 124482, 124487, 124491, 124496, 124501, 124505, 124511, 124515, 124521, 124527, 124531, 124536, 124540, 124544, 124549, 124553, 124559, 124564, 124568, -1, 124574, 124580, 124584, 124588, 124594, 124598, 124602, 124606, 124611, 124615, 124620, 124625, 124630, 124637, 124644, 124649, 124656, 124662, 124667, 124673, 124677, 124684, 124690, 124695, 124699, 124705, 124710, 124715, 124720, 124724, 124730, 124735, 124739, 124745, 124749, 124753, 124759, 124764, 124769, 124774, 124780, 124784, 124789, 124794, 124798, 124803, 124808, 124814, 124818, 124822, 124828, 124832, 124837, 124842, 124846, 124851, 124856, 124860, 124866, 124871, 124876, 124880, 124885, 124890, 124895, 124899, 124903, 124908, 124913, 124917, 124921, 124926, 124931, 124937, 124941, 124945, 124951, 124955, 124960, 124965, 124971, 124975, 124980, 124985, 124989, 124995, 125001, 125006, 125012, 125016, 125021, 125027, 125031, 125035, 125039, 125045, 125050, 125055, 125061, 125065, 125072, 125077, 125081, 125087, 125093, 125099, 125104, 125109, 125114, 125119, 125124, 125128, 125134, 125139, 125145, 125149, 125156, 125161, 125166, 125171, 125177, 125181, 125187, 125193, 125198, 125202, 125207, 125211, 125215, 125219, 125225, 125230, 125235, 125239, 125244, 125249, 125254, 125258, 125262, 125267, 125271, 125275, 125280, 125285, 125291, 125296, 125302, 125308, 125312, 125318, 125322, 125326, 125330, 125334, 125338, 125342, 125347, 125353, 125359, 125363, 125367, 125372, 125377, 125382, 125387, 125392, 125396, 125401, 125407, 125411, 125417, 125423, 125429, 125434, 125440, 125445, 125450, 125455, 125460, 125465, 125471, 125476, 125480, 125485, 125489, 125493, 125498, 125503, 125507, 125512, 125518, 125522, 125525, 125529, 125533, 125539, 125544, 125550, 125555, 125560, 125564, 125569, 125575, 125579, 125584, 125588, 125594, 125599, 125605, 125609, 125614, 125618, 125624, 125628, 125632, 125638, 125644, 125650, 125656, 125661, 125667, 125673, 125679, 125684, 125688, 125694, 125698, 125704, 125710, 125715, 125720, 125725, 125730, 125735, 125740, 125746, 125750, 125755, 125760, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 125764, 125767, 125770, 125772, 125775, 125779, 125783, 125786, 125790, 125793, 125796, 125798, 125801, 125805, 125808, 125812, 125815, 125818, 125820, 125823, 125826, 125828, 125831, 125835, 125839, 125842, 125846, 125851, 125856, 125860, 125865, 125869, 125873, 125876, 125880, 125885, 125889, 125894, 125898, 125902, 125905, 125909, 125913, 125916, 125920, 125924, 125928, 125931, 125935, 125940, 125944, 125948, 125952, 125955, 125959, 125964, 125968, 125972, 125976, 125979, 125983, 125988, 125992, 125997, 126001, 126005, 126008, 126012, 126017, 126021, 126026, 126030, 126034, 126037, 126041, 126045, 126049, 126052, 126056, 126061, 126065, 126069, 126073, 126076, 126080, 126085, 126089, 126094, 126099, 126103, 126108, 126114, 126120, 126125, 126131, 126136, 126141, 126145, 126150, 126156, 126161, 126167, 126172, 126177, 126181, 126186, 126191, 126195, 126200, 126205, 126210, 126214, 126219, 126225, 126230, 126235, 126240, 126244, 126249, 126254, 126259, 126263, 126268, 126274, 126279, 126285, 126290, 126295, 126299, 126304, 126309, 126314, 126318, 126323, 126328, 126333, 126337, 126342, 126348, 126353, 126358, 126363, 126367, 126372, 126378, 126383, 126388, 126393, 126397, 126402, 126408, 126413, 126419, 126424, 126429, 126433, 126438, 126444, 126449, 126455, 126460, 126465, 126469, 126474, 126479, 126484, 126488, 126493, 126499, 126504, 126509, 126513, 126518, 126524, 126529, 126533, 126537, 126540, 126544, 126549, 126553, 126558, 126562, 126566, 126569, 126573, 126578, 126583, 126587, 126592, 126596, 126600, 126603, 126607, 126611, 126614, 126618, 126622, 126625, 126629, 126634, 126638, 126642, 126646, 126649, 126653, 126657, 126661, 126664, 126668, 126672, 126676, 126679, 126683, 126687, 126690, 126694, 126698, 126702, 126705, 126709, 126714, 126718, 126722, 126726, 126729, 126733, 126737, 126741, 126744, 126748, 126753, 126758, 126762, 126767, 126771, 126775, 126778, 126782, 126786, 126790, 126793, 126797, 126801, 126805, 126809, 126813, 126816, 126820, 126825, 126829, 126833, 126837, 126840, 126844, 126849, 126853, 126857, 126861, 126864, 126868, 126873, 126877, 126882, 126886, 126890, 126893, 126897, 126902, 126906, 126910, 126914, 126917, 126921, 126925, 126928, 126932, 126936, 126940, 126943, 126947, 126952, 126956, 126960, 126964, 126967, 126971, 126976, 126980, 126985, 126989, 126993, 126996, 127000, 127005, 127010, 127014, 127019, 127023, 127027, 127030, 127034, 127038, 127041, 127045, 127049, 127053, 127056, 127060, 127065, 127069, 127074, 127079, 127083, 127088, 127094, 127099, 127105, 127110, 127115, 127119, 127124, 127130, 127135, 127141, 127146, 127151, 127155, 127160, 127165, 127169, 127174, 127179, 127184, 127188, 127193, 127199, 127204, 127209, 127214, 127218, 127223, 127229, 127234, 127239, 127244, 127248, 127253, 127258, 127263, 127267, 127272, 127277, 127281, 127286, 127291, 127296, 127300, 127305, 127311, 127316, 127321, 127326, 127330, 127335, 127341, 127347, 127352, 127358, 127363, 127368, 127372, 127377, 127383, 127388, 127393, 127398, 127403, 127408, 127412, 127417, 127422, 127426, 127430, 127433, 127437, 127442, 127446, 127451, 127455, 127458, 127462, 127467, 127471, 127476, 127480, 127484, 127487, 127491, 127495, 127498, 127502, 127506, 127510, 127513, 127517, 127522, 127526, 127531, 127536, 127540, 127545, 127551, 127556, 127562, 127567, 127572, 127576, 127581, 127587, 127592, 127598, 127603, 127607, 127612, 127617, 127621, 127626, 127631, 127636, 127640, 127645, 127651, 127656, 127661, 127666, 127670, 127675, 127681, 127686, 127690, 127694, 127697, 127701, 127706, 127711, 127715, 127720, 127724, 127728, 127731, 127735, 127740, 127745, 127749, 127754, 127758, 127762, 127765, 127769, 127773, 127776, 127780, 127784, 127788, 127791, 127795, 127800, 127804, 127808, 127812, 127815, 127819, 127824, 127828, 127832, 127836, 127839, 127843, 127848, 127853, 127857, 127862, 127866, 127870, 127873, 127877, 127882, 127887, 127891, 127896, 127900, 127904, 127907, 127911, 127915, 127919, 127922, 127926, 127930, 127934, 127937, 127941, 127946, 127950, 127954, 127958, 127961, 127965, 127970, 127974, 127979, 127983, 127987, 127990, 127994, 127999, 128003, 128008, 128012, 128016, 128019, 128023, 128027, 128031, 128034, 128038, 128042, 128046, 128049, 128053, 128058, 128062, 128067, 128072, 128076, 128082, 128087, 128093, 128098, 128103, 128107, 128112, 128118, 128124, 128129, 128135, 128140, 128145, 128149, 128154, 128159, 128164, 128168, 128173, 128178, 128183, 128187, 128192, 128198, 128203, 128209, 128214, 128219, 128224, 128228, 128233, 128239, 128244, 128250, 128255, 128260, 128264, 128269, 128274, 128278, 128283, 128288, 128293, 128297, 128302, 128308, 128313, 128318, 128323, 128327, 128332, 128338, 128344, 128349, 128355, 128360, 128365, 128369, 128374, 128380, 128386, 128391, 128397, 128402, 128407, 128411, 128416, 128421, 128425, 128430, 128436, 128441, 128447, 128452, 128457, 128461, 128466, 128472, 128478, 128483, 128488, 128493, 128497, 128502, 128507, 128511, 128516, 128520, 128525, 128529, 128533, 128537, 128540, 128544, 128549, 128554, 128558, 128563, 128567, 128571, 128574, 128578, 128582, 128585, 128589, 128593, 128597, 128600, 128604, 128609, 128613, 128618, 128622, 128625, 128629, 128633, 128636, 128640, 128644, 128648, 128651, 128655, 128660, 128664, 128669, 128673, 128677, 128680, 128684, 128689, 128693, 128698, 128702, 128706, 128709, 128713, 128717, 128720, 128724, 128728, 128732, 128735, 128739, 128744, 128748, 128752, 128756, 128759, 128763, 128768, 128772, 128776, 128780, 128783, 128787, 128792, 128797, 128801, 128806, 128810, 128814, 128817, 128821, 128826, 128830, 128835, 128839, 128843, 128846, 128850, 128854, 128857, 128861, 128865, 128869, 128872, 128876, 128881, 128885, 128889, 128893, 128896, 128900, 128905, 128909, 128914, 128919, 128923, 128928, 128934, 128940, 128945, 128951, 128956, 128961, 128965, 128970, 128975, 128979, 128984, 128989, 128993, 128998, 129003, 129007, 129012, 129018, 129023, 129028, 129033, 129037, 129042, 129048, 129053, 129058, 129063, 129067, 129072, 129078, 129083, 129089, 129094, 129099, 129103, 129108, 129114, 129119, 129124, 129129, 129134, 129138, 129143, 129147, 129152, 129158, 129163, 129168, 129173, 129177, 129182, 129188, 129193, 129197, 129201, 129204, 129208, 129213, 129217, 129222, 129226, 129230, 129233, 129237, 129242, 129246, 129251, 129255, 129259, 129262, 129266, 129270, 129273, 129277, 129281, 129285, 129288, 129292, 129297, 129301, 129305, 129309, 129312, 129316, 129321, 129325, 129330, 129335, 129339, 129344, 129350, 129355, 129361, 129366, 129371, 129375, 129380, 129385, 129390, 129394, 129399, 129404, 129408, 129413, 129418, 129423, 129427, 129432, 129437, 129442, 129446, 129451, 129457, 129462, 129467, 129472, 129476, 129481, 129487, 129492, 129498, 129503, 129508, 129512, 129517, 129522, 129527, 129531, 129536, 129541, 129546, 129550, 129555, 129561, 129566, 129571, 129576, 129580, 129585, 129591, 129596, 129601, 129606, 129610, 129615, 129621, 129627, 129632, 129638, 129643, 129648, 129652, 129657, 129662, 129667, 129671, 129676, 129681, 129685, 129690, 129696, 129701, 129706, 129711, 129715, 129720, 129726, 129731, 129736, 129740, 129746, 129751, 129756, 129761, 129765, 129770, 129775, 129780, 129784, 129789, 129794, 129799, 129803, 129808, 129814, 129819, 129824, 129829, 129833, 129838, 129844, 129849, 129854, 129859, 129863, 129868, 129873, 129877, 129882, 129887, 129892, 129896, 129901, 129906, 129911, 129915, 129920, 129926, 129931, 129936, 129941, 129945, 129950, 129956, 129961, 129966, 129971, 129975, 129980, 129986, 129991, 129997, 130002, 130007, 130011, 130016, 130021, 130026, 130030, 130035, 130040, 130045, 130049, 130054, 130060, 130065, 130070, 130075, 130079, 130084, 130090, 130095, 130099, 130103, 130106, 130110, 130115, 130119, 130124, 130128, 130132, 130135, 130139, 130143, 130146, 130150, 130154, 130158, 130161, 130165, 130170, 130174, 130178, 130182, 130185, 130189, 130194, 130198, 130202, 130206, 130209, 130213, 130218, 130223, 130227, 130232, 130237, 130242, 130246, 130251, 130255, 130259, 130262, 130266, 130270, 130274, 130277, 130281, 130286, 130290, 130294, 130298, 130301, 130305, 130310, 130314, 130318, 130322, 130325, 130329, 130334, 130339, 130343, 130348, 130353, 130358, 130362, 130367, 130371, 130375, 130378, 130382, 130386, 130390, 130393, 130397, 130402, 130406, 130410, 130414, 130417, 130421, 130426, 130430, 130435, 130440, 130444, 130449, 130455, 130461, 130466, 130472, 130478, 130483, 130489, 130494, 130499, 130503, 130508, 130513, 130518, 130522, 130527, 130533, 130538, 130543, 130548, 130552, 130557, 130562, 130567, 130571, 130576, 130582, 130588, 130593, 130599, 130605, 130610, 130615, 130620, 130624, 130629, 130634, 130638, 130643, 130649, 130654, 130659, 130664, 130668, 130673, 130679, 130684, 130689, 130694, 130698, 130703, 130709, 130715, 130720, 130726, 130732, 130737, 130743, 130748, 130753, 130757, 130762, 130767, 130772, 130776, 130781, 130785, 130789, 130792, 130796, 130801, 130806, 130810, 130815, 130820, 130824, 130828, 130832, 130835, 130839, 130843, 130847, 130850, 130854, 130859, 130863, 130867, 130871, 130874, 130878, 130883, 130888, 130892, 130897, 130902, 130907, 130911, 130916, 130920, 130924, 130927, 130931, 130935, 130939, 130942, 130946, 130951, 130955, 130959, 130963, 130966, 130970, 130975, -1, -1, -1, 130979, 130983, 130986, 130990, 130995, 130999, 131003, 131008, 131012, 131015, 131020, 131024, 131029, 131033, 131036, 131040, 131045, 131049, -1, -1, 131052, 131057, 131061, 131066, 131071, 131074, 131077, 131082, 131086, 131090, 131094, 131098, 131102, 131106, 131110, 131113, -1, 131116, 131120, 131124, 131129, 131132, 131135, 131140, 131144, 131147, 131152, 131156, 131161, -1, 131166, 131171, 131175, -1, 131181, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 131184, 131187, 131191, 131196, 131201, 131205, 131210, 131215, 131219, 131223, 131228, 131233, 131238, 131243, 131248, 131253, 131258, 131262, 131266, 131271, 131275, 131280, 131285, 131289, 131293, 131297, 131301, 131305, 131309, 131313, 131318, 131324, 131330, 131335, 131341, 131347, 131352, 131357, 131363, 131369, 131375, 131381, 131387, 131393, 131399, 131404, 131409, 131415, 131420, 131426, 131432, 131437, 131442, 131447, 131452, 131457, 131462, 131466, 131471, 131477, 131483, 131488, 131494, 131500, 131505, 131510, 131516, 131522, 131528, 131534, 131540, 131546, 131552, 131557, 131562, 131568, 131573, 131579, 131585, 131590, 131595, 131600, 131605, 131610, 131615, 131620, 131626, 131633, 131640, 131646, 131653, 131660, 131666, 131672, 131679, 131686, 131693, 131700, 131707, 131714, 131721, 131727, 131733, 131740, 131746, 131753, 131760, 131766, 131772, 131778, 131784, 131790, 131796, 131800, 131805, 131811, 131817, 131822, 131828, 131834, 131839, 131844, 131850, 131856, 131862, 131868, 131874, 131880, 131886, 131891, 131896, 131902, 131907, 131913, 131919, 131924, 131929, 131934, 131939, 131944, 131949, 131952, 131956, 131961, 131966, 131970, 131975, 131980, 131984, 131988, 131993, 131998, 132003, 132008, 132013, 132018, 132023, 132027, 132031, 132036, 132040, 132045, 132050, 132054, 132058, 132062, 132066, 132070, 132074, 132079, 132085, 132092, 132099, 132105, 132112, 132119, 132125, 132131, 132138, 132145, 132152, 132159, 132166, 132173, 132180, 132186, 132192, 132199, 132205, 132212, 132219, 132225, 132231, 132237, 132243, 132249, 132255, 132259, 132264, 132270, 132276, 132281, 132287, 132293, 132298, 132303, 132309, 132315, 132321, 132327, 132333, 132339, 132345, 132350, 132355, 132361, 132366, 132372, 132378, 132383, 132388, 132393, 132398, 132403, 132408, 132411, 132415, 132420, 132425, 132429, 132434, 132439, 132443, 132447, 132452, 132457, 132462, 132467, 132472, 132477, 132482, 132486, 132490, 132495, 132499, 132504, 132509, 132513, 132517, 132521, 132525, 132529, 132533, 132537, 132542, 132548, 132554, 132559, 132565, 132571, 132576, 132581, 132587, 132593, 132599, 132605, 132611, 132617, 132623, 132628, 132633, 132639, 132644, 132650, 132656, 132661, 132666, 132671, 132676, 132681, 132686, 132691, 132697, 132704, 132711, 132717, 132724, 132731, 132737, 132743, 132750, 132757, 132764, 132771, 132778, 132785, 132792, 132798, 132804, 132811, 132817, 132824, 132831, 132837, 132843, 132849, 132855, 132861, 132867, 132871, 132876, 132882, 132888, 132893, 132899, 132905, 132910, 132915, 132921, 132927, 132933, 132939, 132945, 132951, 132957, 132962, 132967, 132973, 132978, 132984, 132990, 132995, 133000, 133005, 133010, 133015, 133020, 133024, 133029, 133035, 133041, 133046, 133052, 133058, 133063, 133068, 133074, 133080, 133086, 133092, 133098, 133104, 133110, 133115, 133120, 133126, 133131, 133137, 133143, 133148, 133153, 133158, 133163, 133168, 133173, 133176, 133180, 133185, 133190, 133194, 133199, 133204, 133208, 133212, 133217, 133222, 133227, 133232, 133237, 133242, 133247, 133251, 133255, 133260, 133264, 133269, 133274, 133278, 133282, 133286, 133290, 133294, 133298, 133303, 133309, 133316, 133323, 133329, 133336, 133343, 133349, 133355, 133362, 133369, 133376, 133383, 133390, 133397, 133404, 133410, 133416, 133423, 133429, 133436, 133443, 133449, 133455, 133461, 133467, 133473, 133479, 133483, 133488, 133494, 133500, 133505, 133511, 133517, 133522, 133527, 133533, 133539, 133545, 133551, 133557, 133563, 133569, 133574, 133579, 133585, 133590, 133596, 133602, 133607, 133612, 133617, 133622, 133627, 133632, 133636, 133641, 133647, 133653, 133658, 133664, 133670, 133675, 133680, 133686, 133692, 133698, 133704, 133710, 133716, 133722, 133727, 133732, 133738, 133743, 133749, 133755, 133760, 133765, 133770, 133775, 133780, 133785, 133789, 133794, 133800, 133806, 133811, 133817, 133823, 133828, 133833, 133839, 133845, 133851, 133857, 133863, 133869, 133875, 133880, 133885, 133891, 133896, 133902, 133908, 133913, 133918, 133923, 133928, 133933, 133938, 133942, 133947, 133953, 133959, 133964, 133970, 133976, 133981, 133986, 133992, 133998, 134004, 134010, 134016, 134022, 134028, 134033, 134038, 134044, 134049, 134055, 134061, 134066, 134071, 134076, 134081, 134086, 134091, 134095, 134100, 134106, 134112, 134117, 134123, 134129, 134134, 134139, 134145, 134151, 134157, 134163, 134169, 134175, 134181, 134186, 134191, 134197, 134202, 134208, 134214, 134219, 134224, 134229, 134234, 134239, 134244, 134247, 134251, 134256, 134261, 134265, 134270, 134275, 134279, 134283, 134288, 134293, 134298, 134303, 134308, 134313, 134318, 134322, 134326, 134331, 134335, 134340, 134345, 134349, 134353, 134357, 134361, 134365, 134369, 134373, 134378, 134384, 134390, 134395, 134401, 134407, 134412, 134417, 134423, 134429, 134435, 134441, 134447, 134453, 134459, 134464, 134469, 134475, 134480, 134486, 134492, 134497, 134502, 134507, 134512, 134517, 134522, 134527, 134533, 134540, 134547, 134553, 134560, 134567, 134573, 134579, 134586, 134593, 134600, 134607, 134614, 134621, 134628, 134634, 134640, 134647, 134653, 134660, 134667, 134673, 134679, 134685, 134691, 134697, 134703, 134708, 134714, 134721, 134728, 134734, 134741, 134748, 134754, 134760, 134767, 134774, 134781, 134788, 134795, 134802, 134809, 134815, 134821, 134828, 134834, 134841, 134848, 134854, 134860, 134866, 134872, 134878, 134884, 134890, 134897, 134905, 134913, 134920, 134928, 134936, 134943, 134950, 134958, 134966, 134974, 134982, 134990, 134998, 135006, 135013, 135020, 135028, 135035, 135043, 135051, 135058, 135065, 135072, 135079, 135086, 135093, 135098, 135104, 135111, 135118, 135124, 135131, 135138, 135144, 135150, 135157, 135164, 135171, 135178, 135185, 135192, 135199, 135205, 135211, 135218, 135224, 135231, 135238, 135244, 135250, 135256, 135262, 135268, 135274, 135278, 135283, 135289, 135295, 135300, 135306, 135312, 135317, 135322, 135328, 135334, 135340, 135346, 135352, 135358, 135364, 135369, 135374, 135380, 135385, 135391, 135397, 135402, 135407, 135412, 135417, 135422, 135427, 135433, 135440, 135448, 135456, 135463, 135471, 135479, 135486, 135493, 135501, 135509, 135517, 135525, 135533, 135541, 135549, 135556, 135563, 135571, 135578, 135586, 135594, 135601, 135608, 135615, 135622, 135629, 135636, 135641, 135647, 135654, 135661, 135667, 135674, 135681, 135687, 135693, 135700, 135707, 135714, 135721, 135728, 135735, 135742, 135748, 135754, 135761, 135767, 135774, 135781, 135787, 135793, 135799, 135805, 135811, 135817, 135821, 135826, 135832, 135838, 135843, 135849, 135855, 135860, 135865, 135871, 135877, 135883, 135889, 135895, 135901, 135907, 135912, 135917, 135923, 135928, 135934, 135940, 135945, 135950, 135955, 135960, 135965, 135970, 135975, 135981, 135988, 135995, 136001, 136008, 136015, 136021, 136027, 136034, 136041, 136048, 136055, 136062, 136069, 136076, 136082, 136088, 136095, 136101, 136108, 136115, 136121, 136127, 136133, 136139, 136145, 136151, 136157, 136164, 136172, 136180, 136187, 136195, 136203, 136210, 136217, 136225, 136233, 136241, 136249, 136257, 136265, 136273, 136280, 136287, 136295, 136302, 136310, 136318, 136325, 136332, 136339, 136346, 136353, 136360, 136365, 136371, 136378, 136385, 136391, 136398, 136405, 136411, 136417, 136424, 136431, 136438, 136445, 136452, 136459, 136466, 136472, 136478, 136485, 136491, 136498, 136505, 136511, 136517, 136523, 136529, 136535, 136541, 136546, 136552, 136559, 136566, 136572, 136579, 136586, 136592, 136598, 136605, 136612, 136619, 136626, 136633, 136640, 136647, 136653, 136659, 136666, 136672, 136679, 136686, 136692, 136698, 136704, 136710, 136716, 136722, 136726, 136731, 136737, 136743, 136748, 136754, 136760, 136765, 136770, 136776, 136782, 136788, 136794, 136800, 136806, 136812, 136817, 136822, 136828, 136833, 136839, 136845, 136850, 136855, 136860, 136865, 136870, 136875, 136881, 136888, 136896, 136904, 136911, 136919, 136927, 136934, 136941, 136949, 136957, 136965, 136973, 136981, 136989, 136997, 137004, 137011, 137019, 137026, 137034, 137042, 137049, 137056, 137063, 137070, 137077, 137084, 137089, 137095, 137102, 137109, 137115, 137122, 137129, 137135, 137141, 137148, 137155, 137162, 137169, 137176, 137183, 137190, 137196, 137202, 137209, 137215, 137222, 137229, 137235, 137241, 137247, 137253, 137259, 137265, 137270, 137276, 137283, 137290, 137296, 137303, 137310, 137316, 137322, 137329, 137336, 137343, 137350, 137357, 137364, 137371, 137377, 137383, 137390, 137396, 137403, 137410, 137416, 137422, 137428, 137434, 137440, 137446, 137451, 137457, 137464, 137471, 137477, 137484, 137491, 137497, 137503, 137510, 137517, 137524, 137531, 137538, 137545, 137552, 137558, 137564, 137571, 137577, 137584, 137591, 137597, 137603, 137609, 137615, 137621, 137627, 137632, 137638, 137645, 137652, 137658, 137665, 137672, 137678, 137684, 137691, 137698, 137705, 137712, 137719, 137726, 137733, 137739, 137745, 137752, 137758, 137765, 137772, 137778, 137784, 137790, 137796, 137802, 137808, 137813, 137819, 137826, 137833, 137839, 137846, 137853, 137859, 137865, 137872, 137879, 137886, 137893, 137900, 137907, 137914, 137920, 137926, 137933, 137939, 137946, 137953, 137959, 137965, 137971, 137977, 137983, 137989, 137993, 137998, 138004, 138010, 138015, 138021, 138027, 138032, 138037, 138043, 138049, 138055, 138061, 138067, 138073, 138079, 138084, 138089, 138095, 138100, 138106, 138112, 138117, 138122, 138127, 138132, 138137, 138142, 138145, 138149, 138154, 138159, 138163, 138168, 138173, 138177, 138181, 138186, 138191, 138196, 138201, 138206, 138211, 138216, 138220, 138224, 138229, 138233, 138238, 138243, 138247, 138251, 138255, 138259, 138263, 138267, 138271, 138276, 138282, 138288, 138293, 138299, 138305, 138310, 138315, 138321, 138327, 138333, 138339, 138345, 138351, 138357, 138362, 138367, 138373, 138378, 138384, 138390, 138395, 138400, 138405, 138410, 138415, 138420, 138424, 138429, 138435, 138441, 138446, 138452, 138458, 138463, 138468, 138474, 138480, 138486, 138492, 138498, 138504, 138510, 138515, 138520, 138526, 138531, 138537, 138543, 138548, 138553, 138558, 138563, 138568, 138573, 138578, 138584, 138591, 138598, 138604, 138611, 138618, 138624, 138630, 138637, 138644, 138651, 138658, 138665, 138672, 138679, 138685, 138691, 138698, 138704, 138711, 138718, 138724, 138730, 138736, 138742, 138748, 138754, 138758, 138763, 138769, 138775, 138780, 138786, 138792, 138797, 138802, 138808, 138814, 138820, 138826, 138832, 138838, 138844, 138849, 138854, 138860, 138865, 138871, 138877, 138882, 138887, 138892, 138897, 138902, 138907, 138910, 138914, 138919, 138924, 138928, 138933, 138938, 138942, 138946, 138951, 138956, 138961, 138966, 138971, 138976, 138981, 138985, 138989, 138994, 138998, 139003, 139008, 139012, 139016, 139020, 139024, 139028, 139032, 139037, 139043, 139050, 139057, 139063, 139070, 139077, 139083, 139089, 139096, 139103, 139110, 139117, 139124, 139131, 139138, 139144, 139150, 139157, 139163, 139170, 139177, 139183, 139189, 139195, 139201, 139207, 139213, 139217, 139222, 139228, 139234, 139239, 139245, 139251, 139256, 139261, 139267, 139273, 139279, 139285, 139291, 139297, 139303, 139308, 139313, 139319, 139324, 139330, 139336, 139341, 139346, 139351, 139356, 139361, 139366, 139369, 139373, 139378, 139383, 139387, 139392, 139397, 139401, 139405, 139410, 139415, 139420, 139425, 139430, 139435, 139440, 139444, 139448, 139453, 139457, 139462, 139467, 139471, 139475, 139479, 139483, 139487, 139491, 139495, 139500, 139506, 139512, 139517, 139523, 139529, 139534, 139539, 139545, 139551, 139557, 139563, 139569, 139575, 139581, 139586, 139591, 139597, 139602, 139608, 139614, 139619, 139624, 139629, 139634, 139639, 139644, 139649, 139655, 139662, 139669, 139675, 139682, 139689, 139695, 139701, 139708, 139715, 139722, 139729, 139736, 139743, 139750, 139756, 139762, 139769, 139775, 139782, 139789, 139795, 139801, 139807, 139813, 139819, 139825, 139829, 139834, 139840, 139846, 139851, 139857, 139863, 139868, 139873, 139879, 139885, 139891, 139897, 139903, 139909, 139915, 139920, 139925, 139931, 139936, 139942, 139948, 139953, 139958, 139963, 139968, 139973, 139978, 139982, 139987, 139993, 139999, 140004, 140010, 140016, 140021, 140026, 140032, 140038, 140044, 140050, 140056, 140062, 140068, 140073, 140078, 140084, 140089, 140095, 140101, 140106, 140111, 140116, 140121, 140126, 140131, 140134, 140138, 140143, 140148, 140152, 140157, 140162, 140166, 140170, 140175, 140180, 140185, 140190, 140195, 140200, 140205, 140209, 140213, 140218, 140222, 140227, 140232, 140236, 140240, 140244, 140248, 140252, 140256, 140261, 140267, 140274, 140281, 140287, 140294, 140301, 140307, 140313, 140320, 140327, 140334, 140341, 140348, 140355, 140362, 140368, 140374, 140381, 140387, 140394, 140401, 140407, 140413, 140419, 140425, 140431, 140437, 140441, 140446, 140452, 140458, 140463, 140469, 140475, 140480, 140485, 140491, 140497, 140503, 140509, 140515, 140521, 140527, 140532, 140537, 140543, 140548, 140554, 140560, 140565, 140570, 140575, 140580, 140585, 140590, 140594, 140599, 140605, 140611, 140616, 140622, 140628, 140633, 140638, 140644, 140650, 140656, 140662, 140668, 140674, 140680, 140685, 140690, 140696, 140701, 140707, 140713, 140718, 140723, 140728, 140733, 140738, 140743, 140747, 140752, 140758, 140764, 140769, 140775, 140781, 140786, 140791, 140797, 140803, 140809, 140815, 140821, 140827, 140833, 140838, 140843, 140849, 140854, 140860, 140866, 140871, 140876, 140881, 140886, 140891, 140896, 140900, 140905, 140911, 140917, 140922, 140928, 140934, 140939, 140944, 140950, 140956, 140962, 140968, 140974, 140980, 140986, 140991, 140996, 141002, 141007, 141013, 141019, 141024, 141029, 141034, 141039, 141044, 141049, 141053, 141058, 141064, 141070, 141075, 141081, 141087, 141092, 141097, 141103, 141109, 141115, 141121, 141127, 141133, 141139, 141144, 141149, 141155, 141160, 141166, 141172, 141177, 141182, 141187, 141192, 141197, 141202, 141205, 141209, 141214, 141219, 141223, 141228, 141233, 141237, 141241, 141246, 141251, 141256, 141261, 141266, 141271, 141276, 141280, 141284, 141289, 141293, 141298, 141303, 141307, 141311, 141315, 141319, 141323, 141327, 141330, 141334, 141339, 141344, 141348, 141353, 141358, 141362, 141366, 141371, 141376, 141381, 141386, 141391, 141396, 141401, 141405, 141409, 141414, 141418, 141423, 141428, 141432, 141436, 141440, 141444, 141448, 141452, 141456, 141461, 141467, 141473, 141478, 141484, 141490, 141495, 141500, 141506, 141512, 141518, 141524, 141530, 141536, 141542, 141547, 141552, 141558, 141563, 141569, 141575, 141580, 141585, 141590, 141595, 141600, 141605, 141609, 141614, 141620, 141626, 141631, 141637, 141643, 141648, 141653, 141659, 141665, 141671, 141677, 141683, 141689, 141695, 141700, 141705, 141711, 141716, 141722, 141728, 141733, 141738, 141743, 141748, 141753, 141758, 141763, 141769, 141776, 141783, 141789, 141796, 141803, 141809, 141815, 141822, 141829, 141836, 141843, 141850, 141857, 141864, 141870, 141876, 141883, 141889, 141896, 141903, 141909, 141915, 141921, 141927, 141933, 141939, 141943, 141948, 141954, 141960, 141965, 141971, 141977, 141982, 141987, 141993, 141999, 142005, 142011, 142017, 142023, 142029, 142034, 142039, 142045, 142050, 142056, 142062, 142067, 142072, 142077, 142082, 142087, 142092, 142095, 142099, 142104, 142109, 142113, 142118, 142123, 142127, 142131, 142136, 142141, 142146, 142151, 142156, 142161, 142166, 142170, 142174, 142179, 142183, 142188, 142193, 142197, 142201, 142205, 142209, 142213, 142217, 142222, 142228, 142235, 142242, 142248, 142255, 142262, 142268, 142274, 142281, 142288, 142295, 142302, 142309, 142316, 142323, 142329, 142335, 142342, 142348, 142355, 142362, 142368, 142374, 142380, 142386, 142392, 142398, 142402, 142407, 142413, 142419, 142424, 142430, 142436, 142441, 142446, 142452, 142458, 142464, 142470, 142476, 142482, 142488, 142493, 142498, 142504, 142509, 142515, 142521, 142526, 142531, 142536, 142541, 142546, 142551, 142554, 142558, 142563, 142568, 142572, 142577, 142582, 142586, 142590, 142595, 142600, 142605, 142610, 142615, 142620, 142625, 142629, 142633, 142638, 142642, 142647, 142652, 142656, 142660, 142664, 142668, 142672, 142676, 142680, 142685, 142691, 142697, 142702, 142708, 142714, 142719, 142724, 142730, 142736, 142742, 142748, 142754, 142760, 142766, 142771, 142776, 142782, 142787, 142793, 142799, 142804, 142809, 142814, 142819, 142824, 142829, 142834, 142840, 142847, 142854, 142860, 142867, 142874, 142880, 142886, 142893, 142900, 142907, 142914, 142921, 142928, 142935, 142941, 142947, 142954, 142960, 142967, 142974, 142980, 142986, 142992, 142998, 143004, 143010, 143014, 143019, 143025, 143031, 143036, 143042, 143048, 143053, 143058, 143064, 143070, 143076, 143082, 143088, 143094, 143100, 143105, 143110, 143116, 143121, 143127, 143133, 143138, 143143, 143148, 143153, 143158, 143163, 143167, 143172, 143178, 143184, 143189, 143195, 143201, 143206, 143211, 143217, 143223, 143229, 143235, 143241, 143247, 143253, 143258, 143263, 143269, 143274, 143280, 143286, 143291, 143296, 143301, 143306, 143311, 143316, 143319, 143323, 143328, 143333, 143337, 143342, 143347, 143351, 143355, 143360, 143365, 143370, 143375, 143380, 143385, 143390, 143394, 143398, 143403, 143407, 143412, 143417, 143421, 143425, 143429, 143433, 143437, 143441, 143446, 143452, 143459, 143466, 143472, 143479, 143486, 143492, 143498, 143505, 143512, 143519, 143526, 143533, 143540, 143547, 143553, 143559, 143566, 143572, 143579, 143586, 143592, 143598, 143604, 143610, 143616, 143622, 143626, 143631, 143637, 143643, 143648, 143654, 143660, 143665, 143670, 143676, 143682, 143688, 143694, 143700, 143706, 143712, 143717, 143722, 143728, 143733, 143739, 143745, 143750, 143755, 143760, 143765, 143770, 143775, 143779, 143784, 143790, 143796, 143801, 143807, 143813, 143818, 143823, 143829, 143835, 143841, 143847, 143853, 143859, 143865, 143870, 143875, 143881, 143886, 143892, 143898, 143903, 143908, 143913, 143918, 143923, 143928, 143932, 143937, 143943, 143949, 143954, 143960, 143966, 143971, 143976, 143982, 143988, 143994, 144000, 144006, 144012, 144018, 144023, 144028, 144034, 144039, 144045, 144051, 144056, 144061, 144066, 144071, 144076, 144081, 144085, 144090, 144096, 144102, 144107, 144113, 144119, 144124, 144129, 144135, 144141, 144147, 144153, 144159, 144165, 144171, 144176, 144181, 144187, 144192, 144198, 144204, 144209, 144214, 144219, 144224, 144229, 144234, 144238, 144243, 144249, 144255, 144260, 144266, 144272, 144277, 144282, 144288, 144294, 144300, 144306, 144312, 144318, 144324, 144329, 144334, 144340, 144345, 144351, 144357, 144362, 144367, 144372, 144377, 144382, 144387, 144390, 144394, 144399, 144404, 144408, 144413, 144418, 144422, 144426, 144431, 144436, 144441, 144446, 144451, 144456, 144461, 144465, 144469, 144474, 144478, 144483, 144488, 144492, 144496, 144500, 144504, 144508, 144512, 144516, 144521, 144527, 144533, 144538, 144544, 144550, 144555, 144560, 144566, 144572, 144578, 144584, 144590, 144596, 144602, 144607, 144612, 144618, 144623, 144629, 144635, 144640, 144645, 144650, 144655, 144660, 144665, 144670, 144676, 144683, 144690, 144696, 144703, 144710, 144716, 144722, 144729, 144736, 144743, 144750, 144757, 144764, 144771, 144777, 144783, 144790, 144796, 144803, 144810, 144816, 144822, 144828, 144834, 144840, 144846, 144851, 144857, 144864, 144871, 144877, 144884, 144891, 144897, 144903, 144910, 144917, 144924, 144931, 144938, 144945, 144952, 144958, 144964, 144971, 144977, 144984, 144991, 144997, 145003, 145009, 145015, 145021, 145027, 145033, 145040, 145048, 145056, 145063, 145071, 145079, 145086, 145093, 145101, 145109, 145117, 145125, 145133, 145141, 145149, 145156, 145163, 145171, 145178, 145186, 145194, 145201, 145208, 145215, 145222, 145229, 145236, 145241, 145247, 145254, 145261, 145267, 145274, 145281, 145287, 145293, 145300, 145307, 145314, 145321, 145328, 145335, 145342, 145348, 145354, 145361, 145367, 145374, 145381, 145387, 145393, 145399, 145405, 145411, 145417, 145421, 145426, 145432, 145438, 145443, 145449, 145455, 145460, 145465, 145471, 145477, 145483, 145489, 145495, 145501, 145507, 145512, 145517, 145523, 145528, 145534, 145540, 145545, 145550, 145555, 145560, 145565, 145570, 145576, 145583, 145591, 145599, 145606, 145614, 145622, 145629, 145636, 145644, 145652, 145660, 145668, 145676, 145684, 145692, 145699, 145706, 145714, 145721, 145729, 145737, 145744, 145751, 145758, 145765, 145772, 145779, 145784, 145790, 145797, 145804, 145810, 145817, 145824, 145830, 145836, 145843, 145850, 145857, 145864, 145871, 145878, 145885, 145891, 145897, 145904, 145910, 145917, 145924, 145930, 145936, 145942, 145948, 145954, 145960, 145964, 145969, 145975, 145981, 145986, 145992, 145998, 146003, 146008, 146014, 146020, 146026, 146032, 146038, 146044, 146050, 146055, 146060, 146066, 146071, 146077, 146083, 146088, 146093, 146098, 146103, 146108, 146113, 146118, 146124, 146131, 146138, 146144, 146151, 146158, 146164, 146170, 146177, 146184, 146191, 146198, 146205, 146212, 146219, 146225, 146231, 146238, 146244, 146251, 146258, 146264, 146270, 146276, 146282, 146288, 146294, 146300, 146307, 146315, 146323, 146330, 146338, 146346, 146353, 146360, 146368, 146376, 146384, 146392, 146400, 146408, 146416, 146423, 146430, 146438, 146445, 146453, 146461, 146468, 146475, 146482, 146489, 146496, 146503, 146508, 146514, 146521, 146528, 146534, 146541, 146548, 146554, 146560, 146567, 146574, 146581, 146588, 146595, 146602, 146609, 146615, 146621, 146628, 146634, 146641, 146648, 146654, 146660, 146666, 146672, 146678, 146684, 146689, 146695, 146702, 146709, 146715, 146722, 146729, 146735, 146741, 146748, 146755, 146762, 146769, 146776, 146783, 146790, 146796, 146802, 146809, 146815, 146822, 146829, 146835, 146841, 146847, 146853, 146859, 146865, 146869, 146874, 146880, 146886, 146891, 146897, 146903, 146908, 146913, 146919, 146925, 146931, 146937, 146943, 146949, 146955, 146960, 146965, 146971, 146976, 146982, 146988, 146993, 146998, 147003, 147008, 147013, 147018, 147024, 147031, 147039, 147047, 147054, 147062, 147070, 147077, 147084, 147092, 147100, 147108, 147116, 147124, 147132, 147140, 147147, 147154, 147162, 147169, 147177, 147185, 147192, 147199, 147206, 147213, 147220, 147227, 147232, 147238, 147245, 147252, 147258, 147265, 147272, 147278, 147284, 147291, 147298, 147305, 147312, 147319, 147326, 147333, 147339, 147345, 147352, 147358, 147365, 147372, 147378, 147384, 147390, 147396, 147402, 147408, 147413, 147419, 147426, 147433, 147439, 147446, 147453, 147459, 147465, 147472, 147479, 147486, 147493, 147500, 147507, 147514, 147520, 147526, 147533, 147539, 147546, 147553, 147559, 147565, 147571, 147577, 147583, 147589, 147594, 147600, 147607, 147614, 147620, 147627, 147634, 147640, 147646, 147653, 147660, 147667, 147674, 147681, 147688, 147695, 147701, 147707, 147714, 147720, 147727, 147734, 147740, 147746, 147752, 147758, 147764, 147770, 147775, 147781, 147788, 147795, 147801, 147808, 147815, 147821, 147827, 147834, 147841, 147848, 147855, 147862, 147869, 147876, 147882, 147888, 147895, 147901, 147908, 147915, 147921, 147927, 147933, 147939, 147945, 147951, 147956, 147962, 147969, 147976, 147982, 147989, 147996, 148002, 148008, 148015, 148022, 148029, 148036, 148043, 148050, 148057, 148063, 148069, 148076, 148082, 148089, 148096, 148102, 148108, 148114, 148120, 148126, 148132, 148136, 148141, 148147, 148153, 148158, 148164, 148170, 148175, 148180, 148186, 148192, 148198, 148204, 148210, 148216, 148222, 148227, 148232, 148238, 148243, 148249, 148255, 148260, 148265, 148270, 148275, 148280, 148285, 148288, 148292, 148297, 148302, 148306, 148311, 148316, 148320, 148324, 148329, 148334, 148339, 148344, 148349, 148354, 148359, 148363, 148367, 148372, 148376, 148381, 148386, 148390, 148394, 148398, 148402, 148406, 148410, 148414, 148419, 148425, 148431, 148436, 148442, 148448, 148453, 148458, 148464, 148470, 148476, 148482, 148488, 148494, 148500, 148505, 148510, 148516, 148521, 148527, 148533, 148538, 148543, 148548, 148553, 148558, 148563, 148567, 148572, 148578, 148584, 148589, 148595, 148601, 148606, 148611, 148617, 148623, 148629, 148635, 148641, 148647, 148653, 148658, 148663, 148669, 148674, 148680, 148686, 148691, 148696, 148701, 148706, 148711, 148716, 148721, 148727, 148734, 148741, 148747, 148754, 148761, 148767, 148773, 148780, 148787, 148794, 148801, 148808, 148815, 148822, 148828, 148834, 148841, 148847, 148854, 148861, 148867, 148873, 148879, 148885, 148891, 148897, 148901, 148906, 148912, 148918, 148923, 148929, 148935, 148940, 148945, 148951, 148957, 148963, 148969, 148975, 148981, 148987, 148992, 148997, 149003, 149008, 149014, 149020, 149025, 149030, 149035, 149040, 149045, 149050, 149053, 149057, 149062, 149067, 149071, 149076, 149081, 149085, 149089, 149094, 149099, 149104, 149109, 149114, 149119, 149124, 149128, 149132, 149137, 149141, 149146, 149151, 149155, 149159, 149163, 149167, 149171, 149175, 149180, 149186, 149193, 149200, 149206, 149213, 149220, 149226, 149232, 149239, 149246, 149253, 149260, 149267, 149274, 149281, 149287, 149293, 149300, 149306, 149313, 149320, 149326, 149332, 149338, 149344, 149350, 149356, 149360, 149365, 149371, 149377, 149382, 149388, 149394, 149399, 149404, 149410, 149416, 149422, 149428, 149434, 149440, 149446, 149451, 149456, 149462, 149467, 149473, 149479, 149484, 149489, 149494, 149499, 149504, 149509, 149512, 149516, 149521, 149526, 149530, 149535, 149540, 149544, 149548, 149553, 149558, 149563, 149568, 149573, 149578, 149583, 149587, 149591, 149596, 149600, 149605, 149610, 149614, 149618, 149622, 149626, 149630, 149634, 149638, 149643, 149649, 149655, 149660, 149666, 149672, 149677, 149682, 149688, 149694, 149700, 149706, 149712, 149718, 149724, 149729, 149734, 149740, 149745, 149751, 149757, 149762, 149767, 149772, 149777, 149782, 149787, 149792, 149798, 149805, 149812, 149818, 149825, 149832, 149838, 149844, 149851, 149858, 149865, 149872, 149879, 149886, 149893, 149899, 149905, 149912, 149918, 149925, 149932, 149938, 149944, 149950, 149956, 149962, 149968, 149972, 149977, 149983, 149989, 149994, 150000, 150006, 150011, 150016, 150022, 150028, 150034, 150040, 150046, 150052, 150058, 150063, 150068, 150074, 150079, 150085, 150091, 150096, 150101, 150106, 150111, 150116, 150121, 150125, 150130, 150136, 150142, 150147, 150153, 150159, 150164, 150169, 150175, 150181, 150187, 150193, 150199, 150205, 150211, 150216, 150221, 150227, 150232, 150238, 150244, 150249, 150254, 150259, 150264, 150269, 150274, 150277, 150281, 150286, 150291, 150295, 150300, 150305, 150309, 150313, 150318, 150323, 150328, 150333, 150338, 150343, 150348, 150352, 150356, 150361, 150365, 150370, 150375, 150379, 150383, 150387, 150391, 150395, 150399, 150404, 150410, 150417, 150424, 150430, 150437, 150444, 150450, 150456, 150463, 150470, 150477, 150484, 150491, 150498, 150505, 150511, 150517, 150524, 150530, 150537, 150544, 150550, 150556, 150562, 150568, 150574, 150580, 150584, 150589, 150595, 150601, 150606, 150612, 150618, 150623, 150628, 150634, 150640, 150646, 150652, 150658, 150664, 150670, 150675, 150680, 150686, 150691, 150697, 150703, 150708, 150713, 150718, 150723, 150728, 150733, 150737, 150742, 150748, 150754, 150759, 150765, 150771, 150776, 150781, 150787, 150793, 150799, 150805, 150811, 150817, 150823, 150828, 150833, 150839, 150844, 150850, 150856, 150861, 150866, 150871, 150876, 150881, 150886, 150890, 150895, 150901, 150907, 150912, 150918, 150924, 150929, 150934, 150940, 150946, 150952, 150958, 150964, 150970, 150976, 150981, 150986, 150992, 150997, 151003, 151009, 151014, 151019, 151024, 151029, 151034, 151039, 151043, 151048, 151054, 151060, 151065, 151071, 151077, 151082, 151087, 151093, 151099, 151105, 151111, 151117, 151123, 151129, 151134, 151139, 151145, 151150, 151156, 151162, 151167, 151172, 151177, 151182, 151187, 151192, 151196, 151201, 151207, 151213, 151218, 151224, 151230, 151235, 151240, 151246, 151252, 151258, 151264, 151270, 151276, 151282, 151287, 151292, 151298, 151303, 151309, 151315, 151320, 151325, 151330, 151335, 151340, 151345, 151348, 151352, 151357, 151362, 151366, 151371, 151376, 151380, 151384, 151389, 151394, 151399, 151404, 151409, 151414, 151419, 151423, 151427, 151432, 151436, 151441, 151446, 151450, 151454, 151458, 151462, 151466, 151470, 151473, 151477, 151482, 151487, 151491, 151496, 151501, 151505, 151509, 151514, 151519, 151524, 151529, 151534, 151539, 151544, 151548, 151552, 151557, 151561, 151566, 151571, 151575, 151579, 151583, 151587, 151591, 151595, 151599, 151604, 151610, 151616, 151621, 151627, 151633, 151638, 151643, 151649, 151655, 151661, 151667, 151673, 151679, 151685, 151690, 151695, 151701, 151706, 151712, 151718, 151723, 151728, 151733, 151738, 151743, 151748, 151752, 151757, 151763, 151769, 151774, 151780, 151786, 151791, 151796, 151802, 151808, 151814, 151820, 151826, 151832, 151838, 151843, 151848, 151854, 151859, 151865, 151871, 151876, 151881, 151886, 151891, 151896, 151901, 151906, 151912, 151919, 151926, 151932, 151939, 151946, 151952, 151958, 151965, 151972, 151979, 151986, 151993, 152000, 152007, 152013, 152019, 152026, 152032, 152039, 152046, 152052, 152058, 152064, 152070, 152076, 152082, 152086, 152091, 152097, 152103, 152108, 152114, 152120, 152125, 152130, 152136, 152142, 152148, 152154, 152160, 152166, 152172, 152177, 152182, 152188, 152193, 152199, 152205, 152210, 152215, 152220, 152225, 152230, 152235, 152238, 152242, 152247, 152252, 152256, 152261, 152266, 152270, 152274, 152279, 152284, 152289, 152294, 152299, 152304, 152309, 152313, 152317, 152322, 152326, 152331, 152336, 152340, 152344, 152348, 152352, 152356, 152360, 152365, 152371, 152378, 152385, 152391, 152398, 152405, 152411, 152417, 152424, 152431, 152438, 152445, 152452, 152459, 152466, 152472, 152478, 152485, 152491, 152498, 152505, 152511, 152517, 152523, 152529, 152535, 152541, 152545, 152550, 152556, 152562, 152567, 152573, 152579, 152584, 152589, 152595, 152601, 152607, 152613, 152619, 152625, 152631, 152636, 152641, 152647, 152652, 152658, 152664, 152669, 152674, 152679, 152684, 152689, 152694, 152697, 152701, 152706, 152711, 152715, 152720, 152725, 152729, 152733, 152738, 152743, 152748, 152753, 152758, 152763, 152768, 152772, 152776, 152781, 152785, 152790, 152795, 152799, 152803, 152807, 152811, 152815, 152819, 152823, 152828, 152834, 152840, 152845, 152851, 152857, 152862, 152867, 152873, 152879, 152885, 152891, 152897, 152903, 152909, 152914, 152919, 152925, 152930, 152936, 152942, 152947, 152952, 152957, 152962, 152967, 152972, 152977, 152983, 152990, 152997, 153003, 153010, 153017, 153023, 153029, 153036, 153043, 153050, 153057, 153064, 153071, 153078, 153084, 153090, 153097, 153103, 153110, 153117, 153123, 153129, 153135, 153141, 153147, 153153, 153157, 153162, 153168, 153174, 153179, 153185, 153191, 153196, 153201, 153207, 153213, 153219, 153225, 153231, 153237, 153243, 153248, 153253, 153259, 153264, 153270, 153276, 153281, 153286, 153291, 153296, 153301, 153306, 153310, 153315, 153321, 153327, 153332, 153338, 153344, 153349, 153354, 153360, 153366, 153372, 153378, 153384, 153390, 153396, 153401, 153406, 153412, 153417, 153423, 153429, 153434, 153439, 153444, 153449, 153454, 153459, 153462, 153466, 153471, 153476, 153480, 153485, 153490, 153494, 153498, 153503, 153508, 153513, 153518, 153523, 153528, 153533, 153537, 153541, 153546, 153550, 153555, 153560, 153564, 153568, 153572, 153576, 153580, 153584, 153589, 153595, 153602, 153609, 153615, 153622, 153629, 153635, 153641, 153648, 153655, 153662, 153669, 153676, 153683, 153690, 153696, 153702, 153709, 153715, 153722, 153729, 153735, 153741, 153747, 153753, 153759, 153765, 153769, 153774, 153780, 153786, 153791, 153797, 153803, 153808, 153813, 153819, 153825, 153831, 153837, 153843, 153849, 153855, 153860, 153865, 153871, 153876, 153882, 153888, 153893, 153898, 153903, 153908, 153913, 153918, 153922, 153927, 153933, 153939, 153944, 153950, 153956, 153961, 153966, 153972, 153978, 153984, 153990, 153996, 154002, 154008, 154013, 154018, 154024, 154029, 154035, 154041, 154046, 154051, 154056, 154061, 154066, 154071, 154075, 154080, 154086, 154092, 154097, 154103, 154109, 154114, 154119, 154125, 154131, 154137, 154143, 154149, 154155, 154161, 154166, 154171, 154177, 154182, 154188, 154194, 154199, 154204, 154209, 154214, 154219, 154224, 154228, 154233, 154239, 154245, 154250, 154256, 154262, 154267, 154272, 154278, 154284, 154290, 154296, 154302, 154308, 154314, 154319, 154324, 154330, 154335, 154341, 154347, 154352, 154357, 154362, 154367, 154372, 154377, 154381, 154386, 154392, 154398, 154403, 154409, 154415, 154420, 154425, 154431, 154437, 154443, 154449, 154455, 154461, 154467, 154472, 154477, 154483, 154488, 154494, 154500, 154505, 154510, 154515, 154520, 154525, 154530, 154533, 154537, 154542, 154547, 154551, 154556, 154561, 154565, 154569, 154574, 154579, 154584, 154589, 154594, 154599, 154604, 154608, 154612, 154617, 154621, 154626, 154631, 154635, 154639, 154643, 154647, 154651, 154655, 154658, 154662, 154667, 154672, 154676, 154681, 154686, 154690, 154694, 154699, 154704, 154709, 154714, 154719, 154724, 154729, 154733, 154737, 154742, 154746, 154751, 154756, 154760, 154764, 154768, 154772, 154776, 154780, 154784, 154789, 154795, 154801, 154806, 154812, 154818, 154823, 154828, 154834, 154840, 154846, 154852, 154858, 154864, 154870, 154875, 154880, 154886, 154891, 154897, 154903, 154908, 154913, 154918, 154923, 154928, 154933, 154937, 154942, 154948, 154954, 154959, 154965, 154971, 154976, 154981, 154987, 154993, 154999, 155005, 155011, 155017, 155023, 155028, 155033, 155039, 155044, 155050, 155056, 155061, 155066, 155071, 155076, 155081, 155086, 155091, 155097, 155104, 155111, 155117, 155124, 155131, 155137, 155143, 155150, 155157, 155164, 155171, 155178, 155185, 155192, 155198, 155204, 155211, 155217, 155224, 155231, 155237, 155243, 155249, 155255, 155261, 155267, 155271, 155276, 155282, 155288, 155293, 155299, 155305, 155310, 155315, 155321, 155327, 155333, 155339, 155345, 155351, 155357, 155362, 155367, 155373, 155378, 155384, 155390, 155395, 155400, 155405, 155410, 155415, 155420, 155423, 155427, 155432, 155437, 155441, 155446, 155451, 155455, 155459, 155464, 155469, 155474, 155479, 155484, 155489, 155494, 155498, 155502, 155507, 155511, 155516, 155521, 155525, 155529, 155533, 155537, 155541, 155545, 155550, 155556, 155563, 155570, 155576, 155583, 155590, 155596, 155602, 155609, 155616, 155623, 155630, 155637, 155644, 155651, 155657, 155663, 155670, 155676, 155683, 155690, 155696, 155702, 155708, 155714, 155720, 155726, 155730, 155735, 155741, 155747, 155752, 155758, 155764, 155769, 155774, 155780, 155786, 155792, 155798, 155804, 155810, 155816, 155821, 155826, 155832, 155837, 155843, 155849, 155854, 155859, 155864, 155869, 155874, 155879, 155882, 155886, 155891, 155896, 155900, 155905, 155910, 155914, 155918, 155923, 155928, 155933, 155938, 155943, 155948, 155953, 155957, 155961, 155966, 155970, 155975, 155980, 155984, 155988, 155992, 155996, 156000, 156004, 156008, 156013, 156019, 156025, 156030, 156036, 156042, 156047, 156052, 156058, 156064, 156070, 156076, 156082, 156088, 156094, 156099, 156104, 156110, 156115, 156121, 156127, 156132, 156137, 156142, 156147, 156152, 156157, 156162, 156168, 156175, 156182, 156188, 156195, 156202, 156208, 156214, 156221, 156228, 156235, 156242, 156249, 156256, 156263, 156269, 156275, 156282, 156288, 156295, 156302, 156308, 156314, 156320, 156326, 156332, 156338, 156342, 156347, 156353, 156359, 156364, 156370, 156376, 156381, 156386, 156392, 156398, 156404, 156410, 156416, 156422, 156428, 156433, 156438, 156444, 156449, 156455, 156461, 156466, 156471, 156476, 156481, 156486, 156491, 156495, 156500, 156506, 156512, 156517, 156523, 156529, 156534, 156539, 156545, 156551, 156557, 156563, 156569, 156575, 156581, 156586, 156591, 156597, 156602, 156608, 156614, 156619, 156624, 156629, 156634, 156639, 156644, 156647, 156651, 156656, 156661, 156665, 156670, 156675, 156679, 156683, 156688, 156693, 156698, 156703, 156708, 156713, 156718, 156722, 156726, 156731, 156735, 156740, 156745, 156749, 156753, 156757, 156761, 156765, 156769, 156774, 156780, 156787, 156794, 156800, 156807, 156814, 156820, 156826, 156833, 156840, 156847, 156854, 156861, 156868, 156875, 156881, 156887, 156894, 156900, 156907, 156914, 156920, 156926, 156932, 156938, 156944, 156950, 156954, 156959, 156965, 156971, 156976, 156982, 156988, 156993, 156998, 157004, 157010, 157016, 157022, 157028, 157034, 157040, 157045, 157050, 157056, 157061, 157067, 157073, 157078, 157083, 157088, 157093, 157098, 157103, 157107, 157112, 157118, 157124, 157129, 157135, 157141, 157146, 157151, 157157, 157163, 157169, 157175, 157181, 157187, 157193, 157198, 157203, 157209, 157214, 157220, 157226, 157231, 157236, 157241, 157246, 157251, 157256, 157260, 157265, 157271, 157277, 157282, 157288, 157294, 157299, 157304, 157310, 157316, 157322, 157328, 157334, 157340, 157346, 157351, 157356, 157362, 157367, 157373, 157379, 157384, 157389, 157394, 157399, 157404, 157409, 157413, 157418, 157424, 157430, 157435, 157441, 157447, 157452, 157457, 157463, 157469, 157475, 157481, 157487, 157493, 157499, 157504, 157509, 157515, 157520, 157526, 157532, 157537, 157542, 157547, 157552, 157557, 157562, 157566, 157571, 157577, 157583, 157588, 157594, 157600, 157605, 157610, 157616, 157622, 157628, 157634, 157640, 157646, 157652, 157657, 157662, 157668, 157673, 157679, 157685, 157690, 157695, 157700, 157705, 157710, 157715, 157718, 157722, 157727, 157732, 157736, 157741, 157746, 157750, 157754, 157759, 157764, 157769, 157774, 157779, 157784, 157789, 157793, 157797, 157802, 157806, 157811, 157816, 157820, 157824, 157828, 157832, 157836, 157840, 157844, 157849, 157855, 157861, 157866, 157872, 157878, 157883, 157888, 157894, 157900, 157906, 157912, 157918, 157924, 157930, 157935, 157940, 157946, 157951, 157957, 157963, 157968, 157973, 157978, 157983, 157988, 157993, 157998, 158004, 158011, 158018, 158024, 158031, 158038, 158044, 158050, 158057, 158064, 158071, 158078, 158085, 158092, 158099, 158105, 158111, 158118, 158124, 158131, 158138, 158144, 158150, 158156, 158162, 158168, 158174, 158179, 158185, 158192, 158199, 158205, 158212, 158219, 158225, 158231, 158238, 158245, 158252, 158259, 158266, 158273, 158280, 158286, 158292, 158299, 158305, 158312, 158319, 158325, 158331, 158337, 158343, 158349, 158355, 158361, 158368, 158376, 158384, 158391, 158399, 158407, 158414, 158421, 158429, 158437, 158445, 158453, 158461, 158469, 158477, 158484, 158491, 158499, 158506, 158514, 158522, 158529, 158536, 158543, 158550, 158557, 158564, 158569, 158575, 158582, 158589, 158595, 158602, 158609, 158615, 158621, 158628, 158635, 158642, 158649, 158656, 158663, 158670, 158676, 158682, 158689, 158695, 158702, 158709, 158715, 158721, 158727, 158733, 158739, 158745, 158749, 158754, 158760, 158766, 158771, 158777, 158783, 158788, 158793, 158799, 158805, 158811, 158817, 158823, 158829, 158835, 158840, 158845, 158851, 158856, 158862, 158868, 158873, 158878, 158883, 158888, 158893, 158898, 158904, 158911, 158919, 158927, 158934, 158942, 158950, 158957, 158964, 158972, 158980, 158988, 158996, 159004, 159012, 159020, 159027, 159034, 159042, 159049, 159057, 159065, 159072, 159079, 159086, 159093, 159100, 159107, 159112, 159118, 159125, 159132, 159138, 159145, 159152, 159158, 159164, 159171, 159178, 159185, 159192, 159199, 159206, 159213, 159219, 159225, 159232, 159238, 159245, 159252, 159258, 159264, 159270, 159276, 159282, 159288, 159292, 159297, 159303, 159309, 159314, 159320, 159326, 159331, 159336, 159342, 159348, 159354, 159360, 159366, 159372, 159378, 159383, 159388, 159394, 159399, 159405, 159411, 159416, 159421, 159426, 159431, 159436, 159441, 159446, 159452, 159459, 159466, 159472, 159479, 159486, 159492, 159498, 159505, 159512, 159519, 159526, 159533, 159540, 159547, 159553, 159559, 159566, 159572, 159579, 159586, 159592, 159598, 159604, 159610, 159616, 159622, 159628, 159635, 159643, 159651, 159658, 159666, 159674, 159681, 159688, 159696, 159704, 159712, 159720, 159728, 159736, 159744, 159751, 159758, 159766, 159773, 159781, 159789, 159796, 159803, 159810, 159817, 159824, 159831, 159836, 159842, 159849, 159856, 159862, 159869, 159876, 159882, 159888, 159895, 159902, 159909, 159916, 159923, 159930, 159937, 159943, 159949, 159956, 159962, 159969, 159976, 159982, 159988, 159994, 160000, 160006, 160012, 160017, 160023, 160030, 160037, 160043, 160050, 160057, 160063, 160069, 160076, 160083, 160090, 160097, 160104, 160111, 160118, 160124, 160130, 160137, 160143, 160150, 160157, 160163, 160169, 160175, 160181, 160187, 160193, 160197, 160202, 160208, 160214, 160219, 160225, 160231, 160236, 160241, 160247, 160253, 160259, 160265, 160271, 160277, 160283, 160288, 160293, 160299, 160304, 160310, 160316, 160321, 160326, 160331, 160336, 160341, 160346, 160352, 160359, 160367, 160375, 160382, 160390, 160398, 160405, 160412, 160420, 160428, 160436, 160444, 160452, 160460, 160468, 160475, 160482, 160490, 160497, 160505, 160513, 160520, 160527, 160534, 160541, 160548, 160555, 160560, 160566, 160573, 160580, 160586, 160593, 160600, 160606, 160612, 160619, 160626, 160633, 160640, 160647, 160654, 160661, 160667, 160673, 160680, 160686, 160693, 160700, 160706, 160712, 160718, 160724, 160730, 160736, 160741, 160747, 160754, 160761, 160767, 160774, 160781, 160787, 160793, 160800, 160807, 160814, 160821, 160828, 160835, 160842, 160848, 160854, 160861, 160867, 160874, 160881, 160887, 160893, 160899, 160905, 160911, 160917, 160922, 160928, 160935, 160942, 160948, 160955, 160962, 160968, 160974, 160981, 160988, 160995, 161002, 161009, 161016, 161023, 161029, 161035, 161042, 161048, 161055, 161062, 161068, 161074, 161080, 161086, 161092, 161098, 161103, 161109, 161116, 161123, 161129, 161136, 161143, 161149, 161155, 161162, 161169, 161176, 161183, 161190, 161197, 161204, 161210, 161216, 161223, 161229, 161236, 161243, 161249, 161255, 161261, 161267, 161273, 161279, 161284, 161290, 161297, 161304, 161310, 161317, 161324, 161330, 161336, 161343, 161350, 161357, 161364, 161371, 161378, 161385, 161391, 161397, 161404, 161410, 161417, 161424, 161430, 161436, 161442, 161448, 161454, 161460, 161464, 161469, 161475, 161481, 161486, 161492, 161498, 161503, 161508, 161514, 161520, 161526, 161532, 161538, 161544, 161550, 161555, 161560, 161566, 161571, 161577, 161583, 161588, 161593, 161598, 161603, 161608, 161613, 161616, 161620, 161625, 161630, 161634, 161639, 161644, 161648, 161652, 161657, 161662, 161667, 161672, 161677, 161682, 161687, 161691, 161695, 161700, 161704, 161709, 161714, 161718, 161722, 161726, 161730, 161734, 161738, 161742, 161747, 161753, 161759, 161764, 161770, 161776, 161781, 161786, 161792, 161798, 161804, 161810, 161816, 161822, 161828, 161833, 161838, 161844, 161849, 161855, 161861, 161866, 161871, 161876, 161881, 161886, 161891, 161895, 161900, 161906, 161912, 161917, 161923, 161929, 161934, 161939, 161945, 161951, 161957, 161963, 161969, 161975, 161981, 161986, 161991, 161997, 162002, 162008, 162014, 162019, 162024, 162029, 162034, 162039, 162044, 162049, 162055, 162062, 162069, 162075, 162082, 162089, 162095, 162101, 162108, 162115, 162122, 162129, 162136, 162143, 162150, 162156, 162162, 162169, 162175, 162182, 162189, 162195, 162201, 162207, 162213, 162219, 162225, 162229, 162234, 162240, 162246, 162251, 162257, 162263, 162268, 162273, 162279, 162285, 162291, 162297, 162303, 162309, 162315, 162320, 162325, 162331, 162336, 162342, 162348, 162353, 162358, 162363, 162368, 162373, 162378, 162381, 162385, 162390, 162395, 162399, 162404, 162409, 162413, 162417, 162422, 162427, 162432, 162437, 162442, 162447, 162452, 162456, 162460, 162465, 162469, 162474, 162479, 162483, 162487, 162491, 162495, 162499, 162503, 162508, 162514, 162521, 162528, 162534, 162541, 162548, 162554, 162560, 162567, 162574, 162581, 162588, 162595, 162602, 162609, 162615, 162621, 162628, 162634, 162641, 162648, 162654, 162660, 162666, 162672, 162678, 162684, 162688, 162693, 162699, 162705, 162710, 162716, 162722, 162727, 162732, 162738, 162744, 162750, 162756, 162762, 162768, 162774, 162779, 162784, 162790, 162795, 162801, 162807, 162812, 162817, 162822, 162827, 162832, 162837, 162840, 162844, 162849, 162854, 162858, 162863, 162868, 162872, 162876, 162881, 162886, 162891, 162896, 162901, 162906, 162911, 162915, 162919, 162924, 162928, 162933, 162938, 162942, 162946, 162950, 162954, 162958, 162962, 162966, 162971, 162977, 162983, 162988, 162994, 163000, 163005, 163010, 163016, 163022, 163028, 163034, 163040, 163046, 163052, 163057, 163062, 163068, 163073, 163079, 163085, 163090, 163095, 163100, 163105, 163110, 163115, 163120, 163126, 163133, 163140, 163146, 163153, 163160, 163166, 163172, 163179, 163186, 163193, 163200, 163207, 163214, 163221, 163227, 163233, 163240, 163246, 163253, 163260, 163266, 163272, 163278, 163284, 163290, 163296, 163300, 163305, 163311, 163317, 163322, 163328, 163334, 163339, 163344, 163350, 163356, 163362, 163368, 163374, 163380, 163386, 163391, 163396, 163402, 163407, 163413, 163419, 163424, 163429, 163434, 163439, 163444, 163449, 163453, 163458, 163464, 163470, 163475, 163481, 163487, 163492, 163497, 163503, 163509, 163515, 163521, 163527, 163533, 163539, 163544, 163549, 163555, 163560, 163566, 163572, 163577, 163582, 163587, 163592, 163597, 163602, 163605, 163609, 163614, 163619, 163623, 163628, 163633, 163637, 163641, 163646, 163651, 163656, 163661, 163666, 163671, 163676, 163680, 163684, 163689, 163693, 163698, 163703, 163707, 163711, 163715, 163719, 163723, 163727, 163732, 163738, 163745, 163752, 163758, 163765, 163772, 163778, 163784, 163791, 163798, 163805, 163812, 163819, 163826, 163833, 163839, 163845, 163852, 163858, 163865, 163872, 163878, 163884, 163890, 163896, 163902, 163908, 163912, 163917, 163923, 163929, 163934, 163940, 163946, 163951, 163956, 163962, 163968, 163974, 163980, 163986, 163992, 163998, 164003, 164008, 164014, 164019, 164025, 164031, 164036, 164041, 164046, 164051, 164056, 164061, 164065, 164070, 164076, 164082, 164087, 164093, 164099, 164104, 164109, 164115, 164121, 164127, 164133, 164139, 164145, 164151, 164156, 164161, 164167, 164172, 164178, 164184, 164189, 164194, 164199, 164204, 164209, 164214, 164218, 164223, 164229, 164235, 164240, 164246, 164252, 164257, 164262, 164268, 164274, 164280, 164286, 164292, 164298, 164304, 164309, 164314, 164320, 164325, 164331, 164337, 164342, 164347, 164352, 164357, 164362, 164367, 164371, 164376, 164382, 164388, 164393, 164399, 164405, 164410, 164415, 164421, 164427, 164433, 164439, 164445, 164451, 164457, 164462, 164467, 164473, 164478, 164484, 164490, 164495, 164500, 164505, 164510, 164515, 164520, 164524, 164529, 164535, 164541, 164546, 164552, 164558, 164563, 164568, 164574, 164580, 164586, 164592, 164598, 164604, 164610, 164615, 164620, 164626, 164631, 164637, 164643, 164648, 164653, 164658, 164663, 164668, 164673, 164676, 164680, 164685, 164690, 164694, 164699, 164704, 164708, 164712, 164717, 164722, 164727, 164732, 164737, 164742, 164747, 164751, 164755, 164760, 164764, 164769, 164774, 164778, 164782, 164786, 164790, 164794, 164798, 164802, 164807, 164813, 164819, 164824, 164830, 164836, 164841, 164846, 164852, 164858, 164864, 164870, 164876, 164882, 164888, 164893, 164898, 164904, 164909, 164915, 164921, 164926, 164931, 164936, 164941, 164946, 164951, 164956, 164962, 164969, 164976, 164982, 164989, 164996, 165002, 165008, 165015, 165022, 165029, 165036, 165043, 165050, 165057, 165063, 165069, 165076, 165082, 165089, 165096, 165102, 165108, 165114, 165120, 165126, 165132, 165137, 165143, 165150, 165157, 165163, 165170, 165177, 165183, 165189, 165196, 165203, 165210, 165217, 165224, 165231, 165238, 165244, 165250, 165257, 165263, 165270, 165277, 165283, 165289, 165295, 165301, 165307, 165313, 165319, 165326, 165334, 165342, 165349, 165357, 165365, 165372, 165379, 165387, 165395, 165403, 165411, 165419, 165427, 165435, 165442, 165449, 165457, 165464, 165472, 165480, 165487, 165494, 165501, 165508, 165515, 165522, 165527, 165533, 165540, 165547, 165553, 165560, 165567, 165573, 165579, 165586, 165593, 165600, 165607, 165614, 165621, 165628, 165634, 165640, 165647, 165653, 165660, 165667, 165673, 165679, 165685, 165691, 165697, 165703, 165707, 165712, 165718, 165724, 165729, 165735, 165741, 165746, 165751, 165757, 165763, 165769, 165775, 165781, 165787, 165793, 165798, 165803, 165809, 165814, 165820, 165826, 165831, 165836, 165841, 165846, 165851, 165856, 165862, 165869, 165877, 165885, 165892, 165900, 165908, 165915, 165922, 165930, 165938, 165946, 165954, 165962, 165970, 165978, 165985, 165992, 166000, 166007, 166015, 166023, 166030, 166037, 166044, 166051, 166058, 166065, 166070, 166076, 166083, 166090, 166096, 166103, 166110, 166116, 166122, 166129, 166136, 166143, 166150, 166157, 166164, 166171, 166177, 166183, 166190, 166196, 166203, 166210, 166216, 166222, 166228, 166234, 166240, 166246, 166250, 166255, 166261, 166267, 166272, 166278, 166284, 166289, 166294, 166300, 166306, 166312, 166318, 166324, 166330, 166336, 166341, 166346, 166352, 166357, 166363, 166369, 166374, 166379, 166384, 166389, 166394, 166399, 166404, 166410, 166417, 166424, 166430, 166437, 166444, 166450, 166456, 166463, 166470, 166477, 166484, 166491, 166498, 166505, 166511, 166517, 166524, 166530, 166537, 166544, 166550, 166556, 166562, 166568, 166574, 166580, 166586, 166593, 166601, 166609, 166616, 166624, 166632, 166639, 166646, 166654, 166662, 166670, 166678, 166686, 166694, 166702, 166709, 166716, 166724, 166731, 166739, 166747, 166754, 166761, 166768, 166775, 166782, 166789, 166794, 166800, 166807, 166814, 166820, 166827, 166834, 166840, 166846, 166853, 166860, 166867, 166874, 166881, 166888, 166895, 166901, 166907, 166914, 166920, 166927, 166934, 166940, 166946, 166952, 166958, 166964, 166970, 166975, 166981, 166988, 166995, 167001, 167008, 167015, 167021, 167027, 167034, 167041, 167048, 167055, 167062, 167069, 167076, 167082, 167088, 167095, 167101, 167108, 167115, 167121, 167127, 167133, 167139, 167145, 167151, 167155, 167160, 167166, 167172, 167177, 167183, 167189, 167194, 167199, 167205, 167211, 167217, 167223, 167229, 167235, 167241, 167246, 167251, 167257, 167262, 167268, 167274, 167279, 167284, 167289, 167294, 167299, 167304, 167310, 167317, 167325, 167333, 167340, 167348, 167356, 167363, 167370, 167378, 167386, 167394, 167402, 167410, 167418, 167426, 167433, 167440, 167448, 167455, 167463, 167471, 167478, 167485, 167492, 167499, 167506, 167513, 167518, 167524, 167531, 167538, 167544, 167551, 167558, 167564, 167570, 167577, 167584, 167591, 167598, 167605, 167612, 167619, 167625, 167631, 167638, 167644, 167651, 167658, 167664, 167670, 167676, 167682, 167688, 167694, 167699, 167705, 167712, 167719, 167725, 167732, 167739, 167745, 167751, 167758, 167765, 167772, 167779, 167786, 167793, 167800, 167806, 167812, 167819, 167825, 167832, 167839, 167845, 167851, 167857, 167863, 167869, 167875, 167880, 167886, 167893, 167900, 167906, 167913, 167920, 167926, 167932, 167939, 167946, 167953, 167960, 167967, 167974, 167981, 167987, 167993, 168000, 168006, 168013, 168020, 168026, 168032, 168038, 168044, 168050, 168056, 168061, 168067, 168074, 168081, 168087, 168094, 168101, 168107, 168113, 168120, 168127, 168134, 168141, 168148, 168155, 168162, 168168, 168174, 168181, 168187, 168194, 168201, 168207, 168213, 168219, 168225, 168231, 168237, 168242, 168248, 168255, 168262, 168268, 168275, 168282, 168288, 168294, 168301, 168308, 168315, 168322, 168329, 168336, 168343, 168349, 168355, 168362, 168368, 168375, 168382, 168388, 168394, 168400, 168406, 168412, 168418, 168422, 168427, 168433, 168439, 168444, 168450, 168456, 168461, 168466, 168472, 168478, 168484, 168490, 168496, 168502, 168508, 168513, 168518, 168524, 168529, 168535, 168541, 168546, 168551, 168556, 168561, 168566, 168571, 168573, 168576, 168580, 168584, 168587, 168591, 168595, 168598, 168601, 168605, 168609, 168613, 168617, 168621, 168625, 168629, 168632, 168635, 168639, 168642, 168646, 168650, 168653, 168656, 168659, 168662, 168665, 168668, 168671, 168675, 168680, 168685, 168689, 168694, 168699, 168703, 168707, 168712, 168717, 168722, 168727, 168732, 168737, 168742, 168746, 168750, 168755, 168759, 168764, 168769, 168773, 168777, 168781, 168785, 168789, 168793, 168796, 168800, 168805, 168810, 168814, 168819, 168824, 168828, 168832, 168837, 168842, 168847, 168852, 168857, 168862, 168867, 168871, 168875, 168880, 168884, 168889, 168894, 168898, 168902, 168906, 168910, 168914, 168918, 168922, 168927, 168933, 168939, 168944, 168950, 168956, 168961, 168966, 168972, 168978, 168984, 168990, 168996, 169002, 169008, 169013, 169018, 169024, 169029, 169035, 169041, 169046, 169051, 169056, 169061, 169066, 169071, 169074, 169078, 169083, 169088, 169092, 169097, 169102, 169106, 169110, 169115, 169120, 169125, 169130, 169135, 169140, 169145, 169149, 169153, 169158, 169162, 169167, 169172, 169176, 169180, 169184, 169188, 169192, 169196, 169198, 169201, 169205, 169209, 169212, 169216, 169220, 169223, 169226, 169230, 169234, 169238, 169242, 169246, 169250, 169254, 169257, 169260, 169264, 169267, 169271, 169275, 169278, 169281, 169284, 169287, 169290, 169293, 169297, 169302, 169308, 169314, 169319, 169325, 169331, 169336, 169341, 169347, 169353, 169359, 169365, 169371, 169377, 169383, 169388, 169393, 169399, 169404, 169410, 169416, 169421, 169426, 169431, 169436, 169441, 169446, 169449, 169453, 169458, 169463, 169467, 169472, 169477, 169481, 169485, 169490, 169495, 169500, 169505, 169510, 169515, 169520, 169524, 169528, 169533, 169537, 169542, 169547, 169551, 169555, 169559, 169563, 169567, 169571, 169573, 169576, 169580, 169584, 169587, 169591, 169595, 169598, 169601, 169605, 169609, 169613, 169617, 169621, 169625, 169629, 169632, 169635, 169639, 169642, 169646, 169650, 169653, 169656, 169659, 169662, 169665, 169668, 169671, 169675, 169680, 169685, 169689, 169694, 169699, 169703, 169707, 169712, 169717, 169722, 169727, 169732, 169737, 169742, 169746, 169750, 169755, 169759, 169764, 169769, 169773, 169777, 169781, 169785, 169789, 169793, 169797, 169802, 169808, 169814, 169819, 169825, 169831, 169836, 169841, 169847, 169853, 169859, 169865, 169871, 169877, 169883, 169888, 169893, 169899, 169904, 169910, 169916, 169921, 169926, 169931, 169936, 169941, 169946, 169949, 169953, 169958, 169963, 169967, 169972, 169977, 169981, 169985, 169990, 169995, 170000, 170005, 170010, 170015, 170020, 170024, 170028, 170033, 170037, 170042, 170047, 170051, 170055, 170059, 170063, 170067, 170071, 170074, 170078, 170083, 170088, 170092, 170097, 170102, 170106, 170110, 170115, 170120, 170125, 170130, 170135, 170140, 170145, 170149, 170153, 170158, 170162, 170167, 170172, 170176, 170180, 170184, 170188, 170192, 170196, 170198, 170201, 170205, 170209, 170212, 170216, 170220, 170223, 170226, 170230, 170234, 170238, 170242, 170246, 170250, 170254, 170257, 170260, 170264, 170267, 170271, 170275, 170278, 170281, 170284, 170287, 170290, 170293, 170297, 170302, 170308, 170314, 170319, 170325, 170331, 170336, 170341, 170347, 170353, 170359, 170365, 170371, 170377, 170383, 170388, 170393, 170399, 170404, 170410, 170416, 170421, 170426, 170431, 170436, 170441, 170446, 170449, 170453, 170458, 170463, 170467, 170472, 170477, 170481, 170485, 170490, 170495, 170500, 170505, 170510, 170515, 170520, 170524, 170528, 170533, 170537, 170542, 170547, 170551, 170555, 170559, 170563, 170567, 170571, 170574, 170578, 170583, 170588, 170592, 170597, 170602, 170606, 170610, 170615, 170620, 170625, 170630, 170635, 170640, 170645, 170649, 170653, 170658, 170662, 170667, 170672, 170676, 170680, 170684, 170688, 170692, 170696, 170699, 170703, 170708, 170713, 170717, 170722, 170727, 170731, 170735, 170740, 170745, 170750, 170755, 170760, 170765, 170770, 170774, 170778, 170783, 170787, 170792, 170797, 170801, 170805, 170809, 170813, 170817, 170821, 170824, 170828, 170833, 170838, 170842, 170847, 170852, 170856, 170860, 170865, 170870, 170875, 170880, 170885, 170890, 170895, 170899, 170903, 170908, 170912, 170917, 170922, 170926, 170930, 170934, 170938, 170942, 170946, 170949, 170953, 170958, 170963, 170967, 170972, 170977, 170981, 170985, 170990, 170995, 171000, 171005, 171010, 171015, 171020, 171024, 171028, 171033, 171037, 171042, 171047, 171051, 171055, 171059, 171063, 171067, 171071, 171073, 171076, 171080, 171084, 171087, 171091, 171095, 171098, 171101, 171105, 171109, 171113, 171117, 171121, 171125, 171129, 171132, 171135, 171139, 171142, 171146, 171150, 171153, 171156, 171159, 171162, 171165, 171168, 171171, 171175, 171180, 171185, 171189, 171194, 171199, 171203, 171207, 171212, 171217, 171222, 171227, 171232, 171237, 171242, 171246, 171250, 171255, 171259, 171264, 171269, 171273, 171277, 171281, 171285, 171289, 171293, 171297, 171302, 171308, 171314, 171319, 171325, 171331, 171336, 171341, 171347, 171353, 171359, 171365, 171371, 171377, 171383, 171388, 171393, 171399, 171404, 171410, 171416, 171421, 171426, 171431, 171436, 171441, 171446, 171450, 171455, 171461, 171467, 171472, 171478, 171484, 171489, 171494, 171500, 171506, 171512, 171518, 171524, 171530, 171536, 171541, 171546, 171552, 171557, 171563, 171569, 171574, 171579, 171584, 171589, 171594, 171599, 171604, 171610, 171617, 171624, 171630, 171637, 171644, 171650, 171656, 171663, 171670, 171677, 171684, 171691, 171698, 171705, 171711, 171717, 171724, 171730, 171737, 171744, 171750, 171756, 171762, 171768, 171774, 171780, 171784, 171789, 171795, 171801, 171806, 171812, 171818, 171823, 171828, 171834, 171840, 171846, 171852, 171858, 171864, 171870, 171875, 171880, 171886, 171891, 171897, 171903, 171908, 171913, 171918, 171923, 171928, 171933, 171936, 171940, 171945, 171950, 171954, 171959, 171964, 171968, 171972, 171977, 171982, 171987, 171992, 171997, 172002, 172007, 172011, 172015, 172020, 172024, 172029, 172034, 172038, 172042, 172046, 172050, 172054, 172058, 172063, 172069, 172076, 172083, 172089, 172096, 172103, 172109, 172115, 172122, 172129, 172136, 172143, 172150, 172157, 172164, 172170, 172176, 172183, 172189, 172196, 172203, 172209, 172215, 172221, 172227, 172233, 172239, 172243, 172248, 172254, 172260, 172265, 172271, 172277, 172282, 172287, 172293, 172299, 172305, 172311, 172317, 172323, 172329, 172334, 172339, 172345, 172350, 172356, 172362, 172367, 172372, 172377, 172382, 172387, 172392, 172395, 172399, 172404, 172409, 172413, 172418, 172423, 172427, 172431, 172436, 172441, 172446, 172451, 172456, 172461, 172466, 172470, 172474, 172479, 172483, 172488, 172493, 172497, 172501, 172505, 172509, 172513, 172517, 172521, 172526, 172532, 172538, 172543, 172549, 172555, 172560, 172565, 172571, 172577, 172583, 172589, 172595, 172601, 172607, 172612, 172617, 172623, 172628, 172634, 172640, 172645, 172650, 172655, 172660, 172665, 172670, 172675, 172681, 172688, 172695, 172701, 172708, 172715, 172721, 172727, 172734, 172741, 172748, 172755, 172762, 172769, 172776, 172782, 172788, 172795, 172801, 172808, 172815, 172821, 172827, 172833, 172839, 172845, 172851, 172855, 172860, 172866, 172872, 172877, 172883, 172889, 172894, 172899, 172905, 172911, 172917, 172923, 172929, 172935, 172941, 172946, 172951, 172957, 172962, 172968, 172974, 172979, 172984, 172989, 172994, 172999, 173004, 173008, 173013, 173019, 173025, 173030, 173036, 173042, 173047, 173052, 173058, 173064, 173070, 173076, 173082, 173088, 173094, 173099, 173104, 173110, 173115, 173121, 173127, 173132, 173137, 173142, 173147, 173152, 173157, 173160, 173164, 173169, 173174, 173178, 173183, 173188, 173192, 173196, 173201, 173206, 173211, 173216, 173221, 173226, 173231, 173235, 173239, 173244, 173248, 173253, 173258, 173262, 173266, 173270, 173274, 173278, 173282, 173287, 173293, 173300, 173307, 173313, 173320, 173327, 173333, 173339, 173346, 173353, 173360, 173367, 173374, 173381, 173388, 173394, 173400, 173407, 173413, 173420, 173427, 173433, 173439, 173445, 173451, 173457, 173463, 173467, 173472, 173478, 173484, 173489, 173495, 173501, 173506, 173511, 173517, 173523, 173529, 173535, 173541, 173547, 173553, 173558, 173563, 173569, 173574, 173580, 173586, 173591, 173596, 173601, 173606, 173611, 173616, 173620, 173625, 173631, 173637, 173642, 173648, 173654, 173659, 173664, 173670, 173676, 173682, 173688, 173694, 173700, 173706, 173711, 173716, 173722, 173727, 173733, 173739, 173744, 173749, 173754, 173759, 173764, 173769, 173773, 173778, 173784, 173790, 173795, 173801, 173807, 173812, 173817, 173823, 173829, 173835, 173841, 173847, 173853, 173859, 173864, 173869, 173875, 173880, 173886, 173892, 173897, 173902, 173907, 173912, 173917, 173922, 173926, 173931, 173937, 173943, 173948, 173954, 173960, 173965, 173970, 173976, 173982, 173988, 173994, 174000, 174006, 174012, 174017, 174022, 174028, 174033, 174039, 174045, 174050, 174055, 174060, 174065, 174070, 174075, 174079, 174084, 174090, 174096, 174101, 174107, 174113, 174118, 174123, 174129, 174135, 174141, 174147, 174153, 174159, 174165, 174170, 174175, 174181, 174186, 174192, 174198, 174203, 174208, 174213, 174218, 174223, 174228, 174231, 174235, 174240, 174245, 174249, 174254, 174259, 174263, 174267, 174272, 174277, 174282, 174287, 174292, 174297, 174302, 174306, 174310, 174315, 174319, 174324, 174329, 174333, 174337, 174341, 174345, 174349, 174353, 174357, 174362, 174368, 174374, 174379, 174385, 174391, 174396, 174401, 174407, 174413, 174419, 174425, 174431, 174437, 174443, 174448, 174453, 174459, 174464, 174470, 174476, 174481, 174486, 174491, 174496, 174501, 174506, 174511, 174517, 174524, 174531, 174537, 174544, 174551, 174557, 174563, 174570, 174577, 174584, 174591, 174598, 174605, 174612, 174618, 174624, 174631, 174637, 174644, 174651, 174657, 174663, 174669, 174675, 174681, 174687, 174692, 174698, 174705, 174712, 174718, 174725, 174732, 174738, 174744, 174751, 174758, 174765, 174772, 174779, 174786, 174793, 174799, 174805, 174812, 174818, 174825, 174832, 174838, 174844, 174850, 174856, 174862, 174868, 174874, 174881, 174889, 174897, 174904, 174912, 174920, 174927, 174934, 174942, 174950, 174958, 174966, 174974, 174982, 174990, 174997, 175004, 175012, 175019, 175027, 175035, 175042, 175049, 175056, 175063, 175070, 175077, 175082, 175088, 175095, 175102, 175108, 175115, 175122, 175128, 175134, 175141, 175148, 175155, 175162, 175169, 175176, 175183, 175189, 175195, 175202, 175208, 175215, 175222, 175228, 175234, 175240, 175246, 175252, 175258, 175262, 175267, 175273, 175279, 175284, 175290, 175296, 175301, 175306, 175312, 175318, 175324, 175330, 175336, 175342, 175348, 175353, 175358, 175364, 175369, 175375, 175381, 175386, 175391, 175396, 175401, 175406, 175411, 175417, 175424, 175432, 175440, 175447, 175455, 175463, 175470, 175477, 175485, 175493, 175501, 175509, 175517, 175525, 175533, 175540, 175547, 175555, 175562, 175570, 175578, 175585, 175592, 175599, 175606, 175613, 175620, 175625, 175631, 175638, 175645, 175651, 175658, 175665, 175671, 175677, 175684, 175691, 175698, 175705, 175712, 175719, 175726, 175732, 175738, 175745, 175751, 175758, 175765, 175771, 175777, 175783, 175789, 175795, 175801, 175805, 175810, 175816, 175822, 175827, 175833, 175839, 175844, 175849, 175855, 175861, 175867, 175873, 175879, 175885, 175891, 175896, 175901, 175907, 175912, 175918, 175924, 175929, 175934, 175939, 175944, 175949, 175954, 175959, 175965, 175972, 175979, 175985, 175992, 175999, 176005, 176011, 176018, 176025, 176032, 176039, 176046, 176053, 176060, 176066, 176072, 176079, 176085, 176092, 176099, 176105, 176111, 176117, 176123, 176129, 176135, 176141, 176148, 176156, 176164, 176171, 176179, 176187, 176194, 176201, 176209, 176217, 176225, 176233, 176241, 176249, 176257, 176264, 176271, 176279, 176286, 176294, 176302, 176309, 176316, 176323, 176330, 176337, 176344, 176349, 176355, 176362, 176369, 176375, 176382, 176389, 176395, 176401, 176408, 176415, 176422, 176429, 176436, 176443, 176450, 176456, 176462, 176469, 176475, 176482, 176489, 176495, 176501, 176507, 176513, 176519, 176525, 176530, 176536, 176543, 176550, 176556, 176563, 176570, 176576, 176582, 176589, 176596, 176603, 176610, 176617, 176624, 176631, 176637, 176643, 176650, 176656, 176663, 176670, 176676, 176682, 176688, 176694, 176700, 176706, 176710, 176715, 176721, 176727, 176732, 176738, 176744, 176749, 176754, 176760, 176766, 176772, 176778, 176784, 176790, 176796, 176801, 176806, 176812, 176817, 176823, 176829, 176834, 176839, 176844, 176849, 176854, 176859, 176865, 176872, 176880, 176888, 176895, 176903, 176911, 176918, 176925, 176933, 176941, 176949, 176957, 176965, 176973, 176981, 176988, 176995, 177003, 177010, 177018, 177026, 177033, 177040, 177047, 177054, 177061, 177068, 177073, 177079, 177086, 177093, 177099, 177106, 177113, 177119, 177125, 177132, 177139, 177146, 177153, 177160, 177167, 177174, 177180, 177186, 177193, 177199, 177206, 177213, 177219, 177225, 177231, 177237, 177243, 177249, 177254, 177260, 177267, 177274, 177280, 177287, 177294, 177300, 177306, 177313, 177320, 177327, 177334, 177341, 177348, 177355, 177361, 177367, 177374, 177380, 177387, 177394, 177400, 177406, 177412, 177418, 177424, 177430, 177435, 177441, 177448, 177455, 177461, 177468, 177475, 177481, 177487, 177494, 177501, 177508, 177515, 177522, 177529, 177536, 177542, 177548, 177555, 177561, 177568, 177575, 177581, 177587, 177593, 177599, 177605, 177611, 177616, 177622, 177629, 177636, 177642, 177649, 177656, 177662, 177668, 177675, 177682, 177689, 177696, 177703, 177710, 177717, 177723, 177729, 177736, 177742, 177749, 177756, 177762, 177768, 177774, 177780, 177786, 177792, 177797, 177803, 177810, 177817, 177823, 177830, 177837, 177843, 177849, 177856, 177863, 177870, 177877, 177884, 177891, 177898, 177904, 177910, 177917, 177923, 177930, 177937, 177943, 177949, 177955, 177961, 177967, 177973, 177977, 177982, 177988, 177994, 177999, 178005, 178011, 178016, 178021, 178027, 178033, 178039, 178045, 178051, 178057, 178063, 178068, 178073, 178079, 178084, 178090, 178096, 178101, 178106, 178111, 178116, 178121, 178126, 178129, 178133, 178138, 178143, 178147, 178152, 178157, 178161, 178165, 178170, 178175, 178180, 178185, 178190, 178195, 178200, 178204, 178208, 178213, 178217, 178222, 178227, 178231, 178235, 178239, 178243, 178247, 178251, 178255, 178260, 178266, 178272, 178277, 178283, 178289, 178294, 178299, 178305, 178311, 178317, 178323, 178329, 178335, 178341, 178346, 178351, 178357, 178362, 178368, 178374, 178379, 178384, 178389, 178394, 178399, 178404, 178408, 178413, 178419, 178425, 178430, 178436, 178442, 178447, 178452, 178458, 178464, 178470, 178476, 178482, 178488, 178494, 178499, 178504, 178510, 178515, 178521, 178527, 178532, 178537, 178542, 178547, 178552, 178557, 178562, 178568, 178575, 178582, 178588, 178595, 178602, 178608, 178614, 178621, 178628, 178635, 178642, 178649, 178656, 178663, 178669, 178675, 178682, 178688, 178695, 178702, 178708, 178714, 178720, 178726, 178732, 178738, 178742, 178747, 178753, 178759, 178764, 178770, 178776, 178781, 178786, 178792, 178798, 178804, 178810, 178816, 178822, 178828, 178833, 178838, 178844, 178849, 178855, 178861, 178866, 178871, 178876, 178881, 178886, 178891, 178894, 178898, 178903, 178908, 178912, 178917, 178922, 178926, 178930, 178935, 178940, 178945, 178950, 178955, 178960, 178965, 178969, 178973, 178978, 178982, 178987, 178992, 178996, 179000, 179004, 179008, 179012, 179016, 179021, 179027, 179034, 179041, 179047, 179054, 179061, 179067, 179073, 179080, 179087, 179094, 179101, 179108, 179115, 179122, 179128, 179134, 179141, 179147, 179154, 179161, 179167, 179173, 179179, 179185, 179191, 179197, 179201, 179206, 179212, 179218, 179223, 179229, 179235, 179240, 179245, 179251, 179257, 179263, 179269, 179275, 179281, 179287, 179292, 179297, 179303, 179308, 179314, 179320, 179325, 179330, 179335, 179340, 179345, 179350, 179353, 179357, 179362, 179367, 179371, 179376, 179381, 179385, 179389, 179394, 179399, 179404, 179409, 179414, 179419, 179424, 179428, 179432, 179437, 179441, 179446, 179451, 179455, 179459, 179463, 179467, 179471, 179475, 179479, 179484, 179490, 179496, 179501, 179507, 179513, 179518, 179523, 179529, 179535, 179541, 179547, 179553, 179559, 179565, 179570, 179575, 179581, 179586, 179592, 179598, 179603, 179608, 179613, 179618, 179623, 179628, 179633, 179639, 179646, 179653, 179659, 179666, 179673, 179679, 179685, 179692, 179699, 179706, 179713, 179720, 179727, 179734, 179740, 179746, 179753, 179759, 179766, 179773, 179779, 179785, 179791, 179797, 179803, 179809, 179813, 179818, 179824, 179830, 179835, 179841, 179847, 179852, 179857, 179863, 179869, 179875, 179881, 179887, 179893, 179899, 179904, 179909, 179915, 179920, 179926, 179932, 179937, 179942, 179947, 179952, 179957, 179962, 179966, 179971, 179977, 179983, 179988, 179994, 180000, 180005, 180010, 180016, 180022, 180028, 180034, 180040, 180046, 180052, 180057, 180062, 180068, 180073, 180079, 180085, 180090, 180095, 180100, 180105, 180110, 180115, 180118, 180122, 180127, 180132, 180136, 180141, 180146, 180150, 180154, 180159, 180164, 180169, 180174, 180179, 180184, 180189, 180193, 180197, 180202, 180206, 180211, 180216, 180220, 180224, 180228, 180232, 180236, 180240, 180245, 180251, 180258, 180265, 180271, 180278, 180285, 180291, 180297, 180304, 180311, 180318, 180325, 180332, 180339, 180346, 180352, 180358, 180365, 180371, 180378, 180385, 180391, 180397, 180403, 180409, 180415, 180421, 180425, 180430, 180436, 180442, 180447, 180453, 180459, 180464, 180469, 180475, 180481, 180487, 180493, 180499, 180505, 180511, 180516, 180521, 180527, 180532, 180538, 180544, 180549, 180554, 180559, 180564, 180569, 180574, 180578, 180583, 180589, 180595, 180600, 180606, 180612, 180617, 180622, 180628, 180634, 180640, 180646, 180652, 180658, 180664, 180669, 180674, 180680, 180685, 180691, 180697, 180702, 180707, 180712, 180717, 180722, 180727, 180731, 180736, 180742, 180748, 180753, 180759, 180765, 180770, 180775, 180781, 180787, 180793, 180799, 180805, 180811, 180817, 180822, 180827, 180833, 180838, 180844, 180850, 180855, 180860, 180865, 180870, 180875, 180880, 180884, 180889, 180895, 180901, 180906, 180912, 180918, 180923, 180928, 180934, 180940, 180946, 180952, 180958, 180964, 180970, 180975, 180980, 180986, 180991, 180997, 181003, 181008, 181013, 181018, 181023, 181028, 181033, 181037, 181042, 181048, 181054, 181059, 181065, 181071, 181076, 181081, 181087, 181093, 181099, 181105, 181111, 181117, 181123, 181128, 181133, 181139, 181144, 181150, 181156, 181161, 181166, 181171, 181176, 181181, 181186, 181189, 181193, 181198, 181203, 181207, 181212, 181217, 181221, 181225, 181230, 181235, 181240, 181245, 181250, 181255, 181260, 181264, 181268, 181273, 181277, 181282, 181287, 181291, 181295, 181299, 181303, 181307, 181311, 181314, 181318, 181323, 181328, 181332, 181337, 181342, 181346, 181350, 181355, 181360, 181365, 181370, 181375, 181380, 181385, 181389, 181393, 181398, 181402, 181407, 181412, 181416, 181420, 181424, 181428, 181432, 181436, 181440, 181445, 181451, 181457, 181462, 181468, 181474, 181479, 181484, 181490, 181496, 181502, 181508, 181514, 181520, 181526, 181531, 181536, 181542, 181547, 181553, 181559, 181564, 181569, 181574, 181579, 181584, 181589, 181593, 181598, 181604, 181610, 181615, 181621, 181627, 181632, 181637, 181643, 181649, 181655, 181661, 181667, 181673, 181679, 181684, 181689, 181695, 181700, 181706, 181712, 181717, 181722, 181727, 181732, 181737, 181742, 181747, 181753, 181760, 181767, 181773, 181780, 181787, 181793, 181799, 181806, 181813, 181820, 181827, 181834, 181841, 181848, 181854, 181860, 181867, 181873, 181880, 181887, 181893, 181899, 181905, 181911, 181917, 181923, 181927, 181932, 181938, 181944, 181949, 181955, 181961, 181966, 181971, 181977, 181983, 181989, 181995, 182001, 182007, 182013, 182018, 182023, 182029, 182034, 182040, 182046, 182051, 182056, 182061, 182066, 182071, 182076, 182079, 182083, 182088, 182093, 182097, 182102, 182107, 182111, 182115, 182120, 182125, 182130, 182135, 182140, 182145, 182150, 182154, 182158, 182163, 182167, 182172, 182177, 182181, 182185, 182189, 182193, 182197, 182201, 182206, 182212, 182219, 182226, 182232, 182239, 182246, 182252, 182258, 182265, 182272, 182279, 182286, 182293, 182300, 182307, 182313, 182319, 182326, 182332, 182339, 182346, 182352, 182358, 182364, 182370, 182376, 182382, 182386, 182391, 182397, 182403, 182408, 182414, 182420, 182425, 182430, 182436, 182442, 182448, 182454, 182460, 182466, 182472, 182477, 182482, 182488, 182493, 182499, 182505, 182510, 182515, 182520, 182525, 182530, 182535, 182538, 182542, 182547, 182552, 182556, 182561, 182566, 182570, 182574, 182579, 182584, 182589, 182594, 182599, 182604, 182609, 182613, 182617, 182622, 182626, 182631, 182636, 182640, 182644, 182648, 182652, 182656, 182660, 182664, 182669, 182675, 182681, 182686, 182692, 182698, 182703, 182708, 182714, 182720, 182726, 182732, 182738, 182744, 182750, 182755, 182760, 182766, 182771, 182777, 182783, 182788, 182793, 182798, 182803, 182808, 182813, 182818, 182824, 182831, 182838, 182844, 182851, 182858, 182864, 182870, 182877, 182884, 182891, 182898, 182905, 182912, 182919, 182925, 182931, 182938, 182944, 182951, 182958, 182964, 182970, 182976, 182982, 182988, 182994, 182998, 183003, 183009, 183015, 183020, 183026, 183032, 183037, 183042, 183048, 183054, 183060, 183066, 183072, 183078, 183084, 183089, 183094, 183100, 183105, 183111, 183117, 183122, 183127, 183132, 183137, 183142, 183147, 183151, 183156, 183162, 183168, 183173, 183179, 183185, 183190, 183195, 183201, 183207, 183213, 183219, 183225, 183231, 183237, 183242, 183247, 183253, 183258, 183264, 183270, 183275, 183280, 183285, 183290, 183295, 183300, 183303, 183307, 183312, 183317, 183321, 183326, 183331, 183335, 183339, 183344, 183349, 183354, 183359, 183364, 183369, 183374, 183378, 183382, 183387, 183391, 183396, 183401, 183405, 183409, 183413, 183417, 183421, 183425, 183430, 183436, 183443, 183450, 183456, 183463, 183470, 183476, 183482, 183489, 183496, 183503, 183510, 183517, 183524, 183531, 183537, 183543, 183550, 183556, 183563, 183570, 183576, 183582, 183588, 183594, 183600, 183606, 183610, 183615, 183621, 183627, 183632, 183638, 183644, 183649, 183654, 183660, 183666, 183672, 183678, 183684, 183690, 183696, 183701, 183706, 183712, 183717, 183723, 183729, 183734, 183739, 183744, 183749, 183754, 183759, 183763, 183768, 183774, 183780, 183785, 183791, 183797, 183802, 183807, 183813, 183819, 183825, 183831, 183837, 183843, 183849, 183854, 183859, 183865, 183870, 183876, 183882, 183887, 183892, 183897, 183902, 183907, 183912, 183916, 183921, 183927, 183933, 183938, 183944, 183950, 183955, 183960, 183966, 183972, 183978, 183984, 183990, 183996, 184002, 184007, 184012, 184018, 184023, 184029, 184035, 184040, 184045, 184050, 184055, 184060, 184065, 184069, 184074, 184080, 184086, 184091, 184097, 184103, 184108, 184113, 184119, 184125, 184131, 184137, 184143, 184149, 184155, 184160, 184165, 184171, 184176, 184182, 184188, 184193, 184198, 184203, 184208, 184213, 184218, 184222, 184227, 184233, 184239, 184244, 184250, 184256, 184261, 184266, 184272, 184278, 184284, 184290, 184296, 184302, 184308, 184313, 184318, 184324, 184329, 184335, 184341, 184346, 184351, 184356, 184361, 184366, 184371, 184374, 184378, 184383, 184388, 184392, 184397, 184402, 184406, 184410, 184415, 184420, 184425, 184430, 184435, 184440, 184445, 184449, 184453, 184458, 184462, 184467, 184472, 184476, 184480, 184484, 184488, 184492, 184496, 184499, 184503, 184508, 184513, 184517, 184522, 184527, 184531, 184535, 184540, 184545, 184550, 184555, 184560, 184565, 184570, 184574, 184578, 184583, 184587, 184592, 184597, 184601, 184605, 184609, 184613, 184617, 184621, 184625, 184630, 184636, 184642, 184647, 184653, 184659, 184664, 184669, 184675, 184681, 184687, 184693, 184699, 184705, 184711, 184716, 184721, 184727, 184732, 184738, 184744, 184749, 184754, 184759, 184764, 184769, 184774, 184778, 184783, 184789, 184795, 184800, 184806, 184812, 184817, 184822, 184828, 184834, 184840, 184846, 184852, 184858, 184864, 184869, 184874, 184880, 184885, 184891, 184897, 184902, 184907, 184912, 184917, 184922, 184927, 184932, 184938, 184945, 184952, 184958, 184965, 184972, 184978, 184984, 184991, 184998, 185005, 185012, 185019, 185026, 185033, 185039, 185045, 185052, 185058, 185065, 185072, 185078, 185084, 185090, 185096, 185102, 185108, 185112, 185117, 185123, 185129, 185134, 185140, 185146, 185151, 185156, 185162, 185168, 185174, 185180, 185186, 185192, 185198, 185203, 185208, 185214, 185219, 185225, 185231, 185236, 185241, 185246, 185251, 185256, 185261, 185264, 185268, 185273, 185278, 185282, 185287, 185292, 185296, 185300, 185305, 185310, 185315, 185320, 185325, 185330, 185335, 185339, 185343, 185348, 185352, 185357, 185362, 185366, 185370, 185374, 185378, 185382, 185386, 185391, 185397, 185404, 185411, 185417, 185424, 185431, 185437, 185443, 185450, 185457, 185464, 185471, 185478, 185485, 185492, 185498, 185504, 185511, 185517, 185524, 185531, 185537, 185543, 185549, 185555, 185561, 185567, 185571, 185576, 185582, 185588, 185593, 185599, 185605, 185610, 185615, 185621, 185627, 185633, 185639, 185645, 185651, 185657, 185662, 185667, 185673, 185678, 185684, 185690, 185695, 185700, 185705, 185710, 185715, 185720, 185723, 185727, 185732, 185737, 185741, 185746, 185751, 185755, 185759, 185764, 185769, 185774, 185779, 185784, 185789, 185794, 185798, 185802, 185807, 185811, 185816, 185821, 185825, 185829, 185833, 185837, 185841, 185845, 185849, 185854, 185860, 185866, 185871, 185877, 185883, 185888, 185893, 185899, 185905, 185911, 185917, 185923, 185929, 185935, 185940, 185945, 185951, 185956, 185962, 185968, 185973, 185978, 185983, 185988, 185993, 185998, 186003, 186009, 186016, 186023, 186029, 186036, 186043, 186049, 186055, 186062, 186069, 186076, 186083, 186090, 186097, 186104, 186110, 186116, 186123, 186129, 186136, 186143, 186149, 186155, 186161, 186167, 186173, 186179, 186183, 186188, 186194, 186200, 186205, 186211, 186217, 186222, 186227, 186233, 186239, 186245, 186251, 186257, 186263, 186269, 186274, 186279, 186285, 186290, 186296, 186302, 186307, 186312, 186317, 186322, 186327, 186332, 186336, 186341, 186347, 186353, 186358, 186364, 186370, 186375, 186380, 186386, 186392, 186398, 186404, 186410, 186416, 186422, 186427, 186432, 186438, 186443, 186449, 186455, 186460, 186465, 186470, 186475, 186480, 186485, 186488, 186492, 186497, 186502, 186506, 186511, 186516, 186520, 186524, 186529, 186534, 186539, 186544, 186549, 186554, 186559, 186563, 186567, 186572, 186576, 186581, 186586, 186590, 186594, 186598, 186602, 186606, 186610, 186615, 186621, 186628, 186635, 186641, 186648, 186655, 186661, 186667, 186674, 186681, 186688, 186695, 186702, 186709, 186716, 186722, 186728, 186735, 186741, 186748, 186755, 186761, 186767, 186773, 186779, 186785, 186791, 186795, 186800, 186806, 186812, 186817, 186823, 186829, 186834, 186839, 186845, 186851, 186857, 186863, 186869, 186875, 186881, 186886, 186891, 186897, 186902, 186908, 186914, 186919, 186924, 186929, 186934, 186939, 186944, 186948, 186953, 186959, 186965, 186970, 186976, 186982, 186987, 186992, 186998, 187004, 187010, 187016, 187022, 187028, 187034, 187039, 187044, 187050, 187055, 187061, 187067, 187072, 187077, 187082, 187087, 187092, 187097, 187101, 187106, 187112, 187118, 187123, 187129, 187135, 187140, 187145, 187151, 187157, 187163, 187169, 187175, 187181, 187187, 187192, 187197, 187203, 187208, 187214, 187220, 187225, 187230, 187235, 187240, 187245, 187250, 187254, 187259, 187265, 187271, 187276, 187282, 187288, 187293, 187298, 187304, 187310, 187316, 187322, 187328, 187334, 187340, 187345, 187350, 187356, 187361, 187367, 187373, 187378, 187383, 187388, 187393, 187398, 187403, 187407, 187412, 187418, 187424, 187429, 187435, 187441, 187446, 187451, 187457, 187463, 187469, 187475, 187481, 187487, 187493, 187498, 187503, 187509, 187514, 187520, 187526, 187531, 187536, 187541, 187546, 187551, 187556, 187559, 187563, 187568, 187573, 187577, 187582, 187587, 187591, 187595, 187600, 187605, 187610, 187615, 187620, 187625, 187630, 187634, 187638, 187643, 187647, 187652, 187657, 187661, 187665, 187669, 187673, 187677, 187681, 187684, 187688, 187693, 187698, 187702, 187707, 187712, 187716, 187720, 187725, 187730, 187735, 187740, 187745, 187750, 187755, 187759, 187763, 187768, 187772, 187777, 187782, 187786, 187790, 187794, 187798, 187802, 187806, 187810, 187815, 187821, 187827, 187832, 187838, 187844, 187849, 187854, 187860, 187866, 187872, 187878, 187884, 187890, 187896, 187901, 187906, 187912, 187917, 187923, 187929, 187934, 187939, 187944, 187949, 187954, 187959, 187963, 187968, 187974, 187980, 187985, 187991, 187997, 188002, 188007, 188013, 188019, 188025, 188031, 188037, 188043, 188049, 188054, 188059, 188065, 188070, 188076, 188082, 188087, 188092, 188097, 188102, 188107, 188112, 188117, 188123, 188130, 188137, 188143, 188150, 188157, 188163, 188169, 188176, 188183, 188190, 188197, 188204, 188211, 188218, 188224, 188230, 188237, 188243, 188250, 188257, 188263, 188269, 188275, 188281, 188287, 188293, 188297, 188302, 188308, 188314, 188319, 188325, 188331, 188336, 188341, 188347, 188353, 188359, 188365, 188371, 188377, 188383, 188388, 188393, 188399, 188404, 188410, 188416, 188421, 188426, 188431, 188436, 188441, 188446, 188449, 188453, 188458, 188463, 188467, 188472, 188477, 188481, 188485, 188490, 188495, 188500, 188505, 188510, 188515, 188520, 188524, 188528, 188533, 188537, 188542, 188547, 188551, 188555, 188559, 188563, 188567, 188571, 188576, 188582, 188589, 188596, 188602, 188609, 188616, 188622, 188628, 188635, 188642, 188649, 188656, 188663, 188670, 188677, 188683, 188689, 188696, 188702, 188709, 188716, 188722, 188728, 188734, 188740, 188746, 188752, 188756, 188761, 188767, 188773, 188778, 188784, 188790, 188795, 188800, 188806, 188812, 188818, 188824, 188830, 188836, 188842, 188847, 188852, 188858, 188863, 188869, 188875, 188880, 188885, 188890, 188895, 188900, 188905, 188908, 188912, 188917, 188922, 188926, 188931, 188936, 188940, 188944, 188949, 188954, 188959, 188964, 188969, 188974, 188979, 188983, 188987, 188992, 188996, 189001, 189006, 189010, 189014, 189018, 189022, 189026, 189030, 189034, 189039, 189045, 189051, 189056, 189062, 189068, 189073, 189078, 189084, 189090, 189096, 189102, 189108, 189114, 189120, 189125, 189130, 189136, 189141, 189147, 189153, 189158, 189163, 189168, 189173, 189178, 189183, 189188, 189194, 189201, 189208, 189214, 189221, 189228, 189234, 189240, 189247, 189254, 189261, 189268, 189275, 189282, 189289, 189295, 189301, 189308, 189314, 189321, 189328, 189334, 189340, 189346, 189352, 189358, 189364, 189368, 189373, 189379, 189385, 189390, 189396, 189402, 189407, 189412, 189418, 189424, 189430, 189436, 189442, 189448, 189454, 189459, 189464, 189470, 189475, 189481, 189487, 189492, 189497, 189502, 189507, 189512, 189517, 189521, 189526, 189532, 189538, 189543, 189549, 189555, 189560, 189565, 189571, 189577, 189583, 189589, 189595, 189601, 189607, 189612, 189617, 189623, 189628, 189634, 189640, 189645, 189650, 189655, 189660, 189665, 189670, 189673, 189677, 189682, 189687, 189691, 189696, 189701, 189705, 189709, 189714, 189719, 189724, 189729, 189734, 189739, 189744, 189748, 189752, 189757, 189761, 189766, 189771, 189775, 189779, 189783, 189787, 189791, 189795, 189800, 189806, 189813, 189820, 189826, 189833, 189840, 189846, 189852, 189859, 189866, 189873, 189880, 189887, 189894, 189901, 189907, 189913, 189920, 189926, 189933, 189940, 189946, 189952, 189958, 189964, 189970, 189976, 189980, 189985, 189991, 189997, 190002, 190008, 190014, 190019, 190024, 190030, 190036, 190042, 190048, 190054, 190060, 190066, 190071, 190076, 190082, 190087, 190093, 190099, 190104, 190109, 190114, 190119, 190124, 190129, 190133, 190138, 190144, 190150, 190155, 190161, 190167, 190172, 190177, 190183, 190189, 190195, 190201, 190207, 190213, 190219, 190224, 190229, 190235, 190240, 190246, 190252, 190257, 190262, 190267, 190272, 190277, 190282, 190286, 190291, 190297, 190303, 190308, 190314, 190320, 190325, 190330, 190336, 190342, 190348, 190354, 190360, 190366, 190372, 190377, 190382, 190388, 190393, 190399, 190405, 190410, 190415, 190420, 190425, 190430, 190435, 190439, 190444, 190450, 190456, 190461, 190467, 190473, 190478, 190483, 190489, 190495, 190501, 190507, 190513, 190519, 190525, 190530, 190535, 190541, 190546, 190552, 190558, 190563, 190568, 190573, 190578, 190583, 190588, 190592, 190597, 190603, 190609, 190614, 190620, 190626, 190631, 190636, 190642, 190648, 190654, 190660, 190666, 190672, 190678, 190683, 190688, 190694, 190699, 190705, 190711, 190716, 190721, 190726, 190731, 190736, 190741, 190744, 190748, 190753, 190758, 190762, 190767, 190772, 190776, 190780, 190785, 190790, 190795, 190800, 190805, 190810, 190815, 190819, 190823, 190828, 190832, 190837, 190842, 190846, 190850, 190854, 190858, 190862, 190866, 190869, 190873, 190878, 190883, 190887, 190892, 190897, 190901, 190905, 190910, 190915, 190920, 190925, 190930, 190935, 190940, 190944, 190948, 190953, 190957, 190962, 190967, 190971, 190975, 190979, 190983, 190987, 190991, 190995, 191000, 191006, 191012, 191017, 191023, 191029, 191034, 191039, 191045, 191051, 191057, 191063, 191069, 191075, 191081, 191086, 191091, 191097, 191102, 191108, 191114, 191119, 191124, 191129, 191134, 191139, 191144, 191148, 191153, 191159, 191165, 191170, 191176, 191182, 191187, 191192, 191198, 191204, 191210, 191216, 191222, 191228, 191234, 191239, 191244, 191250, 191255, 191261, 191267, 191272, 191277, 191282, 191287, 191292, 191297, 191302, 191308, 191315, 191322, 191328, 191335, 191342, 191348, 191354, 191361, 191368, 191375, 191382, 191389, 191396, 191403, 191409, 191415, 191422, 191428, 191435, 191442, 191448, 191454, 191460, 191466, 191472, 191478, 191482, 191487, 191493, 191499, 191504, 191510, 191516, 191521, 191526, 191532, 191538, 191544, 191550, 191556, 191562, 191568, 191573, 191578, 191584, 191589, 191595, 191601, 191606, 191611, 191616, 191621, 191626, 191631, 191634, 191638, 191643, 191648, 191652, 191657, 191662, 191666, 191670, 191675, 191680, 191685, 191690, 191695, 191700, 191705, 191709, 191713, 191718, 191722, 191727, 191732, 191736, 191740, 191744, 191748, 191752, 191756, 191761, 191767, 191774, 191781, 191787, 191794, 191801, 191807, 191813, 191820, 191827, 191834, 191841, 191848, 191855, 191862, 191868, 191874, 191881, 191887, 191894, 191901, 191907, 191913, 191919, 191925, 191931, 191937, 191941, 191946, 191952, 191958, 191963, 191969, 191975, 191980, 191985, 191991, 191997, 192003, 192009, 192015, 192021, 192027, 192032, 192037, 192043, 192048, 192054, 192060, 192065, 192070, 192075, 192080, 192085, 192090, 192093, 192097, 192102, 192107, 192111, 192116, 192121, 192125, 192129, 192134, 192139, 192144, 192149, 192154, 192159, 192164, 192168, 192172, 192177, 192181, 192186, 192191, 192195, 192199, 192203, 192207, 192211, 192215, 192219, 192224, 192230, 192236, 192241, 192247, 192253, 192258, 192263, 192269, 192275, 192281, 192287, 192293, 192299, 192305, 192310, 192315, 192321, 192326, 192332, 192338, 192343, 192348, 192353, 192358, 192363, 192368, 192373, 192379, 192386, 192393, 192399, 192406, 192413, 192419, 192425, 192432, 192439, 192446, 192453, 192460, 192467, 192474, 192480, 192486, 192493, 192499, 192506, 192513, 192519, 192525, 192531, 192537, 192543, 192549, 192553, 192558, 192564, 192570, 192575, 192581, 192587, 192592, 192597, 192603, 192609, 192615, 192621, 192627, 192633, 192639, 192644, 192649, 192655, 192660, 192666, 192672, 192677, 192682, 192687, 192692, 192697, 192702, 192706, 192711, 192717, 192723, 192728, 192734, 192740, 192745, 192750, 192756, 192762, 192768, 192774, 192780, 192786, 192792, 192797, 192802, 192808, 192813, 192819, 192825, 192830, 192835, 192840, 192845, 192850, 192855, 192858, 192862, 192867, 192872, 192876, 192881, 192886, 192890, 192894, 192899, 192904, 192909, 192914, 192919, 192924, 192929, 192933, 192937, 192942, 192946, 192951, 192956, 192960, 192964, 192968, 192972, 192976, 192980, 192985, 192991, 192998, 193005, 193011, 193018, 193025, 193031, 193037, 193044, 193051, 193058, 193065, 193072, 193079, 193086, 193092, 193098, 193105, 193111, 193118, 193125, 193131, 193137, 193143, 193149, 193155, 193161, 193165, 193170, 193176, 193182, 193187, 193193, 193199, 193204, 193209, 193215, 193221, 193227, 193233, 193239, 193245, 193251, 193256, 193261, 193267, 193272, 193278, 193284, 193289, 193294, 193299, 193304, 193309, 193314, 193318, 193323, 193329, 193335, 193340, 193346, 193352, 193357, 193362, 193368, 193374, 193380, 193386, 193392, 193398, 193404, 193409, 193414, 193420, 193425, 193431, 193437, 193442, 193447, 193452, 193457, 193462, 193467, 193471, 193476, 193482, 193488, 193493, 193499, 193505, 193510, 193515, 193521, 193527, 193533, 193539, 193545, 193551, 193557, 193562, 193567, 193573, 193578, 193584, 193590, 193595, 193600, 193605, 193610, 193615, 193620, 193624, 193629, 193635, 193641, 193646, 193652, 193658, 193663, 193668, 193674, 193680, 193686, 193692, 193698, 193704, 193710, 193715, 193720, 193726, 193731, 193737, 193743, 193748, 193753, 193758, 193763, 193768, 193773, 193777, 193782, 193788, 193794, 193799, 193805, 193811, 193816, 193821, 193827, 193833, 193839, 193845, 193851, 193857, 193863, 193868, 193873, 193879, 193884, 193890, 193896, 193901, 193906, 193911, 193916, 193921, 193926, 193929, 193933, 193938, 193943, 193947, 193952, 193957, 193961, 193965, 193970, 193975, 193980, 193985, 193990, 193995, 194000, 194004, 194008, 194013, 194017, 194022, 194027, 194031, 194035, 194039, 194043, 194047, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 194051, 194056, 194063, 194067, 194071, 194076, 194081, 194086, 194091, 194097, 194102, 194107, 194111, 194115, 194119, 194123, 194127, 194131, 194135, 194139, 194143, 194148, 194153, 194158, 194163, 194168, 194173, 194178, 194183, 194188, 194193, 194198, 194203, 194208, 194213, 194218, 194223, 194228, 194233, 194238, 194243, 194249, 194255, 194261, 194267, 194273, 194278, 194285, 194289, 194293, 194297, 194301, 194305, 194309, 194313, 194317, 194321, 194325, 194329, 194333, 194338, 194343, 194348, 194353, 194358, 194363, 194368, 194374, 194380, 194386, 194392, 194397, 194402, 194407, 194412, 194417, 194422, 194427, 194432, 194437, 194442, 194447, 194452, 194457, 194462, 194467, 194473, 194479, 194485, 194491, 194497, 194502, 194506, 194511, 194516, 194521, 194528, 194532, 194538, 194542, 194547, 194552, 194558, 194563, 194569, 194573, 194578, 194583, 194588, 194594, 194601, 194606, 194611, 194617, 194622, 194627, 194632, 194636, 194641, 194646, 194652, 194658, 194664, 194670, 194676, 194682, 194688, 194694, 194698, 194702, 194706, 194710, 194714, 194718, 194722, 194726, 194730, 194734, 194738, 194743, 194748, 194753, 194758, 194763, 194768, 194773, 194778, 194783, 194788, 194793, 194798, 194803, 194808, 194813, 194818, 194823, 194828, 194833, 194838, 194843, 194848, 194853, 194858, 194863, 194868, 194873, 194878, 194883, 194888, 194894, 194900, 194906, 194912, 194918, 194924, 194930, 194936, 194942, 194948, 194954, 194960, 194966, 194971, 194976, 194981, 194986, 194989, 194993, 194997, 195001, 195005, 195009, 195013, 195017, 195021, 195025, 195029, 195035, 195040, 195045, 195049, 195053, 195057, 195061, 195065, 195069, 195073, 195077, 195081, 195085, 195090, 195095, 195100, 195105, 195110, 195115, 195120, 195125, 195130, 195135, 195140, 195146, 195149, 195152, 195155, 195158, 195161, 195164, 195167, 195170, 195173, 195176, 195179, 195182, 195185, 195188, 195192, 195196, 195200, 195204, 195208, 195212, 195216, 195220, 195224, 195228, 195232, 195236, 195240, 195244, 195248, 195254, 195259, 195263, 195268, 195273, 195279, 195285, 195291, 195297, 195304, 195311, 195318, 195323, 195329, 195335, 195341, 195347, 195353, 195357, -1, -1, 195362, -1, 195369, -1, -1, 195375, 195379, 195384, 195388, 195392, 195398, 195405, 195409, 195415, 195421, -1, 195425, -1, 195431, -1, -1, 195436, 195440, -1, -1, -1, 195444, 195449, 195453, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195459, 195462, 195465, 195468, 195472, 195476, 195479, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195482, 195485, 195488, 195491, 195494, -1, -1, -1, -1, -1, 195498, -1, 195500, 195503, 195505, 195507, 195509, 195511, 195514, 195516, 195518, 195520, 195522, 195524, 195527, 195529, 195532, 195534, 195536, 195538, 195540, 195542, 195544, 195546, 195548, 195550, -1, 195552, 195554, 195556, 195559, 195562, -1, 195564, -1, 195566, 195568, -1, 195570, 195572, -1, 195574, 195577, 195579, 195581, 195584, 195586, 195588, 195590, 195593, 195595, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195598, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195600, 195603, 195606, 195608, 195610, 195612, 195614, 195617, 195619, 195622, 195624, 195627, 195630, 195634, 195637, 195641, 195643, 195646, 195648, 195651, 195653, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195655, 195657, 195659, -1, 195661, 195663, 195665, 195667, 195669, 195671, 195673, 195675, 195677, 195679, 195681, 195683, 195685, 195687, 195689, 195691, 195693, 195695, 195697, -1, 195699, 195701, 195703, 195705, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195707, 195709, 195711, 195713, 195715, 195717, 195719, 195721, 195723, 195725, 195727, 195729, 195731, 195733, 195735, 195737, 195739, 195741, 195743, 195745, 195747, 195749, 195751, 195753, 195755, 195757, 195759, 195761, 195763, 195765, 195767, 195769, 195771, 195773, 195775, 195777, 195779, 195781, 195783, 195785, 195787, 195789, 195791, 195793, 195795, 195797, 195799, 195801, 195803, 195805, 195807, 195809, 195811, 195813, 195815, 195817, 195819, 195821, 195823, 195825, 195827, 195829, 195831, 195833, 195835, 195837, 195839, 195841, 195843, 195845, 195847, 195849, 195851, 195853, 195855, 195857, 195859, 195861, 195863, 195865, 195867, 195869, 195871, 195873, 195875, 195877, 195879, 195881, 195883, 195885, 195887, 195889, 195891, 195893, -1, -1, 195895, 195897, 195899, 195901, 195903, 195905, 195908, 195910, 195912, 195914, 195916, 195918, 195921, 195924, 195927, 195930, 195932, 195934, 195936, 195938, 195940, 195942, 195945, 195948, 195951, 195954, 195957, 195960, 195963, 195966, 195969, 195972, 195975, 195978, 195981, 195984, 195987, 195990, 195993, 195996, 195999, 196002, 196005, 196008, 196011, 196014, 196017, 196020, 196023, 196026, 196029, 196032, 196035, 196038, 196041, 196044, 196047, 196050, 196053, 196056, 196059, 196061, 196063, -1, 196065, 196067, 196070, 196073, 196075, 196078, 196081, 196083, 196086, 196088, 196091, 196094, 196097, 196100, 196103, 196106, 196109, 196111, 196113, 196116, 196119, 196121, -1, 196124, 196126, 196129, 196131, 196133, 196135, 196137, -1, -1, -1, 196139, 196141, 196144, 196147, 196151, 196154, -1, -1, 196156, 196160, 196163, 196165, 196168, 196172, -1, -1, 196175, 196178, 196180, 196184, 196187, 196190, -1, -1, 196193, 196196, 196199, -1, -1, -1, 196201, 196204, 196207, 196209, 196211, 196213, 196216, -1, 196219, 196221, 196223, 196225, 196227, 196229, 196231, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 196233, 196235, 196237, -1, -1, -1, }; QString Data::removeAccents(const QString &input) { FCT_IDENTIFICATION; // Based on iconv algorithm. // However, I don't want to use iconv here, because the library is too complex for what I actually need if ( input.isEmpty() ) return QString(); QString ret; for ( const QChar &character : input ) { const char16_t charInt = character.unicode(); // skip the non-printable chars if ( charInt < 32 ) continue; // basic ASCII are mapped 1:1 if ( charInt < 128 ) { ret.append(character); } else // the rest is mapped based on translitTab { const int offset = charInt - 128; const int maxIndex = static_cast(sizeof(tranlitIndexMap) / sizeof(tranlitIndexMap[0])); if ( offset < maxIndex ) { const int index = tranlitIndexMap[offset]; if ( index >= 0 ) { const char size = translitTab[index]; if ( size > 0 ) { for (ushort i = 0; i < size; i++) ret.append(translitTab[index + 1 + i]); } else { ret.append("?"); } } else { ret.append("?"); } } else { ret.append("?"); } } } /* If stripped string is empty then QString to store NULL value do DB */ if ( ret.isEmpty() ) return QString(); return ret; } foldynl-QLog-3252ff9/data/ActivityProfile.cpp000066400000000000000000000211261517334601000211170ustar00rootroot00000000000000#include "ActivityProfile.h" #include "core/debug.h" #include "data/ProfileManager.h" #include "data/AntProfile.h" #include "data/MainLayoutProfile.h" #include "data/RigProfile.h" #include "data/RotProfile.h" #include "data/StationProfile.h" MODULE_IDENTIFICATION("qlog.data.activityprofile"); // a compilation issue under 20.04 Ubuntu because qt 5.12 does not // support >> for QHash but it is not used now. // QDataStream& operator<<(QDataStream& out, const ActivityProfile& v) // { // out << v.profileName // << v.profiles // << v.fieldValues; // return out; // } // QDataStream& operator<<(QDataStream& out, const ActivityProfile::ProfileRecord& v) // { // out << v.name // << v.params; // return out; // } // QDataStream& operator>>(QDataStream& in, ActivityProfile& v) // { // in >> v.profileName; // in >> v.profiles; // in >> v.fieldValues; // return in; // } // QDataStream& operator>>(QDataStream& in, ActivityProfile::ProfileRecord& v) // { // in >> v.name; // in >> v.params; // return in; // } ActivityProfile::ActivityProfile(const QString &name, const QJsonDocument &config) { /* Config example * { * "activityName" = "name", * "profiles" = [ * { "profileType" = 1, * "name" = "name", * "params" = [ * { * "name" = "connect" * "value" : true * } * ] * } * ] * "fieldValues" = [ * { "fieldID" = 12, * "value" = "Contest" * } * ] * } */ if ( config.isEmpty() ) return; profileName = name; const QJsonArray &profilesArray = config["profiles"].toArray(); for ( const QJsonValue &value : profilesArray ) { const QJsonObject &obj = value.toObject(); ActivityProfile::ProfileRecord profileRec; profileRec.name = obj["name"].toString(); const QJsonArray &profilesParamsArray = value["params"].toArray(); for ( const QJsonValue ¶mValue : profilesParamsArray ) { const QJsonObject &inner = paramValue.toObject(); profileRec.params[getParamID(inner["name"].toString())] = inner["value"].toVariant(); } profiles[static_cast(obj["profileType"].toInt())] = profileRec; } const QJsonArray &fieldValuesArray = config["fieldValues"].toArray(); for ( const QJsonValue &fieldValue : fieldValuesArray ) { const QJsonObject &obj = fieldValue.toObject(); fieldValues[obj["fieldID"].toInt()] = obj["value"].toString(); } } QByteArray ActivityProfile::toJson() const { /* Config example * { * "activityName" = "name", * "profiles" = [ * { "profileType" = 1, * "name" = "name", * "params" = [ * { * "name" = "connect" * "value" : true * } * ] * } * ] * "fieldValues" = [ * { "fieldID" = 12, * "value" = "Contest" * } * ] * } */ QJsonObject activityObject; activityObject["activityName"] = profileName; if ( !profiles.isEmpty() ) { QJsonArray profilesArray; for (auto i = profiles.begin(); i != profiles.end(); ++i) { QJsonObject profileObject; profileObject["profileType"] = i.key(); profileObject["name"] = i.value().name; if ( !i.value().params.isEmpty() ) { QJsonArray paramsArray; for (auto j = i.value().params.begin(); j != i.value().params.end(); ++j ) { QJsonObject profileParamObject; profileParamObject["name"] = getParamName(j.key()); profileParamObject["value"] = j.value().toJsonValue(); paramsArray.push_back(profileParamObject); } profileObject["params"] = paramsArray; } profilesArray.push_back(profileObject); } activityObject["profiles"] = profilesArray; } if ( !fieldValues.isEmpty() ) { QJsonArray fieldValuesArray; for (auto i = fieldValues.begin(); i != fieldValues.end(); i++ ) { QJsonObject fieldObject; fieldObject["fieldID"] = i.key(); fieldObject["value"] = i.value().toJsonValue(); fieldValuesArray.push_back(fieldObject); } activityObject["fieldValues"] = fieldValuesArray; } QJsonDocument doc(activityObject); return doc.toJson(); } bool ActivityProfile::operator==(const ActivityProfile &profile) { return ( profile.profileName == this->profileName && profile.profiles == this->profiles && profile.fieldValues == this->fieldValues ); } bool ActivityProfile::operator!=(const ActivityProfile &profile) { return !operator==(profile); } void ActivityProfilesManager::setAllProfiles() { ActivityProfile currActivity = getCurProfile1(); if (currActivity == ActivityProfile() ) return; for( auto i = currActivity.profiles.begin(); i != currActivity.profiles.end(); i++ ) { qCDebug(runtime) << i.key() << i.value().name; switch ( i.key() ) { case ActivityProfile::ANTENNA_PROFILE: AntProfilesManager::instance()->setCurProfile1(i.value().name); break; case ActivityProfile::STATION_PROFILE: StationProfilesManager::instance()->setCurProfile1(i.value().name); break; case ActivityProfile::RIG_PROFILE: RigProfilesManager::instance()->setCurProfile1(i.value().name); break; case ActivityProfile::ROT_PROFILE: RotProfilesManager::instance()->setCurProfile1(i.value().name); break; case ActivityProfile::MAIN_LAYOUT_PROFILE: MainLayoutProfilesManager::instance()->setCurProfile1(i.value().name); break; default: qWarning() << "Unknown Activity profile" << i.key(); } } emit changeFinished(currActivity.profileName); } ActivityProfilesManager::ActivityProfilesManager() : ProfileManagerSQL("activity_profiles") { FCT_IDENTIFICATION; QSqlQuery profileQuery; if ( ! profileQuery.prepare("SELECT profile_name, config FROM activity_profiles") ) qWarning()<< "Cannot prepare select"; if ( profileQuery.exec() ) { while (profileQuery.next()) { ActivityProfile profileDB(profileQuery.value(0).toString(), QJsonDocument::fromJson(profileQuery.value(1).toByteArray())); addProfile(profileDB.profileName, profileDB); } } else qInfo() << "Activity Profile DB select error " << profileQuery.lastError().text(); connect (this, &ActivityProfilesManager::profileChanged, this, &ActivityProfilesManager::setAllProfiles); } void ActivityProfilesManager::save() { FCT_IDENTIFICATION; QSqlQuery deleteQuery; QSqlQuery insertQuery; if ( ! deleteQuery.prepare("DELETE FROM activity_profiles") ) { qWarning() << "cannot prepare Delete statement"; return; } if ( ! insertQuery.prepare("INSERT INTO activity_profiles(profile_name, config) " "VALUES (:profile_name, :config)") ) { qWarning() << "cannot prepare Insert statement"; return; } if ( deleteQuery.exec() ) { const QStringList &keys = profileNameList(); for ( const QString &key: keys ) { const ActivityProfile &activityProfile = getProfile(key); insertQuery.bindValue(":profile_name", key); insertQuery.bindValue(":config", activityProfile.toJson()); if ( ! insertQuery.exec() ) qInfo() << "Station Profile DB insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); } } else qInfo() << "Activity Profile DB delete error " << deleteQuery.lastError().text(); saveCurProfile1(); } foldynl-QLog-3252ff9/data/ActivityProfile.h000066400000000000000000000044611517334601000205670ustar00rootroot00000000000000#ifndef Q_LOG_DATA_ACTIVITYPROFILE_H #define Q_LOG_DATA_ACTIVITYPROFILE_H #include #include "data/ProfileManager.h" class ActivityProfile { public: enum ProfileType { ANTENNA_PROFILE = 0, STATION_PROFILE = 1, RIG_PROFILE = 2, ROT_PROFILE = 3, MAIN_LAYOUT_PROFILE = 4 }; enum ProfileParamType { CONNECT = 0, }; struct ProfileRecord { QString name; QHash params; bool operator==(const ProfileRecord &other) const { return name == other.name && params == other.params; } }; ActivityProfile() {}; ActivityProfile(const QString &name, const QJsonDocument &config); QByteArray toJson() const; QString profileName; QHash profiles; QHash fieldValues; QVariant getProfileParam(ProfileType profileType, ProfileParamType profileParam) const { return profiles.value(profileType).params.value(profileParam); }; bool operator== (const ActivityProfile &profile); bool operator!= (const ActivityProfile &profile); private: // friend QDataStream& operator<<(QDataStream& out, const ActivityProfile& v); // friend QDataStream& operator<<(QDataStream& out, const ActivityProfile::ProfileRecord& v); // friend QDataStream& operator>>(QDataStream& in, ActivityProfile& v); // friend QDataStream& operator>>(QDataStream& in, ActivityProfile::ProfileRecord& v); QString getParamName(ProfileParamType id) const { return profileParamsNameMapping.value(id);} ; ProfileParamType getParamID(const QString ¶mName) const { return profileParamsNameMapping.key(paramName);}; QHash profileParamsNameMapping = {{CONNECT, "connect"}}; }; Q_DECLARE_METATYPE(ActivityProfile); class ActivityProfilesManager : public ProfileManagerSQL { Q_OBJECT signals: void changeFinished(const QString &name); public slots: void setAllProfiles(); public: explicit ActivityProfilesManager(); ~ActivityProfilesManager() { }; static ActivityProfilesManager* instance() { static ActivityProfilesManager instance; return &instance; }; void save(); }; #endif // Q_LOG_DATA_ACTIVITYPROFILE_H foldynl-QLog-3252ff9/data/AntProfile.cpp000066400000000000000000000062201517334601000200430ustar00rootroot00000000000000#include #include #include #include "AntProfile.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.data.antprofile"); QDataStream& operator<<(QDataStream& out, const AntProfile& v) { out << v.profileName << v.description << v.azimuthBeamWidth << v.azimuthOffset; return out; } QDataStream& operator>>(QDataStream& in, AntProfile& v) { in >> v.profileName; in >> v.description; in >> v.azimuthBeamWidth; in >> v.azimuthOffset; return in; } AntProfilesManager::AntProfilesManager() : ProfileManagerSQL("ant_profiles") { FCT_IDENTIFICATION; QSqlQuery profileQuery; if ( ! profileQuery.prepare("SELECT profile_name, desc, azimuth_beamwidth, azimuth_offset FROM ant_profiles") ) { qWarning()<< "Cannot prepare select"; } if ( profileQuery.exec() ) { while (profileQuery.next()) { AntProfile profileDB; profileDB.profileName = profileQuery.value(0).toString(); profileDB.description = profileQuery.value(1).toString(); profileDB.azimuthBeamWidth = profileQuery.value(2).toDouble(); profileDB.azimuthOffset = profileQuery.value(3).toDouble(); addProfile(profileDB.profileName, profileDB); } } else { qInfo() << "Station Profile DB select error " << profileQuery.lastError().text(); } } void AntProfilesManager::save() { FCT_IDENTIFICATION; QSqlQuery deleteQuery; QSqlQuery insertQuery; if ( ! deleteQuery.prepare("DELETE FROM ant_profiles") ) { qWarning() << "cannot prepare Delete statement"; return; } if ( ! insertQuery.prepare("INSERT INTO ant_profiles(profile_name, desc, azimuth_beamwidth, azimuth_offset) " "VALUES (:profile_name, :desc, :azimuth_beamwidth, :azimuth_offset)") ) { qWarning() << "cannot prepare Insert statement"; return; } if ( deleteQuery.exec() ) { const QStringList &keys = profileNameList(); for ( const QString &key: keys ) { const AntProfile &antProfile = getProfile(key); insertQuery.bindValue(":profile_name", key); insertQuery.bindValue(":desc", antProfile.description); insertQuery.bindValue(":azimuth_beamwidth", antProfile.azimuthBeamWidth); insertQuery.bindValue(":azimuth_offset", antProfile.azimuthOffset); if ( ! insertQuery.exec() ) { qInfo() << "Station Profile DB insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); } } } else { qInfo() << "Station Profile DB delete error " << deleteQuery.lastError().text(); } saveCurProfile1(); } bool AntProfile::operator==(const AntProfile &profile) { return (profile.profileName == this->profileName && profile.description == this->description && profile.azimuthBeamWidth == this->azimuthBeamWidth && profile.azimuthOffset == this->azimuthOffset); } bool AntProfile::operator!=(const AntProfile &profile) { return !operator==(profile); } foldynl-QLog-3252ff9/data/AntProfile.h000066400000000000000000000017631517334601000175170ustar00rootroot00000000000000#ifndef QLOG_DATA_ANTPROFILE_H #define QLOG_DATA_ANTPROFILE_H #include #include #include #include "data/ProfileManager.h" #define DEFAULT_ROT_MODEL 1 class AntProfile { public: AntProfile() : azimuthBeamWidth(0.0), azimuthOffset(0.0) {}; QString profileName; QString description; double azimuthBeamWidth; double azimuthOffset; bool operator== (const AntProfile &profile); bool operator!= (const AntProfile &profile); private: friend QDataStream& operator<<(QDataStream& out, const AntProfile& v); friend QDataStream& operator>>(QDataStream& in, AntProfile& v); }; Q_DECLARE_METATYPE(AntProfile) class AntProfilesManager : public ProfileManagerSQL { Q_OBJECT public: explicit AntProfilesManager(); ~AntProfilesManager() { }; static AntProfilesManager *instance() { static AntProfilesManager instance; return &instance; }; void save(); }; #endif // QLOG_DATA_ANTPROFILE_H foldynl-QLog-3252ff9/data/Band.h000066400000000000000000000007361517334601000163170ustar00rootroot00000000000000#ifndef QLOG_DATA_BAND_H #define QLOG_DATA_BAND_H #include class Band { public: QString name; double start; double end; QString satDesignator; bool operator==(const Band &band) const { return ( this->name == band.name && this->start == band.start && this->end == band.end && this->satDesignator == band.satDesignator ); } }; Q_DECLARE_METATYPE(Band); #endif // QLOG_DATA_BAND_H foldynl-QLog-3252ff9/data/BandPlan.cpp000066400000000000000000000326011517334601000174610ustar00rootroot00000000000000#include #include #include "BandPlan.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.data.bandplan"); struct BandModeRange { double start; double end; BandPlan::BandPlanMode mode; }; // currectly only IARU Region 1 is implemented // https://www.iaru-r1.org/wp-content/uploads/2019/08/hf_r1_bandplan.pdf // https://www.oevsv.at/export/shared/.content/.galleries/pdf-Downloads/OVSV-Bandplan_05-2019.pdf static const BandModeRange r1BandModeTable[] = { // 2200m {0.1357, 0.1378, BandPlan::BAND_MODE_CW}, // 630m {0.472, 0.475, BandPlan::BAND_MODE_CW}, {0.475, 0.479, BandPlan::BAND_MODE_DIGITAL}, // 160m {1.800, 1.838, BandPlan::BAND_MODE_CW}, {1.838, 1.840, BandPlan::BAND_MODE_DIGITAL}, {1.840, 1.843, BandPlan::BAND_MODE_FT8}, {1.843, 2.000, BandPlan::BAND_MODE_LSB}, // 80m {3.500, 3.570, BandPlan::BAND_MODE_CW}, {3.570, 3.573, BandPlan::BAND_MODE_DIGITAL}, {3.573, 3.576, BandPlan::BAND_MODE_FT8}, {3.576, 3.579, BandPlan::BAND_MODE_FT4}, {3.579, 3.600, BandPlan::BAND_MODE_DIGITAL}, {3.600, 4.000, BandPlan::BAND_MODE_LSB}, // 60m {5.3515, 5.356, BandPlan::BAND_MODE_CW}, {5.356, 5.361, BandPlan::BAND_MODE_FT8}, {5.361, 5.500, BandPlan::BAND_MODE_LSB}, // 40m {7.000, 7.040, BandPlan::BAND_MODE_CW}, {7.040, 7.047, BandPlan::BAND_MODE_DIGITAL}, {7.047, 7.050, BandPlan::BAND_MODE_FT4}, {7.050, 7.060, BandPlan::BAND_MODE_DIGITAL}, {7.060, 7.074, BandPlan::BAND_MODE_LSB}, {7.074, 7.077, BandPlan::BAND_MODE_FT8}, {7.077, 7.300, BandPlan::BAND_MODE_LSB}, // 30m {10.100, 10.130, BandPlan::BAND_MODE_CW}, {10.130, 10.136, BandPlan::BAND_MODE_DIGITAL}, {10.136, 10.139, BandPlan::BAND_MODE_FT8}, {10.139, 10.140, BandPlan::BAND_MODE_DIGITAL}, {10.140, 10.143, BandPlan::BAND_MODE_FT4}, {10.143, 10.150, BandPlan::BAND_MODE_DIGITAL}, // 20m {14.000, 14.070, BandPlan::BAND_MODE_CW}, {14.070, 14.074, BandPlan::BAND_MODE_DIGITAL}, {14.074, 14.080, BandPlan::BAND_MODE_FT8}, {14.080, 14.083, BandPlan::BAND_MODE_FT4}, {14.083, 14.099, BandPlan::BAND_MODE_DIGITAL}, {14.099, 14.101, BandPlan::BAND_MODE_CW}, {14.101, 14.350, BandPlan::BAND_MODE_USB}, // 17m {18.068, 18.095, BandPlan::BAND_MODE_CW}, {18.095, 18.100, BandPlan::BAND_MODE_DIGITAL}, {18.100, 18.103, BandPlan::BAND_MODE_FT8}, {18.103, 18.106, BandPlan::BAND_MODE_FT4}, {18.106, 18.109, BandPlan::BAND_MODE_DIGITAL}, {18.109, 18.111, BandPlan::BAND_MODE_CW}, {18.111, 18.168, BandPlan::BAND_MODE_USB}, // 15m {21.000, 21.070, BandPlan::BAND_MODE_CW}, {21.070, 21.074, BandPlan::BAND_MODE_DIGITAL}, {21.074, 21.077, BandPlan::BAND_MODE_FT8}, {21.077, 21.140, BandPlan::BAND_MODE_DIGITAL}, {21.140, 21.143, BandPlan::BAND_MODE_FT4}, {21.143, 21.149, BandPlan::BAND_MODE_DIGITAL}, {21.149, 21.151, BandPlan::BAND_MODE_CW}, {21.151, 21.450, BandPlan::BAND_MODE_USB}, // 12m {24.890, 24.915, BandPlan::BAND_MODE_CW}, {24.915, 24.919, BandPlan::BAND_MODE_FT8}, {24.919, 24.922, BandPlan::BAND_MODE_FT4}, {24.922, 24.929, BandPlan::BAND_MODE_DIGITAL}, {24.929, 24.931, BandPlan::BAND_MODE_CW}, {24.931, 24.990, BandPlan::BAND_MODE_USB}, // 10m {28.000, 28.070, BandPlan::BAND_MODE_CW}, {28.070, 28.074, BandPlan::BAND_MODE_DIGITAL}, {28.074, 28.077, BandPlan::BAND_MODE_FT8}, {28.077, 28.180, BandPlan::BAND_MODE_DIGITAL}, {28.180, 28.183, BandPlan::BAND_MODE_FT4}, {28.183, 28.190, BandPlan::BAND_MODE_DIGITAL}, {28.190, 28.225, BandPlan::BAND_MODE_CW}, {28.225, 29.700, BandPlan::BAND_MODE_USB}, // 6m {50.000, 50.100, BandPlan::BAND_MODE_CW}, {50.100, 50.313, BandPlan::BAND_MODE_USB}, {50.313, 50.318, BandPlan::BAND_MODE_FT8}, {50.318, 50.321, BandPlan::BAND_MODE_FT4}, {50.321, 50.400, BandPlan::BAND_MODE_DIGITAL}, {50.400, 50.500, BandPlan::BAND_MODE_CW}, {50.500, 54.000, BandPlan::BAND_MODE_PHONE}, // 4m {70.000, 70.100, BandPlan::BAND_MODE_CW}, {70.100, 70.102, BandPlan::BAND_MODE_FT8}, {70.102, 70.500, BandPlan::BAND_MODE_USB}, // 2m {144.000, 144.100, BandPlan::BAND_MODE_CW}, {144.100, 144.120, BandPlan::BAND_MODE_USB}, {144.120, 144.123, BandPlan::BAND_MODE_FT4}, {144.123, 144.174, BandPlan::BAND_MODE_USB}, {144.174, 144.176, BandPlan::BAND_MODE_FT8}, {144.176, 144.360, BandPlan::BAND_MODE_USB}, {144.360, 144.400, BandPlan::BAND_MODE_DIGITAL}, {144.400, 144.491, BandPlan::BAND_MODE_CW}, {144.491, 144.975, BandPlan::BAND_MODE_DIGITAL}, {144.975, 148.000, BandPlan::BAND_MODE_USB}, // 1.25m {222.000, 222.150, BandPlan::BAND_MODE_CW}, {222.150, 225.000, BandPlan::BAND_MODE_USB}, // 70cm {430.000, 432.000, BandPlan::BAND_MODE_USB}, {432.000, 432.065, BandPlan::BAND_MODE_CW}, {432.065, 432.067, BandPlan::BAND_MODE_FT8}, {432.067, 432.100, BandPlan::BAND_MODE_CW}, {432.100, 440.000, BandPlan::BAND_MODE_USB}, // 33cm {902.000, 928.000, BandPlan::BAND_MODE_USB}, // 23cm {1240.000, 1296.150, BandPlan::BAND_MODE_USB}, {1296.150, 1296.400, BandPlan::BAND_MODE_CW}, {1296.400, 1300.000, BandPlan::BAND_MODE_PHONE}, // 3cm QO100 // at the moment there is no other satellite that would be used, so we can afford it. // It will not affect tropo operation, because it is in the lower part of the band. {10489.505, 10489.540, BandPlan::BAND_MODE_CW}, {10489.540, 10489.580, BandPlan::BAND_MODE_FT8}, {10489.580, 10489.650, BandPlan::BAND_MODE_DIGITAL}, {10489.650, 10489.745, BandPlan::BAND_MODE_USB}, {10489.755, 10489.850, BandPlan::BAND_MODE_USB}, {10489.850, 10489.990, BandPlan::BAND_MODE_PHONE} }; static int bandModeTableSize = sizeof(r1BandModeTable) / sizeof(r1BandModeTable[0]); BandPlan::BandPlanMode BandPlan::freq2BandMode(const double freq) { FCT_IDENTIFICATION; qCDebug(function_parameters) << freq; int left = 0; int right = bandModeTableSize - 1; while ( left <= right ) { int mid = (left + right) / 2; const BandModeRange &range = r1BandModeTable[mid]; if (freq < range.start) right = mid - 1; else if (freq >= range.end) left = mid + 1; else return range.mode; } // fallback return BandPlan::BAND_MODE_PHONE; } const QString BandPlan::bandMode2BandModeGroupString(const BandPlanMode &bandPlanMode) { FCT_IDENTIFICATION; switch ( bandPlanMode ) { case BAND_MODE_CW: return BandPlan::MODE_GROUP_STRING_CW; case BAND_MODE_DIGITAL: return BandPlan::MODE_GROUP_STRING_DIGITAL; case BAND_MODE_FT8: case BAND_MODE_FT4: case BAND_MODE_FT2: return BandPlan::MODE_GROUP_STRING_FTx; case BAND_MODE_PHONE: case BAND_MODE_LSB: case BAND_MODE_USB: return BandPlan::MODE_GROUP_STRING_PHONE; case BAND_MODE_UNKNOWN: return QString(); } return QString(); } const QString BandPlan::freq2BandModeGroupString(const double freq) { FCT_IDENTIFICATION; qCDebug(function_parameters) << freq; return bandMode2BandModeGroupString(freq2BandMode(freq)); } const QString BandPlan::bandPlanMode2ExpectedMode(const BandPlanMode &bandPlanMode, QString &submode) { FCT_IDENTIFICATION; submode = QString(); switch ( bandPlanMode ) { case BAND_MODE_CW: {submode = QString(); return "CW";} case BAND_MODE_LSB: {submode = "LSB"; return "SSB";} case BAND_MODE_USB: {submode = "USB"; return "SSB";} case BAND_MODE_FT8: {return "FT8";} case BAND_MODE_FT4: {submode = "FT4";return "MFSK";} case BAND_MODE_FT2: // not currently specified - use USB case BAND_MODE_DIGITAL: {submode = "USB"; return "SSB";} // imprecise, but let's try this //case BAND_MODE_PHONE: // it can be FM, SSB, AM - no Mode Change default: submode = QString(); } return QString(); } const QString BandPlan::freq2ExpectedMode(const double freq, QString &submode) { FCT_IDENTIFICATION; qCDebug(function_parameters) << freq; return bandPlanMode2ExpectedMode(freq2BandMode(freq), submode); } const Band BandPlan::freq2Band(double freq) { FCT_IDENTIFICATION; qCDebug(function_parameters) << freq; QSqlQuery query; if ( ! query.prepare("SELECT name, start_freq, end_freq, sat_designator " "FROM bands " "WHERE :freq BETWEEN start_freq AND end_freq") ) { qWarning() << "Cannot prepare Select statement"; return Band(); } query.bindValue(0, freq); if ( ! query.exec() ) { qWarning() << "Cannot execute select statement" << query.lastError(); return Band(); } if ( query.next() ) { Band band; band.name = query.value(0).toString(); band.start = query.value(1).toDouble(); band.end = query.value(2).toDouble(); band.satDesignator = query.value(3).toString(); return band; } return Band(); } const Band BandPlan::bandName2Band(const QString &name) { FCT_IDENTIFICATION; qCDebug(function_parameters) << name; QSqlQuery query; if ( ! query.prepare("SELECT name, start_freq, end_freq, sat_designator " "FROM bands " "WHERE name = :name LIMIT 1") ) { qWarning() << "Cannot prepare Select statement"; return Band(); } query.bindValue(0, name.toLower()); if ( ! query.exec() ) { qWarning() << "Cannot execute select statement" << query.lastError(); return Band(); } if ( query.next() ) { Band band; band.name = query.value(0).toString(); band.start = query.value(1).toDouble(); band.end = query.value(2).toDouble(); band.satDesignator = query.value(3).toString(); return band; } return Band(); } const QList BandPlan::bandsList(const bool onlyDXCCBands, const bool onlyEnabled) { FCT_IDENTIFICATION; qCDebug(function_parameters) << onlyDXCCBands << onlyEnabled; QSqlQuery query; QList ret; QString stmt(QLatin1String("SELECT name, start_freq, end_freq, sat_designator " "FROM bands WHERE 1 = 1 ")); if ( onlyEnabled ) stmt.append("AND enabled = 1 "); if ( onlyDXCCBands ) { stmt.append("AND ((1.9 between start_freq and end_freq) " " OR (3.6 between start_freq and end_freq) " " OR (7.1 between start_freq and end_freq) " " OR (10.1 between start_freq and end_freq) " " OR (14.1 between start_freq and end_freq) " " OR (18.1 between start_freq and end_freq) " " OR (21.1 between start_freq and end_freq) " " OR (24.9 between start_freq and end_freq) " " OR (28.1 between start_freq and end_freq) " " OR (50.1 between start_freq and end_freq) " " OR (145.1 between start_freq and end_freq) " " OR (421.1 between start_freq and end_freq) " " OR (1241.0 between start_freq and end_freq) " " OR (2301.0 between start_freq and end_freq) " " OR (10001.0 between start_freq and end_freq)) "); } stmt.append("ORDER BY start_freq "); qCDebug(runtime) << stmt; if ( ! query.prepare(stmt) ) { qWarning() << "Cannot prepare Select statement"; return ret; } if ( ! query.exec() ) { qWarning() << "Cannot execute select statement" << query.lastError(); return ret; } while ( query.next() ) { Band band; band.name = query.value(0).toString(); band.start = query.value(1).toDouble(); band.end = query.value(2).toDouble(); band.satDesignator = query.value(3).toString(); ret << band; } return ret; } const QString BandPlan::modeToDXCCModeGroup(const QString &mode) { FCT_IDENTIFICATION; qCDebug(function_parameters) << mode; if ( mode.isEmpty() ) return QString(); QSqlQuery query; if ( !query.prepare("SELECT modes.dxcc " "FROM modes " "WHERE modes.name = :mode LIMIT 1")) { qWarning() << "Cannot prepare Select statement"; return QString(); } query.bindValue(0, mode); if ( query.exec() ) { QString ret; query.next(); ret = query.value(0).toString(); return ret; } return QString(); } const QString BandPlan::modeToModeGroup(const QString &mode) { FCT_IDENTIFICATION; return isFTxMode(mode) ? BandPlan::MODE_GROUP_STRING_FTx : BandPlan::modeToDXCCModeGroup(mode); } bool BandPlan::isFTxMode(const QString &mode) { return mode == "FT8" || mode == "FT4" || mode == "FT2"; } bool BandPlan::isFTxBandMode(BandPlanMode mode) { return mode == BAND_MODE_FT8 || mode == BAND_MODE_FT4 || mode == BAND_MODE_FT2; } BandPlan::BandPlan() { FCT_IDENTIFICATION; } const QString BandPlan::MODE_GROUP_STRING_CW = "CW"; const QString BandPlan::MODE_GROUP_STRING_DIGITAL = "DIGITAL"; const QString BandPlan::MODE_GROUP_STRING_FTx = "FTx"; const QString BandPlan::MODE_GROUP_STRING_PHONE = "PHONE"; foldynl-QLog-3252ff9/data/BandPlan.h000066400000000000000000000031661517334601000171320ustar00rootroot00000000000000#ifndef QLOG_DATA_BANDPLAN_H #define QLOG_DATA_BANDPLAN_H #include #include "Band.h" class BandPlan { public: static const QString MODE_GROUP_STRING_CW; static const QString MODE_GROUP_STRING_DIGITAL; static const QString MODE_GROUP_STRING_FTx; static const QString MODE_GROUP_STRING_PHONE; enum BandPlanMode { BAND_MODE_UNKNOWN, BAND_MODE_CW, BAND_MODE_DIGITAL, BAND_MODE_FT8, BAND_MODE_FT4, BAND_MODE_FT2, BAND_MODE_LSB, BAND_MODE_USB, BAND_MODE_PHONE }; static BandPlanMode freq2BandMode(const double freq); static const QString bandMode2BandModeGroupString(const BandPlan::BandPlanMode &bandPlanMode); static const QString freq2BandModeGroupString(const double freq); static const QString bandPlanMode2ExpectedMode(const BandPlan::BandPlanMode &bandPlanMode, QString &submode); static const QString freq2ExpectedMode(const double freq, QString &submode); static const Band freq2Band(double freq); static const Band bandName2Band(const QString& name); static const QList bandsList(const bool onlyDXCCBands = false, const bool onlyEnabled = false); static const QString modeToDXCCModeGroup(const QString &mode); static const QString modeToModeGroup(const QString &mode); static bool isFTxMode(const QString &mode); static bool isFTxBandMode(BandPlanMode mode); BandPlan(); }; Q_DECLARE_METATYPE(BandPlan::BandPlanMode); #endif // QLOG_DATA_BANDPLAN_H foldynl-QLog-3252ff9/data/CWKeyProfile.cpp000066400000000000000000000122741517334601000203110ustar00rootroot00000000000000#include #include #include "CWKeyProfile.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.data.cwkeyprofile"); QDataStream& operator<<(QDataStream& out, const CWKeyProfile& v) { out << v.profileName << v.model << v.defaultSpeed << v.keyMode << v.portPath << v.baudrate << v.hostname << v.netport << v.paddleSwap << v.paddleOnlySidetone << v.sidetoneFrequency; return out; } QDataStream& operator>>(QDataStream& in, CWKeyProfile& v) { in >> v.profileName; in >> v.model; in >> v.defaultSpeed; in >> v.keyMode; in >> v.portPath; in >> v.baudrate; in >> v.hostname; in >> v.netport; in >> v.paddleSwap; in >> v.paddleOnlySidetone; in >> v.sidetoneFrequency; return in; } CWKeyProfilesManager::CWKeyProfilesManager() : ProfileManagerSQL("cwkey_profiles") { FCT_IDENTIFICATION; QSqlQuery profileQuery; if ( ! profileQuery.prepare("SELECT profile_name, model, default_speed, " " key_mode, port_pathname, baudrate, hostname, netport, paddle_swap, paddle_only_sidetone, sidetone_frequency " "FROM cwkey_profiles") ) { qWarning()<< "Cannot prepare select"; } if ( profileQuery.exec() ) { while (profileQuery.next()) { CWKeyProfile profileDB; profileDB.profileName = profileQuery.value(0).toString(); profileDB.model = CWKey::intToTypeID(profileQuery.value(1).toInt()); profileDB.defaultSpeed = profileQuery.value(2).toInt(); profileDB.keyMode = CWKey::intToModeID(profileQuery.value(3).toInt()); profileDB.portPath = profileQuery.value(4).toString(); profileDB.baudrate = profileQuery.value(5).toUInt(); profileDB.hostname = profileQuery.value(6).toString(); profileDB.netport = profileQuery.value(7).toUInt(); profileDB.paddleSwap = profileQuery.value(8).toBool(); profileDB.paddleOnlySidetone = profileQuery.value(9).toBool(); profileDB.sidetoneFrequency = profileQuery.value(10).toInt(); addProfile(profileDB.profileName, profileDB); } } else { qInfo() << "CW Key Profile DB select error " << profileQuery.lastError().text(); } } void CWKeyProfilesManager::save() { FCT_IDENTIFICATION; QSqlQuery deleteQuery; QSqlQuery insertQuery; if ( ! deleteQuery.prepare("DELETE FROM cwkey_profiles") ) { qWarning() << "Cannot prepare Delete statement"; return; } if ( ! insertQuery.prepare("INSERT INTO cwkey_profiles(profile_name, model, default_speed, key_mode, port_pathname, baudrate, hostname, netport, paddle_swap, paddle_only_sidetone, sidetone_frequency) " "VALUES (:profile_name, :model, :default_speed, :key_mode, :port_pathname, :baudrate, :hostname, :netport, :paddle_swap, :paddle_only_sidetone, :sidetone_frequency)") ) { qWarning() << "Cannot prepare Insert statement"; return; } if ( deleteQuery.exec() ) { const QStringList &keys = profileNameList(); for ( const QString &key: keys ) { const CWKeyProfile &cwKeyProfile = getProfile(key); insertQuery.bindValue(":profile_name", key); insertQuery.bindValue(":model", cwKeyProfile.model); insertQuery.bindValue(":default_speed", cwKeyProfile.defaultSpeed); insertQuery.bindValue(":key_mode", cwKeyProfile.keyMode); insertQuery.bindValue(":port_pathname", cwKeyProfile.portPath); insertQuery.bindValue(":baudrate", cwKeyProfile.baudrate); insertQuery.bindValue(":hostname", cwKeyProfile.hostname); insertQuery.bindValue(":netport", cwKeyProfile.netport); insertQuery.bindValue(":paddle_swap", cwKeyProfile.paddleSwap); insertQuery.bindValue(":paddle_only_sidetone", cwKeyProfile.paddleOnlySidetone); insertQuery.bindValue(":sidetone_frequency", cwKeyProfile.sidetoneFrequency); if ( ! insertQuery.exec() ) { qInfo() << "CW Key Profile DB insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); } } } else { qInfo() << "CW Key Profile DB delete error " << deleteQuery.lastError().text(); } saveCurProfile1(); } bool CWKeyProfile::operator==(const CWKeyProfile &profile) { return (profile.profileName == this->profileName && profile.model == this->model && profile.defaultSpeed == this->defaultSpeed && profile.keyMode == this->keyMode && profile.portPath == this->portPath && profile.baudrate == this->baudrate && profile.hostname == this->hostname && profile.netport == this->netport && profile.paddleSwap == this->paddleSwap && profile.paddleOnlySidetone == this->paddleOnlySidetone && profile.sidetoneFrequency == this->sidetoneFrequency); } bool CWKeyProfile::operator!=(const CWKeyProfile &profile) { return !operator==(profile); } foldynl-QLog-3252ff9/data/CWKeyProfile.h000066400000000000000000000032171517334601000177530ustar00rootroot00000000000000#ifndef QLOG_DATA_CWKEYPROFILE_H #define QLOG_DATA_CWKEYPROFILE_H #include #include #include #include "data/ProfileManager.h" #include "cwkey/drivers/CWKey.h" #define DEFAULT_CWKEY_MODEL 0 // this is a hack. We have non-empty text to set empty value in Setting dialog->Rig's Assigned CW Key combo // therefore QLog use one space as a profile that meams no CW is assigned to Rig #define EMPTY_PROFILE_NAME " " class CWKeyProfile { public: CWKeyProfile() : model(CWKey::DUMMY_KEYER), keyMode(CWKey::IAMBIC_B) { defaultSpeed = 0; baudrate = 0; netport = 0; paddleSwap = false; paddleOnlySidetone = false; sidetoneFrequency = 800; }; QString profileName; CWKey::CWKeyTypeID model; qint32 defaultSpeed; CWKey::CWKeyModeID keyMode; QString portPath; quint32 baudrate; QString hostname; quint16 netport; bool paddleSwap; bool paddleOnlySidetone; qint32 sidetoneFrequency; bool operator== (const CWKeyProfile &profile); bool operator!= (const CWKeyProfile &profile); private: friend QDataStream& operator<<(QDataStream& out, const CWKeyProfile& v); friend QDataStream& operator>>(QDataStream& in, CWKeyProfile& v); }; Q_DECLARE_METATYPE(CWKeyProfile); class CWKeyProfilesManager : public ProfileManagerSQL { Q_OBJECT public: explicit CWKeyProfilesManager(); ~CWKeyProfilesManager() { }; static CWKeyProfilesManager* instance() { static CWKeyProfilesManager instance; return &instance; }; void save(); }; #endif // QLOG_DATA_CWKEYPROFILE_H foldynl-QLog-3252ff9/data/CWShortcutProfile.cpp000066400000000000000000000102261517334601000213670ustar00rootroot00000000000000#include #include #include "CWShortcutProfile.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.data.cwshortcutprofile"); QDataStream& operator<<(QDataStream& out, const CWShortcutProfile& v) { out << v.profileName; for( int i = 0; i < v.shortDescs.size(); i++ ) { out << v.shortDescs[i]; } for( int i = 0; i < v.macros.size(); i++ ) { out << v.macros[i]; } return out; } QDataStream& operator>>(QDataStream& in, CWShortcutProfile& v) { in >> v.profileName; for( int i = 0; i < v.shortDescs.size(); i++ ) { in >> v.shortDescs[i]; } for( int i = 0; i < v.macros.size(); i++ ) { in >> v.macros[i]; } return in; } CWShortcutProfilesManager::CWShortcutProfilesManager() : ProfileManagerSQL("cwshortcut_profiles") { FCT_IDENTIFICATION; QSqlQuery profileQuery; if ( ! profileQuery.prepare("SELECT profile_name, f1_short, f1_macro, f2_short, f2_macro, " "f3_short, f3_macro, f4_short, f4_macro, f5_short, f5_macro, " "f6_short, f6_macro, f7_short, f7_macro FROM cwshortcut_profiles") ) { qWarning()<< "Cannot prepare select"; } if ( profileQuery.exec() ) { while (profileQuery.next()) { CWShortcutProfile profileDB; int column = 0; profileDB.profileName = profileQuery.value(column++).toString(); for ( int i = 0; i < profileDB.shortDescs.size(); i++ ) { profileDB.shortDescs[i] = profileQuery.value(column++).toString(); profileDB.macros[i] = profileQuery.value(column++).toString(); } addProfile(profileDB.profileName, profileDB); } } else { qInfo() << "CW Shortcut Profile DB select error " << profileQuery.lastError().text(); } } void CWShortcutProfilesManager::save() { FCT_IDENTIFICATION; QSqlQuery deleteQuery; QSqlQuery insertQuery; if ( ! deleteQuery.prepare("DELETE FROM cwshortcut_profiles") ) { qWarning() << "Cannot prepare Delete statement"; return; } if ( ! insertQuery.prepare("INSERT INTO cwshortcut_profiles(profile_name, f1_short, f1_macro, f2_short, f2_macro," "f3_short, f3_macro, f4_short, f4_macro, f5_short, f5_macro," "f6_short, f6_macro, f7_short, f7_macro)" "VALUES (:profile_name, :f1_short, :f1_macro, :f2_short, :f2_macro," ":f3_short, :f3_macro, :f4_short, :f4_macro, :f5_short, :f5_macro," ":f6_short, :f6_macro, :f7_short, :f7_macro)") ) { qWarning() << "Cannot prepare Insert statement"; return; } if ( deleteQuery.exec() ) { const QStringList &keys = profileNameList(); for ( const QString &key: keys ) { const CWShortcutProfile &cwShortcutProfile = getProfile(key); insertQuery.bindValue(":profile_name", key); for ( int i = 0; i < cwShortcutProfile.shortDescs.size(); i++ ) { insertQuery.bindValue(QString(":f%1_short").arg(i+1), cwShortcutProfile.shortDescs[i]); } for ( int i = 0; i < cwShortcutProfile.macros.size(); i++ ) { insertQuery.bindValue(QString(":f%1_macro").arg(i+1), cwShortcutProfile.macros[i]); } if ( ! insertQuery.exec() ) { qInfo() << "CW Shortcut Profile DB insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); } } } else { qInfo() << "CW Shortcut Profile DB delete error " << deleteQuery.lastError().text(); } saveCurProfile1(); } bool CWShortcutProfile::operator==(const CWShortcutProfile &profile) { return (profile.profileName == this->profileName && profile.shortDescs == this->shortDescs && profile.macros == this->macros); } bool CWShortcutProfile::operator!=(const CWShortcutProfile &profile) { return !operator==(profile); } foldynl-QLog-3252ff9/data/CWShortcutProfile.h000066400000000000000000000022061517334601000210330ustar00rootroot00000000000000#ifndef QLOG_DATA_CWSHORTCUTPROFILE_H #define QLOG_DATA_CWSHORTCUTPROFILE_H #include #include #include #include "data/ProfileManager.h" #define MAX_SHORTCUT_KEYS 7 class CWShortcutProfile { public: CWShortcutProfile() { shortDescs.resize(MAX_SHORTCUT_KEYS); macros.resize(MAX_SHORTCUT_KEYS); }; QString profileName; QVector shortDescs; QVector macros; bool operator== (const CWShortcutProfile &profile); bool operator!= (const CWShortcutProfile &profile); private: friend QDataStream& operator<<(QDataStream& out, const CWShortcutProfile& v); friend QDataStream& operator>>(QDataStream& in, CWShortcutProfile& v); }; Q_DECLARE_METATYPE(CWShortcutProfile); class CWShortcutProfilesManager : public ProfileManagerSQL { Q_OBJECT public: explicit CWShortcutProfilesManager(); ~CWShortcutProfilesManager() { }; static CWShortcutProfilesManager* instance() { static CWShortcutProfilesManager instance; return &instance; }; void save(); }; #endif // QLOG_DATA_CWSHORTCUTPROFILE_H foldynl-QLog-3252ff9/data/Callsign.cpp000066400000000000000000000122711517334601000175370ustar00rootroot00000000000000#include "Callsign.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.callsign"); Callsign::Callsign(const QString &callsign, QObject *parent) : QObject{parent}, fullCallsign(callsign.toUpper()), valid(false) { FCT_IDENTIFICATION; QRegularExpression callsignRE = callsignRegEx(); QRegularExpressionMatch match = callsignRE.match(fullCallsign); if ( match.hasMatch() ) { //it is a valid callsign valid = true; hostPrefixWithDelimiter = match.captured(1); hostPrefix = match.captured(2); base = match.captured(3); basePrefix = match.captured(4); basePrefixNumber = match.captured(5); suffixWithDelimiter = match.captured(7); suffix = match.captured(8); qCDebug(runtime) << hostPrefix << base << suffix; } else { //it is an invalid callsign fullCallsign = QString(); } } const QRegularExpression Callsign::callsignRegEx() { FCT_IDENTIFICATION; return QRegularExpression(callsignRegExString(), QRegularExpression::CaseInsensitiveOption); } const QString Callsign::callsignRegExString() { FCT_IDENTIFICATION; return QString("^(([A-Z0-9]+)[\\/])?(([A-Z][0-9]|[A-Z]{1,2}|[0-9][A-Z])([0-9]|[0-9]+)([A-Z]+))([\\/]([A-Z0-9]+))?"); } const QString Callsign::getCallsign() const { FCT_IDENTIFICATION; return fullCallsign; } const QString Callsign::getHostPrefix() const { FCT_IDENTIFICATION; return hostPrefix; } const QString Callsign::getHostPrefixWithDelimiter() const { FCT_IDENTIFICATION; return hostPrefixWithDelimiter; } const QString Callsign::getBase() const { FCT_IDENTIFICATION; return base; } const QString Callsign::getBasePrefix() const { FCT_IDENTIFICATION; return basePrefix; } const QString Callsign::getBasePrefixNumber() const { FCT_IDENTIFICATION; return basePrefixNumber; } const QString Callsign::getSuffix() const { FCT_IDENTIFICATION; return suffix; } const QString Callsign::getSuffixWithDelimiter() const { FCT_IDENTIFICATION; return suffixWithDelimiter; } const QString Callsign::getWPXPrefix() const { FCT_IDENTIFICATION; if ( !isValid() ) return QString(); // defined here // https://www.cqwpx.com/rules.htm // inspired here // https://git.fkurz.net/dj1yfk/yfklog/src/branch/develop/yfksubs.pl#L605 /********************* * ONLY BASE CALLSIGN *********************/ if ( getBase() != QString() && getHostPrefix() == QString() && getSuffix() == QString() ) { // only callsign // return callsign prefix + prefix number // OL80ABC -> OL80 // OK1ABC -> OK1 return getBasePrefix() + getBasePrefixNumber(); } /********************* * HOST PREFIX PRESENT *********************/ if ( getHostPrefix() != QString() ) { // callsign has a Host prefix SP/OK1XXX // we do not look at the suffix and assign automatically HostPrefix + '0' if ( getHostPrefix().back().isDigit() ) return getHostPrefix(); return getHostPrefix() + QString("0"); } /**************** * SUFFIX PRESENT ****************/ if ( getSuffix().length() == 1) // some countries add single numbers as suffix to designate a call area, e.g. /4 { bool isNumber = false; (void)suffix.toInt(&isNumber); if ( isNumber ) { // callsign suffix is a number // VE7ABC/2 -> VE2 return getBasePrefix() + getSuffix(); } // callsign suffix is not a number // OK1ABC/P -> OK1 return getBasePrefix() + getBasePrefixNumber(); } /*************************** * SUFFIX PRESENT LENGTH > 1 ***************************/ if ( secondarySpecialSuffixes.contains(getSuffix()) ) { // QRP, MM etc. // OK1ABC/AM -> OK1 return getBasePrefix() + getBasePrefixNumber(); } // valid prefix should contain a number in the last position - check it // and prefix is not just a number // N8ABC/KH9 -> KH9 bool isNumber = false; (void)getSuffix().toInt(&isNumber); if ( isNumber ) { // suffix contains 2 and more numbers - ignore it return getBasePrefix() + getBasePrefixNumber(); } // suffix is combination letters and digits and last position is a number if ( getSuffix().back().isDigit() ) return getSuffix(); // prefix does not contain a number - add "0" return getSuffix() + QString("0"); } bool Callsign::isValid() const { FCT_IDENTIFICATION; return valid; } // Based on wiki information // https://en.wikipedia.org/wiki/Amateur_radio_call_signs const QStringList Callsign::secondarySpecialSuffixes = { "A", // operator at a secondary location registered with the licensing authorities "AM", // aeronautical mobile "M", // mobile operation "MM", // marine mobile "P", // portable operation "QRP", // QRP - unofficial "R", // repeaters "B", // beacon "LGT" // 'LIGHTHOUSE' or 'LIGHTSHIP' - unofficial }; foldynl-QLog-3252ff9/data/Callsign.h000066400000000000000000000021151517334601000172000ustar00rootroot00000000000000#ifndef QLOG_DATA_CALLSIGN_H #define QLOG_DATA_CALLSIGN_H #include #include class Callsign : public QObject { Q_OBJECT public: explicit Callsign(const QString &callsign, QObject *parent = nullptr); static const QRegularExpression callsignRegEx(); static const QString callsignRegExString(); static const QStringList secondarySpecialSuffixes; const QString getCallsign() const; const QString getHostPrefix() const; const QString getHostPrefixWithDelimiter() const; const QString getBase() const; const QString getBasePrefix() const; const QString getBasePrefixNumber() const; const QString getSuffix() const; const QString getSuffixWithDelimiter() const; const QString getWPXPrefix() const; bool isValid() const; private: QString fullCallsign; QString hostPrefix; QString hostPrefixWithDelimiter; QString base; QString basePrefix; QString basePrefixNumber; QString suffix; QString suffixWithDelimiter; bool valid; }; #endif // QLOG_DATA_CALLSIGN_H foldynl-QLog-3252ff9/data/Data.cpp000066400000000000000000001347261517334601000166660ustar00rootroot00000000000000#include #include #include #include #include #include "Data.h" #include "data/Callsign.h" #include "core/debug.h" #include "BandPlan.h" #include "data/StationProfile.h" #include "core/LogParam.h" MODULE_IDENTIFICATION("qlog.data.data"); Data::Data(QObject *parent) : QObject(parent), zd(nullptr), isDXCCQueryValid(false) { FCT_IDENTIFICATION; loadContests(); loadPropagationModes(); loadLegacyModes(); loadDxccFlags(); loadSatModes(); loadIOTA(); loadSOTA(); loadWWFF(); loadPOTA(); loadTZ(); // dxcc_prefixes_ad1c.exact DESC, dxcc_prefixes_ad1c.prefix DESC // is used because it prefers an exact-match record over a partial-match records isDXCCQueryValid = queryDXCC.prepare( "SELECT " " dxcc_entities_ad1c.id, " " dxcc_entities_ad1c.name, " " dxcc_entities_ad1c.prefix, " " dxcc_entities_ad1c.cont, " " CASE " " WHEN (dxcc_prefixes_ad1c.cqz != 0) " " THEN dxcc_prefixes_ad1c.cqz " " ELSE dxcc_entities_ad1c.cqz " " END AS cqz, " " CASE " " WHEN (dxcc_prefixes_ad1c.ituz != 0) " " THEN dxcc_prefixes_ad1c.ituz " " ELSE dxcc_entities_ad1c.ituz " " END AS ituz , " " dxcc_entities_ad1c.lat, " " dxcc_entities_ad1c.lon, " " dxcc_entities_ad1c.tz, " " dxcc_prefixes_ad1c.exact " "FROM dxcc_prefixes_ad1c " "INNER JOIN dxcc_entities_ad1c ON (dxcc_prefixes_ad1c.dxcc = dxcc_entities_ad1c.id) " "WHERE (dxcc_prefixes_ad1c.prefix = :callsign and dxcc_prefixes_ad1c.exact = true) " " OR (dxcc_prefixes_ad1c.exact = false and :callsign LIKE dxcc_prefixes_ad1c.prefix || '%') " "ORDER BY dxcc_prefixes_ad1c.exact DESC, dxcc_prefixes_ad1c.prefix DESC " "LIMIT 1 " ); isDXCCClublogQueryValid = queryDXCCClublog.prepare( "SELECT e.id, " " e.name, " " e.prefix, " " e.cont, " " COALESCE(z.cqz, " " CASE WHEN (p.cqz != 0) THEN p.cqz ELSE e.cqz END) AS cqz, " " CASE WHEN z.cqz IS NOT NULL THEN NULL " " WHEN (p.ituz != 0) THEN p.ituz " " ELSE e.ituz END AS ituz, " " e.lat, " " e.lon, " " p.exact " " FROM dxcc_prefixes_clublog p" " INNER JOIN dxcc_entities_clublog e ON (p.dxcc = e.id) " " LEFT JOIN dxcc_zone_exceptions_clublog z ON ( z.call = :exactcall AND :dxccdate BETWEEN COALESCE(z.start, '0001-01-01 00:00:00') " " AND COALESCE(z.end, '9999-12-31 23:59:59')) " " WHERE ((p.prefix = :exactcall and p.exact = 1) " " OR (p.exact = 0 and :modifiedcall LIKE p.prefix || '%')) " " AND :dxccdate BETWEEN COALESCE(p.start, '0001-01-01 00:00:00') " " AND COALESCE(p.end, '9999-12-31 23:59:59') " " ORDER BY p.exact DESC, p.prefix DESC LIMIT 1" ); isDXCCIDAD1CQueryValid = queryDXCCIDAD1C.prepare( " SELECT dxcc_entities_ad1c.id, dxcc_entities_ad1c.name, dxcc_entities_ad1c.prefix, dxcc_entities_ad1c.cont, " " dxcc_entities_ad1c.cqz, dxcc_entities_ad1c.ituz, dxcc_entities_ad1c.lat, dxcc_entities_ad1c.lon, dxcc_entities_ad1c.tz " " FROM dxcc_entities_ad1c " " WHERE dxcc_entities_ad1c.id = :dxccid" ); isDXCCIDClublogQueryValid = queryDXCCIDClublog.prepare( " SELECT c.id, c.name, c.prefix, c.cont, " " c.cqz, c.ituz, c.lat, c.lon " " FROM dxcc_entities_clublog c " " WHERE c.id = :dxccid" ); isSOTAQueryValid = querySOTA.prepare( "SELECT summit_code," " association_name," " region_name," " summit_name," " altm," " altft," " gridref1," " gridref2," " longitude," " latitude," " points," " bonus_points," " valid_from," " valid_to " "FROM sota_summits " "WHERE summit_code = :code" ); isPOTAQueryValid = queryPOTA.prepare( "SELECT reference," " name," " active," " entityID," " locationDesc," " latitude," " longitude," " grid " "FROM pota_directory " "WHERE reference = :code" ); isWWFFQueryValid = queryWWFF.prepare( "SELECT reference," " status," " name," " program," " dxcc," " state," " county," " continent," " iota," " iaruLocator," " latitude," " longitude," " iucncat," " valid_from," " valid_to " "FROM wwff_directory " "WHERE reference = :reference" ); } Data::~Data() { FCT_IDENTIFICATION; if ( zd ) { ZDCloseDatabase(zd); } } #define RETCODE(a) \ dxccStatusCache.insert(dxcc, myDXCC, band, mode, new DxccStatus(a)); \ return ((a)); DxccStatus Data::dxccStatus(int dxcc, const QString &band, const QString &mode) { FCT_IDENTIFICATION; qCDebug(function_parameters) << dxcc << " " << band << " " << mode; const int myDXCC = StationProfilesManager::instance()->getCurProfile1().dxcc; DxccStatus *statusFromCache = dxccStatusCache.value(dxcc, myDXCC, band, mode); if ( statusFromCache ) return *statusFromCache; // FTx modes (FT8, FT4, FT2) are stored in contacts with modes.dxcc = 'DIGITAL', // so we use DIGITAL as the effective mode group when querying for FTx. const QString modeForQuery = ( mode == BandPlan::MODE_GROUP_STRING_FTx ) ? BandPlan::MODE_GROUP_STRING_DIGITAL : mode; QString sql_mode(":mode"); if ( modeForQuery != BandPlan::MODE_GROUP_STRING_CW && modeForQuery != BandPlan::MODE_GROUP_STRING_PHONE && modeForQuery != BandPlan::MODE_GROUP_STRING_DIGITAL ) { sql_mode = "(SELECT modes.dxcc FROM modes WHERE modes.name = :mode LIMIT 1) "; } QStringList dxccConfirmedByCond(QLatin1String("0=1")); // if no option is selected then always false if ( LogParam::getDxccConfirmedByLotwState() ) dxccConfirmedByCond << QLatin1String("all_dxcc_qsos.lotw_qsl_rcvd = 'Y'"); if ( LogParam::getDxccConfirmedByPaperState() ) dxccConfirmedByCond << QLatin1String("all_dxcc_qsos.qsl_rcvd = 'Y'"); if ( LogParam::getDxccConfirmedByEqslState() ) dxccConfirmedByCond << QLatin1String("all_dxcc_qsos.eqsl_qsl_rcvd = 'Y'"); QSqlQuery query; QString sqlStatement = QString("WITH all_dxcc_qsos AS (SELECT DISTINCT contacts.mode, contacts.band, " " contacts.qsl_rcvd, contacts.lotw_qsl_rcvd, contacts.eqsl_qsl_rcvd " " FROM contacts " " WHERE dxcc = :dxcc %1) " " SELECT (SELECT 1 FROM all_dxcc_qsos LIMIT 1) as entity," " (SELECT 1 FROM all_dxcc_qsos WHERE band = :band LIMIT 1) as band, " " (SELECT 1 FROM all_dxcc_qsos INNER JOIN modes ON (modes.name = all_dxcc_qsos.mode) " " WHERE modes.dxcc = %2 LIMIT 1) as mode, " " (SELECT 1 FROM all_dxcc_qsos INNER JOIN modes ON (modes.name = all_dxcc_qsos.mode) " " WHERE modes.dxcc = %3 AND all_dxcc_qsos.band = :band LIMIT 1) as slot, " " (SELECT 1 FROM all_dxcc_qsos INNER JOIN modes ON (modes.name = all_dxcc_qsos.mode) " " WHERE modes.dxcc = %4 AND all_dxcc_qsos.band = :band " " AND (%5) LIMIT 1) as confirmed") .arg(( myDXCC != 0 ) ? QString(" AND my_dxcc = %1").arg(myDXCC) : "", sql_mode, sql_mode, sql_mode, dxccConfirmedByCond.join(" OR ")); if ( ! query.prepare(sqlStatement) ) { qWarning() << "Cannot prepare Select statement"; return DxccStatus::UnknownStatus; } query.bindValue(":dxcc", dxcc); query.bindValue(":band", band); query.bindValue(":mode", modeForQuery); if ( ! query.exec() ) { qWarning() << "Cannot execute Select statement" << query.lastError(); return DxccStatus::UnknownStatus; } if ( query.next() ) { if ( query.value(0).toString().isEmpty() ) { RETCODE(DxccStatus::NewEntity); } if ( query.value(1).toString().isEmpty() ) { if ( query.value(2).toString().isEmpty() ) { RETCODE(DxccStatus::NewBandMode); } else { RETCODE(DxccStatus::NewBand); } } if ( query.value(2).toString().isEmpty() ) { RETCODE(DxccStatus::NewMode); } if ( query.value(3).toString().isEmpty() ) { RETCODE(DxccStatus::NewSlot); } if ( query.value(4).toString().isEmpty() ) { RETCODE(DxccStatus::Worked); } else { RETCODE(DxccStatus::Confirmed); } } RETCODE(DxccStatus::UnknownStatus); } #undef RETCODE QStringList Data::contestList() { FCT_IDENTIFICATION; QStringList contestLOV; QSqlQuery query(QLatin1String("SELECT DISTINCT contest_id FROM contacts ORDER BY 1 COLLATE LOCALEAWARE ASC")); while ( query.next() ) contestLOV << query.value(0).toString(); return contestLOV + contests.keys(); } #define RETURNCODE(a) \ qCDebug(runtime) << "new DXCC Status: " << (a); \ return ((a)) DxccStatus Data::dxccNewStatusWhenQSOAdded(const DxccStatus &oldStatus, const qint32 oldDxcc, const QString &oldBand, const QString &oldMode, const qint32 newDxcc, const QString &newBand, const QString &newMode) { FCT_IDENTIFICATION; qCDebug(function_parameters) << oldStatus << oldDxcc << oldBand << oldMode << newDxcc << newBand << newMode; if ( oldDxcc != newDxcc ) { /* No change */ RETURNCODE(oldStatus); } if ( oldBand == newBand && oldMode == newMode ) { if ( oldStatus < DxccStatus::Worked ) { RETURNCODE(DxccStatus::Worked); } else { RETURNCODE(oldStatus); } } /*************/ /* NewEntity */ /*************/ if ( oldStatus == DxccStatus::NewEntity ) { if ( oldBand != newBand && oldMode != newMode ) { RETURNCODE(DxccStatus::NewBandMode); } if ( oldBand != newBand && oldMode == newMode ) { RETURNCODE(DxccStatus::NewBand); } if ( oldBand == newBand && oldMode != newMode ) { RETURNCODE(DxccStatus::NewMode); } } /***************/ /* NewBandMode */ /***************/ if ( oldStatus == DxccStatus::NewBandMode ) { if ( oldBand != newBand && oldMode != newMode ) { RETURNCODE(DxccStatus::NewBandMode); } if ( oldBand != newBand && oldMode == newMode ) { RETURNCODE(DxccStatus::NewBand); } if ( oldBand == newBand && oldMode != newMode ) { RETURNCODE(DxccStatus::NewMode); } } /*************/ /* NewBand */ /*************/ if ( oldStatus == DxccStatus::NewBand ) { if ( oldBand != newBand && oldMode != newMode ) { RETURNCODE(DxccStatus::NewBand); } if ( oldBand != newBand && oldMode == newMode ) { RETURNCODE(DxccStatus::NewBand); } if ( oldBand == newBand && oldMode != newMode ) { RETURNCODE(DxccStatus::NewSlot); } } /*************/ /* NewMode */ /*************/ if ( oldStatus == DxccStatus::NewMode ) { if ( oldBand != newBand && oldMode != newMode ) { RETURNCODE(DxccStatus::NewMode); } if ( oldBand != newBand && oldMode == newMode ) { RETURNCODE(DxccStatus::NewSlot); } if ( oldBand == newBand && oldMode != newMode ) { RETURNCODE(DxccStatus::NewMode); } } /*************/ /* NewSlot */ /*************/ if ( oldStatus == DxccStatus::NewSlot ) { RETURNCODE(DxccStatus::NewSlot); } /*************/ /* Worked */ /*************/ if ( oldStatus == DxccStatus::Worked ) { RETURNCODE(DxccStatus::Worked); } /***************/ /* Confirmed */ /***************/ if ( oldStatus == DxccStatus::Confirmed ) { RETURNCODE(DxccStatus::Confirmed); } RETURNCODE(DxccStatus::UnknownStatus); } qulonglong Data::dupeNewCountWhenQSOAdded(qulonglong oldCounter, const QString &oldBand, const QString &oldMode, const QString &addedBand, const QString &addedMode) { FCT_IDENTIFICATION; qCDebug(function_parameters) << oldCounter << oldBand << oldMode << addedBand << addedMode; int dupeType = LogParam::getContestDupeType(); const QString &contestID = LogParam::getContestID(); qCDebug(runtime) << dupeType << contestID; if ( contestID.isEmpty() ) return oldCounter; bool shouldIncrease = (dupeType == DupeType::ALL_BANDS) || (dupeType == DupeType::EACH_BAND && oldBand == addedBand) || (dupeType == DupeType::EACH_BAND_MODE && oldBand == addedBand && oldMode == addedMode); RETURNCODE( shouldIncrease ? oldCounter + 1 : oldCounter); } qulonglong Data::dupeNewCountWhenQSODelected(qulonglong oldCounter, const QString &oldBand, const QString &oldMode, const QString &deletedBand, const QString &deletedMode) { FCT_IDENTIFICATION; qCDebug(function_parameters) << oldCounter << oldBand << oldMode << deletedBand << deletedMode; if ( oldCounter == 0 ) return 0; int dupeType = LogParam::getContestDupeType(); const QString &contestID = LogParam::getContestID(); qCDebug(runtime) << dupeType << contestID; if ( contestID.isEmpty() ) return oldCounter; bool shouldDecrease = (dupeType == DupeType::ALL_BANDS) || (dupeType == DupeType::EACH_BAND && oldBand == deletedBand) || (dupeType == DupeType::EACH_BAND_MODE && oldBand == deletedBand && oldMode == deletedMode); RETURNCODE( shouldDecrease ? oldCounter - 1 : oldCounter); } #undef RETURNCODE QColor Data::statusToColor(const DxccStatus &status, bool isDupe, const QColor &defaultColor) { FCT_IDENTIFICATION; qCDebug(function_parameters) << status << isDupe; if ( isDupe ) return QColor(109, 109, 109, 100); switch (status) { case DxccStatus::NewEntity: return QColor(255, 58, 9); case DxccStatus::NewBand: case DxccStatus::NewMode: case DxccStatus::NewBandMode: return QColor(76, 200, 80); case DxccStatus::NewSlot: return QColor(30, 180, 230); case DxccStatus::Worked: return QColor(255,165,0); default: return defaultColor; } } QString Data::colorToHTMLColor(const QColor &in_color) { FCT_IDENTIFICATION; return in_color.name(QColor::HexRgb); } QString Data::statusToText(const DxccStatus &status) { FCT_IDENTIFICATION; qCDebug(function_parameters) << status; switch (status) { case DxccStatus::NewEntity: return tr("New Entity"); case DxccStatus::NewBand: return tr("New Band"); case DxccStatus::NewMode: return tr("New Mode"); case DxccStatus::NewBandMode: return tr("New Band&Mode"); case DxccStatus::NewSlot: return tr("New Slot"); case DxccStatus::Confirmed: return tr("Confirmed"); case DxccStatus::Worked: return tr("Worked"); default: return QString("Unknown"); } } int Data::getITUZMin() { FCT_IDENTIFICATION; qCDebug(runtime) << 1; return 1; } int Data::getITUZMax() { FCT_IDENTIFICATION; qCDebug(runtime) << 90; return 90; } int Data::getCQZMin() { FCT_IDENTIFICATION; qCDebug(runtime) << 1; return 1; } int Data::getCQZMax() { FCT_IDENTIFICATION; qCDebug(runtime) << 40; return 40; } QString Data::debugFilename() { QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); const QString debugFilename = "qlog_debug_" + QDateTime::currentDateTime().toString("yyyyMMddhhmmss") + ".log"; return dir.filePath(debugFilename); } double Data::MHz2UserFriendlyFreq(double freqMHz, QString &unit, unsigned char &efectiveDecP) { FCT_IDENTIFICATION; if ( freqMHz < 0.001 ) { unit = tr("Hz"); efectiveDecP = 0; return freqMHz * 1000000.0; } if ( freqMHz < 1 ) { unit = tr("kHz"); efectiveDecP = 3; return freqMHz * 1000.0; } if ( freqMHz >= 1000 ) { unit = tr("GHz"); efectiveDecP = 3; return freqMHz / 1000.0; } unit = tr("MHz"); efectiveDecP = 3; return freqMHz; } const QStringList &Data::getContinentList() { static const QStringList continents{"AF", "AN", "AS", "EU", "NA", "OC", "SA"}; return continents; } QPair Data::legacyMode(const QString &mode) { FCT_IDENTIFICATION; // used in the case of external programs that generate an invalid ADIF modes. // Database Mode Table cannot be used because these programs have different mode-strings. qCDebug(function_parameters) << mode; return legacyModes.value(mode); } QString Data::getIANATimeZone(double lat, double lon) { FCT_IDENTIFICATION; qCDebug(function_parameters) << lat << lon; QString ret; if ( zd ) { ret = ZDHelperSimpleLookupString(zd, static_cast(lat), static_cast(lon)); } qCDebug(runtime) << ret; return ret; } QStringList Data::sigIDList() { FCT_IDENTIFICATION; QStringList sigLOV; QSqlQuery query(QLatin1String("SELECT DISTINCT sig_intl FROM contacts")); while ( query.next() ) sigLOV << query.value(0).toString(); return sigLOV; } void Data::invalidateDXCCStatusCache(const QSqlRecord &record) { FCT_IDENTIFICATION; dxccStatusCache.invalidate(record.value("dxcc").toInt(), StationProfilesManager::instance()->getCurProfile1().dxcc); } void Data::invalidateSetOfDXCCStatusCache(const QSet &entities) { FCT_IDENTIFICATION; int myDXCC = StationProfilesManager::instance()->getCurProfile1().dxcc; for ( uint entity : entities ) dxccStatusCache.invalidate(entity, myDXCC); } void Data::clearDXCCStatusCache() { FCT_IDENTIFICATION; dxccStatusCache.clear(); } qulonglong Data::countDupe(const QString &callsign, const QString &band, const QString &mode) { FCT_IDENTIFICATION; qCDebug(function_parameters) << callsign << band << mode; int dupeType = LogParam::getContestDupeType(); const QString &contestID = LogParam::getContestID(); const QDateTime &dupeStartTime = LogParam::getContestDupeDate(); qCDebug(runtime) << dupeType << dupeStartTime << contestID; if ( contestID.isEmpty() || dupeType == DupeType::NO_CHECK || !dupeStartTime.isValid() ) return false; QStringList whereClause = { "callsign = :callsign", "contest_id = :contestid" }; if ( dupeType >= DupeType::ALL_BANDS ) whereClause << QLatin1String("datetime(start_time) >= datetime(:date)"); if ( dupeType >= DupeType::EACH_BAND) whereClause << QLatin1String("band = :band"); // FTx modes are stored with modes.dxcc = 'DIGITAL', so map FTx to DIGITAL. const QString modeForQuery = ( mode == BandPlan::MODE_GROUP_STRING_FTx ) ? BandPlan::MODE_GROUP_STRING_DIGITAL : mode; if ( dupeType >= DupeType::EACH_BAND_MODE ) { QString sql_mode = (modeForQuery != BandPlan::MODE_GROUP_STRING_CW && modeForQuery != BandPlan::MODE_GROUP_STRING_PHONE && modeForQuery != BandPlan::MODE_GROUP_STRING_DIGITAL) ? "(SELECT modes.dxcc FROM modes WHERE modes.name = :mode LIMIT 1)" : ":mode"; whereClause << QString("m.dxcc = %1").arg(sql_mode); } QString queryString("SELECT COUNT(1) " "FROM contacts c " "INNER JOIN modes m ON (m.name = c.mode) " "WHERE %1 "); QSqlQuery query; if ( ! query.prepare(queryString.arg(whereClause.join(" AND ")))) { qWarning() << "Cannot prepare Select statement" << queryString.arg(whereClause.join(" AND ")); return false; } query.bindValue(":callsign", callsign); query.bindValue(":date", dupeStartTime); query.bindValue(":band", band); query.bindValue(":mode", modeForQuery); query.bindValue(":contestid", contestID); if ( ! query.exec() ) { qWarning() << "Cannot execute Select statement" << query.lastError() << query.lastQuery(); return false; } return (query.first()) ? query.value(0).toULongLong() : 0ULL; } QString Data::safeQueryString(const QUrlQuery &query) { FCT_IDENTIFICATION; QUrlQuery safe; const QList> &items = query.queryItems(QUrl::FullyDecoded); for ( const auto &item : items ) { if ( item.first.compare("password", Qt::CaseInsensitive) == 0 || item.first.compare("code", Qt::CaseInsensitive) == 0) safe.addQueryItem(item.first, "***MASKED***"); else safe.addQueryItem(item.first, item.second); } return safe.query(QUrl::FullyEncoded); } void Data::loadContests() { FCT_IDENTIFICATION; QFile file(":/res/data/contests.json"); file.open(QIODevice::ReadOnly | QIODevice::Text); QByteArray data = file.readAll(); const QList objectList = QJsonDocument::fromJson(data).toVariant().toList(); for ( const QVariant &object : objectList ) { const QVariantMap &contestData = object.toMap(); const QString &id = contestData.value("id").toString(); const QString &name = contestData.value("name").toString(); contests.insert(id, name); } } void Data::loadPropagationModes() { FCT_IDENTIFICATION; QFile file(":/res/data/propagation_modes.json"); file.open(QIODevice::ReadOnly | QIODevice::Text); QByteArray data = file.readAll(); const QList objects = QJsonDocument::fromJson(data).toVariant().toList(); for ( const QVariant &object : objects ) { const QVariantMap &propagationModeData = object.toMap(); const QString &id = propagationModeData.value("id").toString(); const QString &name = tr(propagationModeData.value("name").toString().toUtf8().constData()); propagationModes.insert(id, name); } } void Data::loadLegacyModes() { FCT_IDENTIFICATION; // Load conversion table from non-ADIF mode to ADIF mode/submode // used in the case of external programs that generate an invalid ADIF modes. // Database Mode Table cannot be used because these programs have different mode-strings. QFile file(":/res/data/legacy_modes.json"); file.open(QIODevice::ReadOnly | QIODevice::Text); QByteArray data = file.readAll(); QVariantMap extModes = QJsonDocument::fromJson(data).toVariant().toMap(); const QList keys = extModes.keys(); for ( const QString &key : keys ) { const QVariantMap &legacyModeData = extModes[key].toMap(); const QString &mode = legacyModeData.value("mode").toString(); const QString &submode = legacyModeData.value("submode").toString(); QPair modes = QPair(mode, submode); legacyModes.insert(key, modes); } } void Data::loadDxccFlags() { FCT_IDENTIFICATION; QFile file(":/res/data/dxcc.json"); file.open(QIODevice::ReadOnly | QIODevice::Text); QByteArray data = file.readAll(); const QList &objects = QJsonDocument::fromJson(data).toVariant().toList(); for ( const QVariant &object : objects ) { const QVariantMap &dxccData = object.toMap(); int id = dxccData.value("id").toInt(); dxccEntityStaticInfo.insert(id, dxccData); } } void Data::loadSatModes() { FCT_IDENTIFICATION; QFile file(":/res/data/sat_modes.json"); file.open(QIODevice::ReadOnly | QIODevice::Text); QByteArray data = file.readAll(); const QList &objects = QJsonDocument::fromJson(data).toVariant().toList(); for ( const QVariant &object : objects ) { const QVariantMap &satModesData = object.toMap(); const QString &id = satModesData.value("id").toString(); const QString &name = satModesData.value("name").toString(); satModes.insert(id, name); } } void Data::loadIOTA() { FCT_IDENTIFICATION; QSqlQuery query("SELECT iotaid, islandname FROM iota"); while ( query.next() ) { const QString &iotaID = query.value(0).toString(); const QString &islandName = query.value(1).toString(); iotaRef.insert(iotaID, islandName); } } void Data::loadSOTA() { FCT_IDENTIFICATION; QSqlQuery query("SELECT summit_code FROM sota_summits"); while ( query.next() ) { const QString &summitCode = query.value(0).toString(); sotaRefID.insert(summitCode, QString()); } } void Data::loadWWFF() { QSqlQuery query("SELECT reference FROM wwff_directory"); while ( query.next() ) { const QString &reference = query.value(0).toString(); wwffRefID.insert(reference, QString()); } } void Data::loadPOTA() { FCT_IDENTIFICATION; QSqlQuery query("SELECT reference FROM pota_directory"); while ( query.next() ) { const QString &reference = query.value(0).toString(); potaRefID.insert(reference, QString()); } } QCompleter* Data::createCountyCompleter(int dxcc, QObject *parent) { FCT_IDENTIFICATION; QSqlQuery query; if ( dxcc != 0 ) { query.prepare("SELECT code FROM adif_enum_secondary_subdivision " "WHERE dxcc = :dxcc ORDER BY code"); query.bindValue(":dxcc", dxcc); } else query.prepare("SELECT code FROM adif_enum_secondary_subdivision ORDER BY code"); if ( !query.exec() ) { qCWarning(runtime) << query.lastError().text(); return nullptr; } QStringList list; while ( query.next() ) list << query.value(0).toString(); if ( list.isEmpty() ) return nullptr; QCompleter *completer = new QCompleter(list, parent); completer->setCaseSensitivity(Qt::CaseInsensitive); completer->setFilterMode(Qt::MatchStartsWith); completer->setModelSorting(QCompleter::CaseSensitivelySortedModel); return completer; } void Data::loadTZ() { FCT_IDENTIFICATION; QFile file (":/res/data/timezone21.bin"); file.open(QIODevice::ReadOnly); uchar *tzMap = file.map(0, file.size()); if ( tzMap ) { zd = ZDOpenDatabaseFromMemory(tzMap, file.size()); if ( !zd ) { qWarning() << "Cannot open TZ Database"; } } else { qWarning() << "Cannot map TZ File to memory"; } } DxccEntity Data::lookupDxcc(const QString &callsign) { FCT_IDENTIFICATION; #if 0 //qInfo() << "Start AD1C"; DxccEntity ad1cDXCCData = lookupDxccAD1C(callsign); //qInfo() << "Finished AD1C"; DxccEntity clublogDXCCData = lookupDxccClublog(callsign); //qInfo() << "Finished Clublog"; if ( ad1cDXCCData.dxcc != clublogDXCCData.dxcc || ad1cDXCCData.cqz != clublogDXCCData.cqz || ad1cDXCCData.ituz != clublogDXCCData.ituz) { qInfo(runtime) << "DIFF for call " << callsign << "AD1C:" << ad1cDXCCData.dxcc << ad1cDXCCData.cqz << ad1cDXCCData.ituz << "Clublog:" << clublogDXCCData.dxcc << clublogDXCCData.cqz << clublogDXCCData.ituz; } //qInfo() << "AD1C:" << ad1cDXCCData.dxcc << ad1cDXCCData.cqz << ad1cDXCCData.ituz // << "Clublog:" << clublogDXCCData.dxcc << clublogDXCCData.cqz << clublogDXCCData.ituz; return ad1cDXCCData; #else // LF: The AD1C method seems more accurate for current data regarding ITU and CQZ. // The Clublog method is good for determining historical data and CQZ, but unfortunately, // the ITU zone is not reliable in this method because it’s not listed and has to be // calculated. Therefore, I decided to use the AD1C method as the general approach and only // use Clublog in exceptional cases. Once Clublog starts distributing ITUZ, we should // completely switch to the Clublog method. // I also believes that the AD1C method is more accurate in determining special exceptions // for American callsigns. return lookupDxccAD1C(callsign); #endif } DxccEntity Data::lookupDxccAD1C(const QString &callsign) { FCT_IDENTIFICATION; static QCache localCache(1000); qCDebug(function_parameters) << callsign; if ( callsign.isEmpty()) return DxccEntity(); DxccEntity dxccRet; DxccEntity *dxccCached = localCache.object(callsign); if ( dxccCached ) { dxccRet = *dxccCached; } else { if ( ! isDXCCQueryValid ) { qWarning() << "Cannot prepare Select statement"; return DxccEntity(); } QString lookupPrefix = callsign; // use the callsign with optional prefix as default to find the dxcc const Callsign parsedCallsign(callsign); // use Callsign to split the callsign into its parts if ( parsedCallsign.isValid() ) { QString suffix = parsedCallsign.getSuffix(); if ( suffix.length() == 1 ) // some countries add single numbers as suffix to designate a call area, e.g. /4 { bool isNumber = false; (void)suffix.toInt(&isNumber); if ( isNumber ) { lookupPrefix = parsedCallsign.getBasePrefix() + suffix; // use the call prefix and the number from the suffix to find the dxcc } } else if ( suffix.length() > 1 && !parsedCallsign.secondarySpecialSuffixes.contains(suffix) ) // if there is more than one character and it is not one of the special suffixes, we definitely have a call prefix as suffix { lookupPrefix = suffix; } } queryDXCC.bindValue(":callsign", lookupPrefix); if ( ! queryDXCC.exec() ) { qWarning() << "Cannot execute Select statement" << queryDXCC.lastError() << queryDXCC.lastQuery(); return DxccEntity(); } if ( queryDXCC.next() ) { dxccRet.dxcc = queryDXCC.value(0).toInt(); dxccRet.country = queryDXCC.value(1).toString(); dxccRet.prefix = queryDXCC.value(2).toString(); dxccRet.cont = queryDXCC.value(3).toString(); dxccRet.cqz = queryDXCC.value(4).toInt(); dxccRet.ituz = queryDXCC.value(5).toInt(); dxccRet.latlon[0] = queryDXCC.value(6).toDouble(); dxccRet.latlon[1] = queryDXCC.value(7).toDouble(); dxccRet.tz = queryDXCC.value(8).toFloat(); bool isExactMatch = queryDXCC.value(9).toBool(); dxccRet.flag = dxccFlag(dxccRet.dxcc); if ( !isExactMatch ) { // find the exceptions to the exceptions if ( dxccRet.prefix == "KG4" && parsedCallsign.getBase().size() != 5 ) { //only KG4AA - KG4ZZ are US Navy in Guantanamo Bay. Other KG4s are USA dxccRet = lookupDxccID(291); // USA //do not overwrite the original prefix dxccRet.prefix = "KG4"; } } dxccCached = new DxccEntity; if ( dxccCached ) { *dxccCached = dxccRet; localCache.insert(callsign, dxccCached); } } else { dxccRet.dxcc = 0; dxccRet.ituz = 0; dxccRet.cqz = 0; dxccRet.tz = 0; } } return dxccRet; } DxccEntity Data::lookupDxccIDAD1C(const int dxccID) { FCT_IDENTIFICATION; qCDebug(function_parameters) << dxccID; if ( !isDXCCIDAD1CQueryValid ) { qWarning() << "Cannot prepare Select statement"; return DxccEntity(); } queryDXCCIDAD1C.bindValue(":dxccid", dxccID); if ( ! queryDXCCIDAD1C.exec() ) { qWarning() << "Cannot execte Select statement" << queryDXCCIDAD1C.lastError(); return DxccEntity(); } DxccEntity dxccRet; if ( queryDXCCIDAD1C.next() ) { dxccRet.dxcc = queryDXCCIDAD1C.value(0).toInt(); dxccRet.country = queryDXCCIDAD1C.value(1).toString(); dxccRet.prefix = queryDXCCIDAD1C.value(2).toString(); dxccRet.cont = queryDXCCIDAD1C.value(3).toString(); dxccRet.cqz = queryDXCCIDAD1C.value(4).toInt(); dxccRet.ituz = queryDXCCIDAD1C.value(5).toInt(); dxccRet.latlon[0] = queryDXCCIDAD1C.value(6).toDouble(); dxccRet.latlon[1] = queryDXCCIDAD1C.value(7).toDouble(); dxccRet.tz = queryDXCCIDAD1C.value(8).toFloat(); dxccRet.flag = dxccFlag(dxccRet.dxcc); } else { dxccRet.dxcc = 0; dxccRet.ituz = 0; dxccRet.cqz = 0; dxccRet.tz = 0; } return dxccRet; } DxccEntity Data::lookupDxccIDClublog(const int dxccID) { FCT_IDENTIFICATION; qCDebug(function_parameters) << dxccID; if ( !isDXCCIDClublogQueryValid ) { qWarning() << "Cannot prepare Select statement"; return DxccEntity(); } queryDXCCIDClublog.bindValue(":dxccid", dxccID); if ( ! queryDXCCIDClublog.exec() ) { qWarning() << "Cannot execte Select statement" << queryDXCCIDClublog.lastError(); return DxccEntity(); } DxccEntity dxccRet; if ( queryDXCCIDClublog.next() ) { dxccRet.dxcc = queryDXCCIDClublog.value(0).toInt(); dxccRet.country = queryDXCCIDClublog.value(1).toString(); dxccRet.prefix = queryDXCCIDClublog.value(2).toString(); dxccRet.cont = queryDXCCIDClublog.value(3).toString(); dxccRet.cqz = queryDXCCIDClublog.value(4).toInt(); dxccRet.ituz = queryDXCCIDClublog.value(5).toInt(); dxccRet.latlon[0] = queryDXCCIDClublog.value(6).toDouble(); dxccRet.latlon[1] = queryDXCCIDClublog.value(7).toDouble(); dxccRet.tz = queryDXCCIDClublog.value(8).toFloat(); dxccRet.flag = dxccFlag(dxccRet.dxcc); } else { dxccRet.dxcc = 0; dxccRet.ituz = 0; dxccRet.cqz = 0; dxccRet.tz = 0; } return dxccRet; } DxccEntity Data::lookupDxccID(const int dxccID) { FCT_IDENTIFICATION; // LF: The AD1C method seems more accurate for current data regarding ITU and CQZ. // The Clublog method is good for determining historical data and CQZ, but unfortunately, // the ITU zone is not reliable in this method because it’s not listed and has to be // calculated. Therefore, I decided to use the AD1C method as the general approach and only // use Clublog in exceptional cases. Once Clublog starts distributing ITUZ, we should // completely switch to the Clublog method. // I also believes that the AD1C method is more accurate in determining special exceptions // for American callsigns. return lookupDxccIDAD1C(dxccID); } DxccEntity Data::lookupDxccClublog(const QString &callsign, const QDateTime &date) { FCT_IDENTIFICATION; qCDebug(function_parameters) << callsign; if ( callsign.isEmpty()) return DxccEntity(); if ( ! isDXCCClublogQueryValid ) { qWarning() << "Cannot prepare Select statement"; return DxccEntity(); } QString lookupPrefix = callsign; // use the callsign with optional prefix as default to find the dxcc const Callsign parsedCallsign(callsign); // use Callsign to split the callsign into its parts if ( parsedCallsign.isValid() ) { QString suffix = parsedCallsign.getSuffix(); if ( suffix.length() == 1 ) // some countries add single numbers as suffix to designate a call area, e.g. /4 { bool isNumber = false; (void)suffix.toInt(&isNumber); if ( isNumber ) { lookupPrefix = parsedCallsign.getBasePrefix() + suffix; // use the call prefix and the number from the suffix to find the dxcc } } else if ( suffix.length() > 1 && !parsedCallsign.secondarySpecialSuffixes.contains(suffix) ) // if there is more than one character and it is not one of the special suffixes, we definitely have a call prefix as suffix { lookupPrefix = suffix; } } queryDXCCClublog.bindValue(":modifiedcall", lookupPrefix); queryDXCCClublog.bindValue(":exactcall", callsign); queryDXCCClublog.bindValue(":dxccdate", date); if ( ! queryDXCCClublog.exec() ) { qWarning() << "Cannot execute Select statement" << queryDXCCClublog.lastError() << queryDXCCClublog.lastQuery(); return DxccEntity(); } DxccEntity dxccRet; const DxccEntity &ad1cDXCCData = lookupDxccAD1C(callsign); if ( queryDXCCClublog.first() ) { dxccRet.dxcc = queryDXCCClublog.value(0).toInt(); dxccRet.country = queryDXCCClublog.value(1).toString(); dxccRet.prefix = queryDXCCClublog.value(2).toString(); dxccRet.cont = queryDXCCClublog.value(3).toString(); dxccRet.cqz = queryDXCCClublog.value(4).toInt(); dxccRet.ituz = queryDXCCClublog.value(5).toInt(); dxccRet.latlon[0] = queryDXCCClublog.value(6).toDouble(); dxccRet.latlon[1] = queryDXCCClublog.value(7).toDouble(); dxccRet.tz = queryDXCCClublog.value(8).toFloat(); bool isExactMatch = queryDXCCClublog.value(9).toBool(); dxccRet.flag = dxccFlag(dxccRet.dxcc); if ( !isExactMatch ) { // find the exceptions to the exceptions if ( dxccRet.prefix == "KG4" && parsedCallsign.getBase().size() != 5 ) { //only KG4AA - KG4ZZ are US Navy in Guantanamo Bay. Other KG4s are USA dxccRet = lookupDxccID(291); // USA //do not overwrite the original prefix dxccRet.prefix = "KG4"; } } } else { qCDebug(runtime) << "DXCC not found for " << lookupPrefix << "; Using AD1C Info"; dxccRet = ad1cDXCCData; } if ( dxccRet.ituz == 0 ) { qCDebug(runtime) << "Zone exception, using AD1C Info Info to find ITUZ for " << callsign; if ( ad1cDXCCData.dxcc == dxccRet.dxcc && ad1cDXCCData.cqz == dxccRet.cqz ) { qCDebug(runtime) << "Fixing ITUZ for call" << callsign; dxccRet.ituz = ad1cDXCCData.ituz; } else { qCDebug(runtime) << "not match" << callsign << ad1cDXCCData.dxcc << dxccRet.dxcc << ad1cDXCCData.cqz << dxccRet.cqz; } } if ( ad1cDXCCData.dxcc == dxccRet.dxcc && ad1cDXCCData.cqz == dxccRet.cqz ) dxccRet.ituz = ad1cDXCCData.ituz; return dxccRet; } SOTAEntity Data::lookupSOTA(const QString &SOTACode) { FCT_IDENTIFICATION; if ( ! isSOTAQueryValid ) { qWarning() << "Cannot prepare Select statement"; return SOTAEntity(); } querySOTA.bindValue(":code", SOTACode.toUpper()); if ( ! querySOTA.exec() ) { qWarning() << "Cannot execte Select statement" << querySOTA.lastError(); return SOTAEntity(); } SOTAEntity SOTARet; if (querySOTA.next()) { SOTARet.summitCode = querySOTA.value(0).toString(); SOTARet.associationName = querySOTA.value(1).toString(); SOTARet.regionName = querySOTA.value(2).toString(); SOTARet.summitName = querySOTA.value(3).toString(); SOTARet.altm = querySOTA.value(4).toInt(); SOTARet.altft = querySOTA.value(5).toInt(); SOTARet.gridref1 = querySOTA.value(6).toDouble(); SOTARet.gridref2 = querySOTA.value(7).toDouble(); SOTARet.longitude = querySOTA.value(8).toDouble(); SOTARet.latitude = querySOTA.value(9).toDouble(); SOTARet.points = querySOTA.value(10).toInt(); SOTARet.bonusPoints = querySOTA.value(11).toInt(); SOTARet.validFrom = querySOTA.value(12).toDate(); SOTARet.validTo = querySOTA.value(13).toDate(); } else { SOTARet.altft = 0; SOTARet.altm = 0; SOTARet.gridref1 = 0.0; SOTARet.gridref2 = 0.0; SOTARet.longitude = 0.0; SOTARet.latitude = 0.0; SOTARet.points = 0; SOTARet.bonusPoints = 0; } return SOTARet; } POTAEntity Data::lookupPOTA(const QString &POTACode) { FCT_IDENTIFICATION; if ( ! isPOTAQueryValid ) { qWarning() << "Cannot prepare Select statement"; return POTAEntity(); } queryPOTA.bindValue(":code", POTACode.toUpper()); if ( ! queryPOTA.exec() ) { qWarning() << "Cannot execte Select statement" << queryPOTA.lastError(); return POTAEntity(); } POTAEntity POTARet; if (queryPOTA.next()) { POTARet.reference = queryPOTA.value(0).toString(); POTARet.name = queryPOTA.value(1).toString(); POTARet.active = queryPOTA.value(2).toBool(); POTARet.entityID = queryPOTA.value(3).toInt(); POTARet.locationDesc = queryPOTA.value(4).toString(); POTARet.longitude = queryPOTA.value(5).toDouble(); POTARet.latitude = queryPOTA.value(6).toDouble(); POTARet.grid = queryPOTA.value(7).toString(); } else { POTARet.active = false; POTARet.entityID = 0; POTARet.longitude = 0.0; POTARet.latitude = 0.0; } return POTARet; } WWFFEntity Data::lookupWWFF(const QString &reference) { FCT_IDENTIFICATION; if ( ! isWWFFQueryValid ) { qWarning() << "Cannot prepare Select statement"; return WWFFEntity(); } queryWWFF.bindValue(":reference", reference.toUpper()); if ( ! queryWWFF.exec() ) { qWarning() << "Cannot execte Select statement" << queryWWFF.lastError(); return WWFFEntity(); } WWFFEntity WWFFRet; if (queryWWFF.next()) { WWFFRet.reference = queryWWFF.value(0).toString(); WWFFRet.status = queryWWFF.value(1).toString(); WWFFRet.name = queryWWFF.value(2).toString(); WWFFRet.program = queryWWFF.value(3).toString(); WWFFRet.dxcc = queryWWFF.value(4).toString(); WWFFRet.state = queryWWFF.value(5).toString(); WWFFRet.county = queryWWFF.value(6).toString(); WWFFRet.continent = queryWWFF.value(7).toString(); WWFFRet.iota = queryWWFF.value(8).toString(); WWFFRet.iaruLocator = queryWWFF.value(9).toString(); WWFFRet.latitude = queryWWFF.value(10).toDouble(); WWFFRet.longitude = queryWWFF.value(11).toDouble(); WWFFRet.iucncat = queryWWFF.value(12).toString(); WWFFRet.validFrom = queryWWFF.value(13).toDate(); WWFFRet.validTo = queryWWFF.value(14).toDate(); } else { WWFFRet.longitude = 0.0; WWFFRet.latitude = 0.0; } return WWFFRet; } foldynl-QLog-3252ff9/data/Data.h000066400000000000000000000203631517334601000163220ustar00rootroot00000000000000#ifndef QLOG_DATA_DATA_H #define QLOG_DATA_DATA_H #include #include #include "Dxcc.h" #include "SOTAEntity.h" #include "WWFFEntity.h" #include "POTAEntity.h" #include "core/zonedetect.h" #include "core/QuadKeyCache.h" class QCompleter; class Data : public QObject { Q_OBJECT public: enum DupeType { ALL_BANDS = 1, EACH_BAND = 2, EACH_BAND_MODE = 3, NO_CHECK = 4 }; enum SeqType { SINGLE = 1, PER_BAND = 2 }; const QMap qslSentEnum = { {"Y", tr("Yes")}, {"N", tr("No")}, {"R", tr("Requested")}, {"Q", tr("Queued")}, {"I", tr("Invalid")} }; const QMap qslSentViaEnum = { {"B", tr("Bureau")}, {"D", tr("Direct")}, {"E", tr("Electronic")}, {" ", tr("Blank")} }; const QMap qslRcvdEnum = { {"Y", tr("Yes")}, {"N", tr("No")}, {"R", tr("Requested")}, {"I", tr("Invalid")} }; const QMap uploadStatusEnum = { {"Y", tr("Yes")}, {"N", tr("No")}, {"M", tr("Modified")}, {" ", tr("Blank")} }; const QMap antPathEnum = { {"G", tr("Grayline")}, {"O", tr("Other")}, {"S", tr("Short Path")}, {"L", tr("Long Path")}, {" ", tr("Blank")} }; const QMap boolEnum = { {"Y", tr("Yes")}, {"N", tr("No")}, {" ", tr("Blank")} }; const QMap qsoCompleteEnum = { {"Y", tr("Yes")}, {"N", tr("No")}, {"Nil", tr("Not Heard")}, {"?", tr("Uncertain")}, {" ", tr("Blank")} }; const QMap morseKeyTypeEnum = { {"SK", tr("Straight Key")}, {"SS", tr("Sideswiper")}, {"BUG", tr("Mechanical semi-automatic keyer or Bug")}, {"FAB", tr("Mechanical fully-automatic keyer or Bug")}, {"SP", tr("Single Paddle")}, {"DP", tr("Dual Paddle")}, {"CPU", tr("Computer Driven")}, {" ", tr("Blank")} }; const QMap downloadStatusEnum = { {"Y", tr("Yes")}, {"N", tr("No")}, {"I", tr("Invalid")}, {" ", tr("Blank")} }; const QMap eqslAgEnum = { {"Y", tr("Confirmed (AG)")}, {"N", tr("Confirmed (no AG)")}, {"U", tr("Unknown")}, {" ", tr("Blank")} }; explicit Data(QObject *parent = nullptr); ~Data(); static Data* instance() { static Data instance; return &instance; }; static DxccStatus dxccNewStatusWhenQSOAdded(const DxccStatus &oldStatus, const qint32 oldDxcc, const QString &oldBand, const QString &oldMode, const qint32 newDxcc, const QString &newBand, const QString &newMode); static qulonglong dupeNewCountWhenQSOAdded(qulonglong oldCounter, const QString &oldBand, const QString &oldMode, const QString &addedBand, const QString &addedMode); static qulonglong dupeNewCountWhenQSODelected(qulonglong oldCounter, const QString &oldBand, const QString &oldMode, const QString &deletedBand, const QString &deletedMode); static QColor statusToColor(const DxccStatus &status, bool isDupe, const QColor &defaultColor); static QString colorToHTMLColor(const QColor&); static QString statusToText(const DxccStatus &status); static QString removeAccents(const QString &input); static int getITUZMin(); static int getITUZMax(); static int getCQZMin(); static int getCQZMax(); static QString debugFilename(); static double MHz2UserFriendlyFreq(double, QString &unit, unsigned char &efectiveDecP); static const QStringList& getContinentList(); static qulonglong countDupe(const QString& callsign, const QString &band, const QString &mode); static QString safeQueryString(const QUrlQuery &query); DxccStatus dxccStatus(int dxcc, const QString &band, const QString &mode); QStringList contestList(); QStringList propagationModesList() const { return QStringList{""} + propagationModes.values(); } QStringList propagationModesIDList() const { return QStringList{""} + propagationModes.keys(); } QString propagationModeTextToID(const QString &propagationText) const { return propagationModes.key(propagationText);} QString propagationModeIDToText(const QString &propagationID) const { return propagationModes.value(propagationID);} DxccEntity lookupDxcc(const QString &callsign); DxccEntity lookupDxccID(const int dxccID); DxccEntity lookupDxccAD1C(const QString &callsign); DxccEntity lookupDxccIDAD1C(const int dxccID); DxccEntity lookupDxccClublog(const QString &callsign, const QDateTime &date = QDateTime::currentDateTimeUtc()); DxccEntity lookupDxccIDClublog(const int dxccID); SOTAEntity lookupSOTA(const QString &SOTACode); POTAEntity lookupPOTA(const QString &POTACode); WWFFEntity lookupWWFF(const QString &reference); const QString dxccFlag(int dxcc) const {return dxccEntityStaticInfo.value(dxcc).value("flag").toString();}; const QString dxccName(int dxcc) const {return dxccEntityStaticInfo.value(dxcc).value("name").toString();}; int dxccITUZ(int dxcc) const {return dxccEntityStaticInfo.value(dxcc).value("ituz").toInt();}; QPair legacyMode(const QString &mode); QStringList satModeList() { return satModes.values();} QStringList satModesIDList() { return satModes.keys(); } QString satModeTextToID(const QString &satModeText) { return satModes.key(satModeText);} QString satModeIDToText(const QString &satModeID) { return satModes.value(satModeID);} QStringList iotaList() { return iotaRef.values();} QStringList iotaIDList() { return iotaRef.keys();} QString iotaTextToID(const QString &iotaText) { return iotaRef.key(iotaText);} QStringList sotaIDList() { return sotaRefID.keys();} QStringList wwffIDList() { return wwffRefID.keys();} QStringList potaIDList() { return potaRefID.keys();} QString getIANATimeZone(double, double); QStringList sigIDList(); static QCompleter* createCountyCompleter(int dxcc, QObject *parent = nullptr); signals: public slots: void invalidateDXCCStatusCache(const QSqlRecord &record); void invalidateSetOfDXCCStatusCache(const QSet &entities); void clearDXCCStatusCache(); private: void loadContests(); void loadPropagationModes(); void loadLegacyModes(); void loadDxccFlags(); void loadSatModes(); void loadIOTA(); void loadSOTA(); void loadWWFF(); void loadPOTA(); void loadTZ(); QHash dxccEntityStaticInfo; QMap contests; QMap propagationModes; QMap> legacyModes; QMap satModes; QMap iotaRef; QMap sotaRefID; QMap wwffRefID; QMap potaRefID; ZoneDetect * zd; QSqlQuery queryDXCC; QSqlQuery queryDXCCIDAD1C; QSqlQuery queryDXCCIDClublog; QSqlQuery queryDXCCClublog; QSqlQuery querySOTA; QSqlQuery queryWWFF; QSqlQuery queryPOTA; bool isDXCCQueryValid; bool isDXCCClublogQueryValid; bool isSOTAQueryValid; bool isWWFFQueryValid; bool isPOTAQueryValid; bool isDXCCIDAD1CQueryValid; bool isDXCCIDClublogQueryValid; QuadKeyCache dxccStatusCache; static const char translitTab[]; static const int tranlitIndexMap[]; }; #endif // QLOG_DATA_DATA_H foldynl-QLog-3252ff9/data/DxServerString.cpp000066400000000000000000000037541517334601000207420ustar00rootroot00000000000000#include #include "DxServerString.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.dxserverstring"); DxServerString::DxServerString(const QString &connectString, const QString &defaultUsername) : port(7300), valid(false) { FCT_IDENTIFICATION; if ( !isValidServerString(connectString) ) return; // serverSelect format is: // [username@]hostname:port // username is not mandatory QStringList serverElements = connectString.split(":"); username = defaultUsername; if ( serverElements[0].contains(QStringLiteral("@")) ) { QStringList hostNameElements = serverElements[0].split(QStringLiteral("@")); username = hostNameElements[0]; hostname = hostNameElements[1]; } else { hostname = serverElements[0]; } port = serverElements[1].toInt(); // servername is verified, therefore it is not needed to check // whether the variable "server" contains hostname and port valid = true; } const QRegularExpression DxServerString::serverStringRegEx() { FCT_IDENTIFICATION; return QRegularExpression(QStringLiteral("^([a-z0-9\\-._~%!$&'()*+,;=]+@)?(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):([0-9]{1,5})$|^([a-z0-9\\-._~%!$&'()*+,;=]+@)?(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\\-]*[A-Za-z0-9]):([0-9]{1,5})$"), QRegularExpression::CaseInsensitiveOption); } bool DxServerString::isValidServerString(const QString &connectString) { FCT_IDENTIFICATION; QRegularExpressionMatch stringMatch = serverStringRegEx().match(connectString); bool ret = stringMatch.hasMatch(); qCDebug(runtime) << ret; return ret; } const QString DxServerString::getPasswordStorageKey() const { FCT_IDENTIFICATION; if ( !isValid() ) return QString(); return getHostname() + ":" + QString::number(getPort()); } foldynl-QLog-3252ff9/data/DxServerString.h000066400000000000000000000013121517334601000203730ustar00rootroot00000000000000#ifndef QLOG_DATA_DXSERVERSTRING_H #define QLOG_DATA_DXSERVERSTRING_H #include class DxServerString { public: explicit DxServerString(const QString &connectString, const QString &defaultUsername = QString()); static bool isValidServerString(const QString &); bool isValid() const {return valid;}; QString getUsername() const {return username;}; QString getHostname() const {return hostname;}; int getPort() const {return port;}; const QString getPasswordStorageKey() const; private: static const QRegularExpression serverStringRegEx(); QString username, hostname; int port; bool valid; }; #endif // QLOG_DATA_DXSERVERSTRING_H foldynl-QLog-3252ff9/data/DxSpot.h000066400000000000000000000052721517334601000166740ustar00rootroot00000000000000#ifndef QLOG_DATA_DXSPOT_H #define QLOG_DATA_DXSPOT_H #include #include "Dxcc.h" #include "core/MembershipQE.h" #include "data/BandPlan.h" class DxSpot { public: QDateTime dateTime; QString callsign; QList callsign_member; double freq; double freqTX; QString band; QString modeGroupString; BandPlan::BandPlanMode bandPlanMode; QString spotter; QString comment; qulonglong dupeCount = 0; QString wwffRef; QString potaRef; QString sotaRef; QString iotaRef; DxccEntity dxcc; DxccEntity dxcc_spotter; DxccStatus status; bool containsWWFF; bool containsPOTA; bool containsSOTA; bool containsIOTA; DxSpot() : freq(0.0), freqTX(0.0), bandPlanMode(BandPlan::BAND_MODE_UNKNOWN), status(DxccStatus::UnknownStatus), containsWWFF(false), containsPOTA(false), containsSOTA(false), containsIOTA(false) {}; QStringList memberList2StringList() const { QStringList ret; for ( const ClubInfo &member : static_cast&>(callsign_member) ) ret << member.getClubInfo(); return ret; }; QSet memberList2Set() const { QSet ret; for ( const ClubInfo &member : static_cast&>(callsign_member) ) ret << member.getClubInfo(); return ret; } operator QString() const { return QString("DxSpot ") + "Country: " + QString::number(dxcc.dxcc) + " " + "CQZ: " + QString::number(dxcc.cqz) + " " + "ITUZ: " + QString::number(dxcc.ituz) + " " + "Status: " + QString::number(status) + " " + "ModeGroup: " + modeGroupString + " " + "Band: " + band + " " + "spotter Country: " + QString::number(dxcc_spotter.dxcc) + " " + "Continent: " + dxcc.cont + " " + "Spotter Continent: " + dxcc_spotter.cont + " " + "Callsign: " + callsign + " " + "FreqTX: " + QString::number(freqTX) + " " + "Message: " + comment + " " + "DX Member: " + memberList2StringList().join(", ") + " " + "POTA: " + potaRef + " " + "POTA present: " + (containsPOTA ? "true" : "false") + " " + "SOTA: " + sotaRef + " " + "SOTA present: " + (containsSOTA ? "true" : "false") + " " + "WWFF: " + wwffRef + " " + "WWFF present: " + (containsWWFF ? "true" : "false") + " " + "IOTA: " + iotaRef + " " + "IOTA present: " + (containsIOTA ? "true" : "false") + " "; } }; Q_DECLARE_METATYPE(DxSpot); #endif // QLOG_DATA_DXSPOT_H foldynl-QLog-3252ff9/data/Dxcc.h000066400000000000000000000013241517334601000163260ustar00rootroot00000000000000#ifndef QLOG_DATA_DXCC_H #define QLOG_DATA_DXCC_H #include enum DxccStatus { NewEntity = 0b1, NewBand = 0b10, NewMode = 0b100, NewBandMode = 0b110, NewSlot = 0b1000, Worked = 0b10000, Confirmed = 0b100000, UnknownStatus = 0b1000000, All = 0b1111111 }; class DxccEntity { public: QString country; QString prefix; qint32 dxcc; QString cont; qint32 cqz; qint32 ituz; double latlon[2]; float tz; QString flag; }; struct DxccPrefix { public: QString prefix; bool exact; qint32 dxcc; qint32 cqz; qint32 ituz; QString cont; double latlon[2]; }; #endif // QLOG_DATA_DXCC_H foldynl-QLog-3252ff9/data/Gridsquare.cpp000066400000000000000000000155711517334601000201170ustar00rootroot00000000000000#include "Gridsquare.h" #include #include #include #include #include MODULE_IDENTIFICATION("qlog.core.gridsquare"); Gridsquare::Gridsquare(const QString &in_grid) : validGrid(false), lat(qQNaN()), lon(qQNaN()) { FCT_IDENTIFICATION; if ( !in_grid.isEmpty() ) { grid = in_grid.toUpper(); if ( gridRegEx().match(grid).hasMatch() ) { lon = (grid.at(0).toLatin1() - 'A') * 20 - 180; lat = (grid.at(1).toLatin1() - 'A') * 10 - 90; if ( grid.size() >= 4 ) { lon += (grid.at(2).toLatin1() - '0') * 2; lat += (grid.at(3).toLatin1() - '0') * 1; if ( grid.size() >= 6 ) { lon += (grid.at(4).toLatin1() - 'A') * (5.0/60.0); lat += (grid.at(5).toLatin1() - 'A') * (2.5/60.0); if ( grid.size() >= 8 ) { lon += (grid.at(6).toLatin1() - '0') * (30.0/3600.0); lat += (grid.at(7).toLatin1() - '0') * (15.0/3600.0); // move to the center lon += 15.0/3600.0; lat += 7.5/3600.0; } else { // move to the center lon += 2.5/60.0; lat += 1.25/60.0; } } else { // move to the center lon += 1; lat += 0.5; } } else { // move 0to the center lon += 10; lat += 5; } validGrid = true; } else { /* not valid grid */ grid = QString(); } } } Gridsquare::Gridsquare(const double inlat, const double inlon) : validGrid(false), lat(inlat), lon(inlon) { FCT_IDENTIFICATION; QString U = "ABCDEFGHIJKLMNOPQRSTUVWX"; if ( qIsNaN(inlat) || qIsNaN(inlon) || qAbs(inlat) >= 90.0 || qAbs(inlon) >= 180.0 ) { qCDebug(runtime) << "Invalid Grid lat/lon" << inlat << inlon; this->lat = this->lon = qQNaN(); } else { // currently user only for SOTA where only 6 chars are enough double modifiedLat = lat + 90.0; double modifiedLon = lon + 180.0; QString grid1 = U.at(static_cast(modifiedLon/20)); QString grid2 = U.at(static_cast(modifiedLat/10)); QString grid3 = QString::number(static_cast(fmod((modifiedLon/2), 10.0))); QString grid4 = QString::number(static_cast(fmod(modifiedLat,10.0))); double rLat = (modifiedLat - static_cast(modifiedLat)) * 60; double rLon = (modifiedLon - 2*static_cast(modifiedLon/2)) *60; QString grid5 = U.at((int)(rLon/5)); QString grid6 = U.at((int)(rLat/2.5)); grid = grid1 + grid2 + grid3 + grid4 + grid5 + grid6; qCDebug(runtime) << grid; validGrid = true; } } const QRegularExpression Gridsquare::gridRegEx() { FCT_IDENTIFICATION; return QRegularExpression("^[A-Ra-r]{2}(?:[0-9]{2}|[0-9]{2}[A-Xa-x]{2}|[0-9]{2}[A-Xa-x]{2}[0-9]{2})?$"); //return QRegularExpression("^[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2})?([0-9]{2})?$"); } const QRegularExpression Gridsquare::gridVUCCRegEx() { FCT_IDENTIFICATION; return QRegularExpression("^[A-Ra-r]{2}(?:[0-9]{2}|[0-9]{2}[A-Xa-x]{2}),[ ]*[A-Ra-r]{2}(?:[0-9]{2}|[0-9]{2}[A-Xa-x]{2})$|" "^[A-Ra-r]{2}(?:[0-9]{2}|[0-9]{2}[A-Xa-x]{2}),[ ]*[A-Ra-r]{2}(?:[0-9]{2}|[0-9]{2}[A-Xa-x]{2}),[ ]*[A-Ra-r]{2}(?:[0-9]{2}|[0-9]{2}[A-Xa-x]{2}),[ ]*[A-Ra-r]{2}(?:[0-9]{2}|[0-9]{2}[A-Xa-x]{2})$"); } const QRegularExpression Gridsquare::gridExtRegEx() { FCT_IDENTIFICATION; return QRegularExpression("^[A-Xa-x]{2}?([0-9]{2})?$"); } double Gridsquare::distance2localeUnitDistance(double km, QString &unit, const LogLocale &locale) { FCT_IDENTIFICATION; unit = QObject::tr("km"); double ret = km; // All imperial systems if ( ! locale.getSettingUseMetric() ) { unit = QObject::tr("miles"); ret = km * localeDistanceCoef(locale); } return ret; } double Gridsquare::localeDistanceCoef(const LogLocale &locale) { FCT_IDENTIFICATION; return ( ! locale.getSettingUseMetric() ) ? 0.6213711922 : 1.0; } bool Gridsquare::isValid() const { FCT_IDENTIFICATION; return validGrid; } bool Gridsquare::distanceTo(double lat, double lon, double &distance) const { FCT_IDENTIFICATION; if ( !isValid() ) { distance = 0.0; return false; } /* https://www.movable-type.co.uk/scripts/latlong.html */ double dLat = (lat - this->getLatitude()) * M_PI / 180; double dLon = (lon - this->getLongitude()) * M_PI / 180; double lat1 = this->getLatitude() * M_PI / 180; double lat2 = lat * M_PI / 180; double a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * sin(dLon / 2) * cos(lat1) * cos(lat2); double c = 2 * atan2(sqrt(a), sqrt(1-a)); // Based on IARU Rules // The centre of the Large Locator Square (e.g. IO84MM to IO91MM) is used for distance calculations. // In order to make contest scores comparable, for the conversion from degrees to kilometres a factor // of 111.2 should be used when calculating distances with the aid of the spherical geometry equation. // It means that 111.2km/° * 360 =40032km // It means that R = 40032 / (2*PI) distance = (40032.0 / (2 * M_PI)) * c; return true; } bool Gridsquare::distanceTo(const Gridsquare &in_grid, double &distance) const { FCT_IDENTIFICATION; if ( !in_grid.isValid() ) { distance = 0.0; return false; } return distanceTo(in_grid.getLatitude(), in_grid.getLongitude(), distance); } bool Gridsquare::bearingTo(double lat, double lon, double &bearing) const { FCT_IDENTIFICATION; if ( !isValid() ) { bearing = 0.0; return false; } double dLon = (lon - this->getLongitude()) * M_PI / 180; double lat1 = this->getLatitude() * M_PI / 180; double lat2 = lat * M_PI / 180; double y = sin(dLon) * cos(lat2); double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon); bearing = fmod((180.0 * atan2(y, x) / M_PI + 360.0), 360.0); return true; } bool Gridsquare::bearingTo(const Gridsquare &in_grid, double &bearing) const { FCT_IDENTIFICATION; if ( ! in_grid.isValid() ) { bearing = 0.0; return false; } return bearingTo(in_grid.getLatitude(), in_grid.getLongitude(), bearing); } foldynl-QLog-3252ff9/data/Gridsquare.h000066400000000000000000000025431517334601000175570ustar00rootroot00000000000000#ifndef QLOG_CORE_GRIDSQUARE_H #define QLOG_CORE_GRIDSQUARE_H #include #include #include #include "core/LogLocale.h" class Gridsquare { public: explicit Gridsquare(const QString &in_grid = QString()); explicit Gridsquare(const double inlat,const double inlon); ~Gridsquare() {}; static const QRegularExpression gridRegEx(); static const QRegularExpression gridVUCCRegEx(); static const QRegularExpression gridExtRegEx(); static double distance2localeUnitDistance(double km, QString &unit, const LogLocale &locale); static double localeDistanceCoef(const LogLocale &locale); bool isValid() const; double getLongitude() const {return lon;}; double getLatitude() const {return lat;}; const QString getGrid() const { return grid;}; bool distanceTo(const Gridsquare &in_grid, double &distance) const; bool distanceTo(double lat, double lon, double &distance) const; bool bearingTo(const Gridsquare &in_grid, double &bearing) const; bool bearingTo(double lat, double lon, double &bearing) const ; operator QString() const { return QString("Gridsquare: grid[%1]; valid[%2]; lat[%3]; lon[%4]") .arg(grid).arg(validGrid).arg(lat).arg(lon);}; private: QString grid; bool validGrid; double lat, lon; }; #endif // QLOG_CORE_GRIDSQUARE_H foldynl-QLog-3252ff9/data/HostsPortString.cpp000066400000000000000000000053621517334601000211420ustar00rootroot00000000000000#include #include #include "HostsPortString.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.hostsportstring"); const QRegularExpression HostsPortString::hostsPortRegEx() { return QRegularExpression("^((((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])\\.?\\b){4}):[0-9]{1,5}\\s*)+$"); } HostsPortString::HostsPortString(const QString &addressesString, QObject *parent) : QObject(parent) { FCT_IDENTIFICATION; qDebug(function_parameters) << addressesString; if ( addressesString.isEmpty() ) { return; } const QStringList &addressTokens = addressesString.split(" "); for ( const QString &addrToken : addressTokens ) { qCDebug(runtime) << "Processing address " << addrToken; QStringList addressPair = addrToken.split(":"); if ( addressPair.size() == 2 ) { bool isPortOK = false; uint port = addressPair.at(1).toUInt(&isPortOK); if ( isPortOK && port < 65536 ) { qCDebug(runtime) << "Adding address" << addrToken; addressList << HostPortAddress(addressPair.at(0), port); } else { qCInfo(runtime) << "Malformed port "<< addressPair.at(1) << "for address " << addrToken << " - skipping"; } } else { qCInfo(runtime) << "Malformed address " << addrToken << " - skipping"; } } } bool HostsPortString::hasLocalIPWithPort(int port) const { FCT_IDENTIFICATION; qDebug(function_parameters) << port; QList localAddresses = QNetworkInterface::allAddresses(); localAddresses.append(QHostAddress("0.0.0.0")); qCDebug(runtime) << "My IPs:" << localAddresses; for ( const QHostAddress& addr : static_cast&>(localAddresses) ) if ( addressList.contains(HostPortAddress(addr, port)) ) return true; return false; } QList HostsPortString::getAddrList() const { FCT_IDENTIFICATION; return addressList; } HostPortAddress::HostPortAddress(const QString &hostAddress, quint16 hostPort) : QHostAddress(hostAddress), port(hostPort) { FCT_IDENTIFICATION; } HostPortAddress::HostPortAddress(const QHostAddress &host, quint16 port) : QHostAddress(host), port(port) { FCT_IDENTIFICATION; } void HostPortAddress::setPort(quint16 hostPort) { FCT_IDENTIFICATION; qCDebug(function_parameters) << hostPort; port = hostPort; } quint16 HostPortAddress::getPort() const { FCT_IDENTIFICATION; return port; } bool HostPortAddress::operator==(const HostPortAddress &other) const { return QHostAddress::operator==(other) && port == other.port; } foldynl-QLog-3252ff9/data/HostsPortString.h000066400000000000000000000014511517334601000206020ustar00rootroot00000000000000#ifndef QLOG_DATA_HOSTSPORTSTRING_H #define QLOG_DATA_HOSTSPORTSTRING_H #include #include class HostPortAddress : public QHostAddress { public: explicit HostPortAddress(const QString &, quint16); HostPortAddress(const QHostAddress &host, quint16 port); void setPort(quint16); quint16 getPort() const; bool operator==(const HostPortAddress &other) const; private: quint16 port; }; class HostsPortString : public QObject { Q_OBJECT public: static const QRegularExpression hostsPortRegEx(); explicit HostsPortString(const QString &, QObject *parent=nullptr); bool hasLocalIPWithPort(int port) const; QList getAddrList() const; private: QList addressList; }; #endif // QLOG_DATA_HOSTSPORTSTRING_H foldynl-QLog-3252ff9/data/MainLayoutProfile.cpp000066400000000000000000000206471517334601000214140ustar00rootroot00000000000000#include #include #include #include "MainLayoutProfile.h" #include "core/debug.h" #include "models/LogbookModel.h" MODULE_IDENTIFICATION("qlog.data.mainlayoutprofile"); QDataStream& operator<<(QDataStream& out, const MainLayoutProfile& v) { out << v.profileName << v.rowA << v.rowB << v.detailColA << v.detailColB << v.detailColC << v.mainGeometry << v.mainState << v.darkMode << v.tabsexpanded << v.addlBandmaps; return out; } QDataStream& operator>>(QDataStream& in, MainLayoutProfile& v) { in >> v.profileName; in >> v.rowA; in >> v.rowB; in >> v.detailColA; in >> v.detailColB; in >> v.detailColC; in >> v.mainGeometry; in >> v.mainState; in >> v.darkMode; in >> v.tabsexpanded; in >> v.addlBandmaps; return in; } MainLayoutProfilesManager::MainLayoutProfilesManager() : ProfileManagerSQL("main_layout_profiles") { FCT_IDENTIFICATION; QSqlQuery profileQuery; if ( ! profileQuery.prepare("SELECT profile_name, row_A, row_B, detail_col_A, " "detail_col_B, detail_col_C, main_geometry, main_state, " "dark_mode, tabsexpanded, addlbandmaps " "FROM main_layout_profiles") ) { qWarning()<< "Cannot prepare select"; } if ( profileQuery.exec() ) { while (profileQuery.next()) { MainLayoutProfile profileDB; profileDB.profileName = profileQuery.value(0).toString(); profileDB.rowA = toIntList(profileQuery.value(1).toString()); profileDB.rowB = toIntList(profileQuery.value(2).toString()); profileDB.detailColA = toIntList(profileQuery.value(3).toString()); profileDB.detailColB = toIntList(profileQuery.value(4).toString()); profileDB.detailColC = toIntList(profileQuery.value(5).toString()); profileDB.mainGeometry = QByteArray::fromBase64(profileQuery.value(6).toString().toUtf8()); profileDB.mainState = QByteArray::fromBase64(profileQuery.value(7).toString().toUtf8()); profileDB.darkMode = profileQuery.value(8).toInt(); profileDB.tabsexpanded = profileQuery.value(9).toBool(); profileDB.addlBandmaps = toPairStringList(profileQuery.value(10).toString()); addProfile(profileDB.profileName, profileDB); } } else { qInfo() << "MainLayout Profile DB select error " << profileQuery.lastError().text(); } } void MainLayoutProfilesManager::save() { FCT_IDENTIFICATION; QSqlQuery deleteQuery; QSqlQuery insertQuery; if ( ! deleteQuery.prepare("DELETE FROM main_layout_profiles") ) { qWarning() << "Cannot prepare Delete statement"; return; } if ( ! insertQuery.prepare("INSERT INTO main_layout_profiles(profile_name, row_A, row_B, detail_col_A, detail_col_B, detail_col_C, main_geometry, main_state, dark_mode, tabsexpanded, addlbandmaps) " "VALUES (:profile_name, :row_A, :row_B, :detail_col_A, :detail_col_B, :detail_col_C, :main_geometry, :main_state, :dark_mode, :tabsexpanded, :addlbandmaps)") ) { qWarning() << "Cannot prepare Insert statement"; return; } if ( deleteQuery.exec() ) { const QStringList &keys = profileNameList(); for ( const QString &key: keys ) { const MainLayoutProfile &layoutProfile = getProfile(key); insertQuery.bindValue(":profile_name", key); insertQuery.bindValue(":row_A", toDBStringList(layoutProfile.rowA)); insertQuery.bindValue(":row_B", toDBStringList(layoutProfile.rowB)); insertQuery.bindValue(":detail_col_A", toDBStringList(layoutProfile.detailColA)); insertQuery.bindValue(":detail_col_B", toDBStringList(layoutProfile.detailColB)); insertQuery.bindValue(":detail_col_C", toDBStringList(layoutProfile.detailColC)); insertQuery.bindValue(":main_geometry", layoutProfile.mainGeometry.toBase64()); insertQuery.bindValue(":main_state", layoutProfile.mainState.toBase64()); insertQuery.bindValue(":dark_mode", layoutProfile.darkMode); insertQuery.bindValue(":tabsexpanded", layoutProfile.tabsexpanded); insertQuery.bindValue(":addlbandmaps", toDBStringList(layoutProfile.addlBandmaps)); if ( ! insertQuery.exec() ) { qInfo() << "MainLayoutProfile DB insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); } } } else { qInfo() << "MainLayoutProfile Profile DB delete error " << deleteQuery.lastError().text(); } saveCurProfile1(); } QString MainLayoutProfilesManager::toDBStringList(const QList &list) { FCT_IDENTIFICATION; qCDebug(function_parameters) << list; QStringList stringsList; for ( const int item : list) { stringsList << QString::number(item); } qCDebug(runtime) << "return:" << stringsList; return stringsList.join(","); } QString MainLayoutProfilesManager::toDBStringList(const QList > &list) { FCT_IDENTIFICATION; qCDebug(function_parameters) << list; QStringList stringsList; for ( const QPair &item : list) stringsList << item.first + "/" + item.second; qCDebug(runtime) << "return:" << stringsList; return stringsList.join(","); } QList MainLayoutProfilesManager::toIntList(const QString &list) const { FCT_IDENTIFICATION; qCDebug(function_parameters) << list; QList retList; if ( list.isEmpty() ) return retList; const QStringList splitList = list.split(","); for ( const QString &item : splitList ) { retList << item.toInt(); } qCDebug(runtime) << "return:" << retList; return retList; } QList > MainLayoutProfilesManager::toPairStringList(const QString &list) { FCT_IDENTIFICATION; qCDebug(function_parameters) << list; QList> retList; if ( list.isEmpty() ) return retList; const QStringList &elements = list.split(","); for ( const QString &elementParams : elements ) { const QStringList ¶ms = elementParams.split("/"); if ( params.size() == 2 ) retList << QPair(params.at(0), params.at(1)); else qWarning() << "Unexpected number of Bandmap widget params" << elementParams; } return retList; } bool MainLayoutProfile::operator==(const MainLayoutProfile &profile) { return (profile.profileName == this->profileName && profile.rowA == this->rowA && profile.rowB == this->rowB && profile.detailColA == this->detailColA && profile.detailColB == this->detailColB && profile.detailColC == this->detailColC && profile.mainGeometry == this->mainGeometry && profile.mainState == this->mainState && profile.darkMode == this->darkMode && profile.tabsexpanded == this->tabsexpanded && profile.addlBandmaps == this->addlBandmaps); } bool MainLayoutProfile::operator!=(const MainLayoutProfile &profile) { return !operator==(profile); } MainLayoutProfile MainLayoutProfile::getClassicLayout() { MainLayoutProfile ret; ret.rowA << LogbookModel::COLUMN_NAME_INTL << LogbookModel::COLUMN_QTH_INTL << LogbookModel::COLUMN_GRID << LogbookModel::COLUMN_COMMENT_INTL; ret.detailColA << LogbookModel::COLUMN_CONTINENT << LogbookModel::COLUMN_ITUZ << LogbookModel::COLUMN_CQZ << LogbookModel::COLUMN_STATE << LogbookModel::COLUMN_COUNTY << LogbookModel::COLUMN_AGE << LogbookModel::COLUMN_VUCC_GRIDS; ret.detailColB << LogbookModel::COLUMN_DARC_DOK << LogbookModel::COLUMN_IOTA << LogbookModel::COLUMN_POTA_REF << LogbookModel::COLUMN_SOTA_REF << LogbookModel::COLUMN_WWFF_REF << LogbookModel::COLUMN_SIG_INTL << LogbookModel::COLUMN_SIG_INFO_INTL; ret.detailColC << LogbookModel::COLUMN_EMAIL << LogbookModel::COLUMN_WEB; return ret; } foldynl-QLog-3252ff9/data/MainLayoutProfile.h000066400000000000000000000031261517334601000210520ustar00rootroot00000000000000#ifndef QLOG_DATA_MAINLAYOUTPROFILE_H #define QLOG_DATA_MAINLAYOUTPROFILE_H #include #include #include #include "data/ProfileManager.h" class MainLayoutProfile { public: MainLayoutProfile() { darkMode = 0; tabsexpanded = true; }; QString profileName; QList rowA; QList rowB; QList detailColA; QList detailColB; QList detailColC; QByteArray mainGeometry; QByteArray mainState; int darkMode; bool tabsexpanded; QList> addlBandmaps; bool operator== (const MainLayoutProfile &profile); bool operator!= (const MainLayoutProfile &profile); static MainLayoutProfile getClassicLayout(); private: friend QDataStream& operator<<(QDataStream& out, const MainLayoutProfile& v); friend QDataStream& operator>>(QDataStream& in, MainLayoutProfile& v); }; Q_DECLARE_METATYPE(MainLayoutProfile); class MainLayoutProfilesManager : public ProfileManagerSQL { Q_OBJECT public: explicit MainLayoutProfilesManager(); ~MainLayoutProfilesManager() { }; static MainLayoutProfilesManager* instance() { static MainLayoutProfilesManager instance; return &instance; }; void save(); static QString toDBStringList(const QList &list); static QString toDBStringList(const QList> &list); QList toIntList(const QString &list) const; static QList> toPairStringList(const QString &list); }; #endif // QLOG_DATA_MAINLAYOUTPROFILE_H foldynl-QLog-3252ff9/data/POTAEntity.h000066400000000000000000000004701517334601000174060ustar00rootroot00000000000000#ifndef QLOG_DATA_POTAENTITY_H #define QLOG_DATA_POTAENTITY_H #include class POTAEntity { public: QString reference; QString name; bool active; qint16 entityID; QString locationDesc; double longitude; double latitude; QString grid; }; #endif // QLOG_DATA_POTAENTITY_H foldynl-QLog-3252ff9/data/POTASpot.h000066400000000000000000000006721517334601000170630ustar00rootroot00000000000000#ifndef QLOG_DATA_POTASPOT_H #define QLOG_DATA_POTASPOT_H #include class POTASpot { public: quint64 spotId = 0; QString activator; QString activatorBaseCallsign; double frequency = 0.0; QString mode; QString reference; QString parkName; QDateTime spotTime; QString spotter; QString comments; QString source; QString name; QString locationDesc; }; #endif // QLOG_DATA_POTASPOT_H foldynl-QLog-3252ff9/data/ProfileManager.h000066400000000000000000000217011517334601000203410ustar00rootroot00000000000000#ifndef QLOG_DATA_PROFILEMANAGER_H #define QLOG_DATA_PROFILEMANAGER_H #include #include #include #include #include /* the header file contains function implementation because * https://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor */ /* Question: * when I build, the compiler throws errors in every instance of the template class: * * undefined reference to `cola(float)::cola()'... (it's actually cola'<'float'>'::cola(), * but this doesn't let me use it like that.) */ /* * This is a common question in C++ programming. There are two valid answers to this. There are advantages * and disadvantages to both answers and your choice will depend on context. The common answer is to put all * the implementation in the header file, but there's another approach will will be suitable in some cases. * The choice is yours. * * The code in a template is merely a 'pattern' known to the compiler. The compiler won't compile the * constructors cola::cola(...) and cola::cola(...) until it is forced to do so. * And we must ensure that this compilation happens for the constructors at least once in the entire * compilation process, or we will get the 'undefined reference' error. (This applies to the other * methods of cola also.) * * Understanding the problem: * * The problem is caused by the fact that main.cpp and cola.cpp will be compiled separately first. * In main.cpp, the compiler will implicitly instantiate the template classes cola and * cola because those particular instantiations are used in main.cpp. The bad news is that * the implementations of those member functions are not in main.cpp, nor in any header file included * in main.cpp, and therefore the compiler can't include complete versions of those functions in main.o. * When compiling cola.cpp, the compiler won't compile those instantiations either, because there are no * implicit or explicit instantiations of cola or cola. Remember, when compiling cola.cpp, * the compiler has no clue which instantiations will be needed; and we can't expect it to compile for * every type in order to ensure this problem never happens! (cola, cola, cola, * cola< cola > ... and so on ...) * * The two answers are: * Tell the compiler, at the end of cola.cpp, which particular template classes will be required, * forcing it to compile cola and cola. * Put the implementation of the member functions in a header file that will be included every * time any other 'translation unit' (such as main.cpp) uses the template class. * * Answer 1: Explicitly instantiate the template, and its member definitions * At the end of cola.cpp, you should add lines explicitly instantiating all the relevant templates, such as * * template class cola; * template class cola; * * and you add the following two lines at the end of nodo_colaypila.cpp: * * template class nodo_colaypila; * template class nodo_colaypila; * * This will ensure that, when the compiler is compiling cola.cpp that it will explicitly compile * all the code for the cola and cola classes. Similarly, nodo_colaypila.cpp * contains the implementations of the nodo_colaypila<...> classes. * * In this approach, you should ensure that all the of the implementation is placed into * one .cpp file (i.e. one translation unit) and that the explicit instantation is placed * after the definition of all the functions (i.e. at the end of the file). * * Answer 2: Copy the code into the relevant header file * The common answer is to move all the code from the implementation files cola.cpp and * nodo_colaypila.cpp into cola.h and nodo_colaypila.h. In the long run, this is more * flexible as it means you can use extra instantiations (e.g. cola) without any * more work. But it could mean the same functions are compiled many times, once in * each translation unit. This is not a big problem, as the linker will correctly ignore * the duplicate implementations. But it might slow down the compilation a little. * * Summary * The default answer, used by the STL for example and in most of the code that any * of us will write, is to put all the implementations in the header files. But in a more * private project, you will have more knowledge and control of which particular template * classes will be instantiated. In fact, this 'bug' might be seen as a feature, as it * stops users of your code from accidentally using instantiations you have not tested * for or planned for ("I know this works for cola and cola, if you want * to use something else, tell me first and will can verify it works before enabling it."). */ class ProfileSignalSlot : public QObject { Q_OBJECT signals: void profileChanged(const QString &profileName); }; template class ProfileManagerSQL : public ProfileSignalSlot { public: explicit ProfileManagerSQL(const QString &tableName) : tableName(tableName) { QSqlQuery query(QString("SELECT profile_name FROM %1 WHERE IFNULL(selected, 0) = 1").arg(tableName)); currentProfile1 = query.first() ? query.value(0).toString() : QString(); if ( currentProfile1.isEmpty() ) qDebug() << "Empty profile name for " << tableName << "SQL Error" << query.lastError().text(); }; const T getCurProfile1() { return ( ! currentProfile1.isEmpty() ) ? getProfile(currentProfile1) : T(); }; bool __setCurProfile1(const QString &profileName) { bool ret = false; if ( profiles.contains(profileName) || profileName.isEmpty() ) { QSqlQuery query; // atomic change if ( !query.prepare(QString("UPDATE %1 " "SET selected = CASE " " WHEN profile_name = :profileName THEN 1 " " ELSE NULL " " END " "WHERE selected = 1 OR profile_name = :profileName2").arg(tableName)) ) { qWarning() << "Cannot prepare Update statement for" << tableName; return ret; } query.bindValue(":profileName", profileName); query.bindValue(":profileName2", profileName); if ( query.exec() ) { currentProfile1 = profileName; ret = true; } else qWarning() << "Cannot set the selected profile for " << tableName << query.lastError().text(); } else qWarning() << "Cannot set Current Profile to " << profileName << "because is not not a valid profile name" << tableName; return ret; }; void setCurProfile1(const QString &profileName) { currProfMutex.lock(); bool changed = __setCurProfile1(profileName); currProfMutex.unlock(); if ( changed ) emit profileChanged(currentProfile1); }; void saveCurProfile1() { currProfMutex.lock(); bool changed = __setCurProfile1(currentProfile1); currProfMutex.unlock(); if ( changed ) emit profileChanged(currentProfile1); }; const T getProfile(const QString &profileName) { if ( profiles.contains(profileName) ) { profilesMutex.lock(); T ret = profiles.value(profileName).template value(); profilesMutex.unlock(); return ret; } else { if ( !profileName.isEmpty() ) qWarning() << "Profile " << profileName << " not found" << tableName; return T(); } }; void addProfile(const QString &profileName, T profile) { profilesMutex.lock(); profiles.insert(profileName, QVariant::fromValue(profile)); profilesMutex.unlock(); }; int removeProfile(const QString &profileName) { currProfMutex.lock(); if ( currentProfile1 == profileName ) { __setCurProfile1(QString()); } currProfMutex.unlock(); profilesMutex.lock(); int ret = profiles.remove(profileName); profilesMutex.unlock(); return ret; }; const QStringList profileNameList() { profilesMutex.lock(); QStringList ret(profiles.keys()); profilesMutex.unlock(); return ret; }; private: QMap profiles; QString currentProfile1; QString tableName; QMutex profilesMutex; QMutex currProfMutex; }; #endif // QLOG_DATA_PROFILEMANAGER_H foldynl-QLog-3252ff9/data/RigProfile.cpp000066400000000000000000000332121517334601000200430ustar00rootroot00000000000000#include #include #include "RigProfile.h" #include "core/debug.h" #include "data/ProfileManager.h" #include "rig/Rig.h" #include "SerialPort.h" MODULE_IDENTIFICATION("qlog.data.rigprofile"); QDataStream& operator<<(QDataStream& out, const RigProfile& v) { out << v.profileName << v.model << v.portPath << v.hostname << v.netport << v.baudrate << v.databits << v.stopbits << v.flowcontrol << v.parity << v.pollInterval << v.txFreqStart << v.txFreqEnd << v.getFreqInfo << v.getModeInfo << v.getVFOInfo << v.getPWRInfo << v.ritOffset << v.xitOffset << v.getRITInfo << v.getXITInfo << v.defaultPWR << v.getPTTInfo << v.QSYWiping << v.getKeySpeed << v.assignedCWKey << v.keySpeedSync << v.driver << v.dxSpot2Rig << v.pttType << v.pttPortPath << v.rts << v.dtr << v.civAddr << v.shareRigctld << v.rigctldPort << v.rigctldPath << v.rigctldArgs << v.getSplitInfo; return out; } QDataStream& operator>>(QDataStream& in, RigProfile& v) { in >> v.profileName; in >> v.model; in >> v.portPath; in >> v.hostname; in >> v.netport; in >> v.baudrate; in >> v.databits; in >> v.stopbits; in >> v.flowcontrol; in >> v.parity; in >> v.pollInterval; in >> v.txFreqStart; in >> v.txFreqEnd; in >> v.getFreqInfo; in >> v.getModeInfo; in >> v.getVFOInfo; in >> v.getPWRInfo; in >> v.ritOffset; in >> v.xitOffset; in >> v.getRITInfo; in >> v.getXITInfo; in >> v.defaultPWR; in >> v.getPTTInfo; in >> v.QSYWiping; in >> v.getKeySpeed; in >> v.assignedCWKey; in >> v.keySpeedSync; in >> v.driver; in >> v.dxSpot2Rig; in >> v.pttType; in >> v.pttPortPath; in >> v.rts; in >> v.dtr; in >> v.civAddr; in >> v.shareRigctld; in >> v.rigctldPort; in >> v.rigctldPath; in >> v.rigctldArgs; in >> v.getSplitInfo; return in; } RigProfilesManager::RigProfilesManager() : ProfileManagerSQL("rig_profiles") { FCT_IDENTIFICATION; QSqlQuery profileQuery; if ( ! profileQuery.prepare(QString("SELECT profile_name, model, port_pathname, hostname, " "netport, baudrate, databits, stopbits, flowcontrol, parity, " "pollinterval, txfreq_start, txfreq_end, get_freq, get_mode, " "get_vfo, get_pwr, rit_offset, xit_offset, get_rit, get_xit, " "default_pwr, get_ptt, qsy_wiping, get_key_speed, assigned_cw_key, " "key_speed_sync, driver, dxspot2rig, ptt_type, ptt_port_pathname, " "IFNULL(rts, '%0'), IFNULL(dtr, '%0'), IFNULL(civaddr, -1), " "IFNULL(share_rigctld, 0), IFNULL(rigctld_port, 4532), " "IFNULL(rigctld_path, ''), IFNULL(rigctld_args, ''), get_split " "FROM rig_profiles").arg(SerialPort::SERIAL_SIGNAL_NONE))) { qWarning()<< "Cannot prepare select"; } if ( profileQuery.exec() ) { while (profileQuery.next()) { RigProfile profileDB; profileDB.profileName = profileQuery.value(0).toString(); profileDB.model = profileQuery.value(1).toInt(); profileDB.portPath = profileQuery.value(2).toString(); profileDB.hostname = profileQuery.value(3).toString(); profileDB.netport = profileQuery.value(4).toUInt(); profileDB.baudrate = profileQuery.value(5).toUInt(); profileDB.databits = profileQuery.value(6).toUInt(); profileDB.stopbits = profileQuery.value(7).toFloat(); profileDB.flowcontrol = profileQuery.value(8).toString(); profileDB.parity = profileQuery.value(9).toString(); profileDB.pollInterval = profileQuery.value(10).toUInt(); profileDB.txFreqStart = profileQuery.value(11).toFloat(); profileDB.txFreqEnd = profileQuery.value(12).toFloat(); profileDB.getFreqInfo = profileQuery.value(13).toBool(); profileDB.getModeInfo = profileQuery.value(14).toBool(); profileDB.getVFOInfo = profileQuery.value(15).toBool(); profileDB.getPWRInfo = profileQuery.value(16).toBool(); profileDB.ritOffset = profileQuery.value(17).toDouble(); profileDB.xitOffset = profileQuery.value(18).toDouble(); profileDB.getRITInfo = profileQuery.value(19).toBool(); profileDB.getXITInfo = profileQuery.value(20).toBool(); profileDB.defaultPWR = profileQuery.value(21).toDouble(); profileDB.getPTTInfo = profileQuery.value(22).toBool(); profileDB.QSYWiping = profileQuery.value(23).toBool(); profileDB.getKeySpeed = profileQuery.value(24).toBool(); profileDB.assignedCWKey = profileQuery.value(25).toString(); profileDB.keySpeedSync = profileQuery.value(26).toBool(); profileDB.driver = profileQuery.value(27).toInt(); profileDB.dxSpot2Rig = profileQuery.value(28).toBool(); profileDB.pttType = profileQuery.value(29).toString(); profileDB.pttPortPath = profileQuery.value(30).toString(); profileDB.rts = profileQuery.value(31).toString(); profileDB.dtr = profileQuery.value(32).toString(); profileDB.civAddr = profileQuery.value(33).toInt(); profileDB.shareRigctld = profileQuery.value(34).toBool(); profileDB.rigctldPort = profileQuery.value(35).toUInt(); profileDB.rigctldPath = profileQuery.value(36).toString(); profileDB.rigctldArgs = profileQuery.value(37).toString(); profileDB.getSplitInfo = profileQuery.value(38).toBool(); addProfile(profileDB.profileName, profileDB); } } else { qInfo() << "Station Profile DB select error " << profileQuery.lastError().text(); } } void RigProfilesManager::save() { FCT_IDENTIFICATION; QSqlQuery deleteQuery; QSqlQuery insertQuery; if ( ! deleteQuery.prepare("DELETE FROM rig_profiles") ) { qWarning() << "cannot prepare Delete statement"; return; } if ( ! insertQuery.prepare("INSERT INTO rig_profiles(profile_name, model, port_pathname, hostname, netport, " "baudrate, databits, stopbits, flowcontrol, parity, pollinterval, txfreq_start, " "txfreq_end, get_freq, get_mode, get_vfo, get_pwr, rit_offset, xit_offset, get_rit, " "get_xit, default_pwr, get_ptt, qsy_wiping, get_key_speed, assigned_cw_key, key_speed_sync, " "driver, dxSpot2Rig, ptt_type, ptt_port_pathname, rts, dtr, civaddr, " "share_rigctld, rigctld_port, rigctld_path, rigctld_args, get_split ) " "VALUES (:profile_name, :model, :port_pathname, :hostname, :netport, " ":baudrate, :databits, :stopbits, :flowcontrol, :parity, :pollinterval, :txfreq_start, " ":txfreq_end, :get_freq, :get_mode, :get_vfo, :get_pwr, :rit_offset, :xit_offset, :get_rit, " ":get_xit, :default_pwr, :get_ptt, :qsy_wiping, :get_key_speed, :assigned_cw_key, :key_speed_sync, " ":driver, :dxSpot2Rig, :ptt_type, :ptt_port_pathname, :rts, :dtr, :civaddr, " ":share_rigctld, :rigctld_port, :rigctld_path, :rigctld_args, :get_split )") ) { qWarning() << "cannot prepare Insert statement"; return; } if ( deleteQuery.exec() ) { const QStringList &keys = profileNameList(); for ( const QString &key: keys ) { const RigProfile &rigProfile = getProfile(key); insertQuery.bindValue(":profile_name", key); insertQuery.bindValue(":model", rigProfile.model); insertQuery.bindValue(":port_pathname", rigProfile.portPath); insertQuery.bindValue(":hostname", rigProfile.hostname); insertQuery.bindValue(":netport", rigProfile.netport); insertQuery.bindValue(":baudrate", rigProfile.baudrate); insertQuery.bindValue(":databits", rigProfile.databits); insertQuery.bindValue(":stopbits", rigProfile.stopbits); insertQuery.bindValue(":flowcontrol", rigProfile.flowcontrol); insertQuery.bindValue(":parity", rigProfile.parity); insertQuery.bindValue(":pollinterval", rigProfile.pollInterval); insertQuery.bindValue(":txfreq_start", rigProfile.txFreqStart); insertQuery.bindValue(":txfreq_end", rigProfile.txFreqEnd); insertQuery.bindValue(":get_freq", rigProfile.getFreqInfo); insertQuery.bindValue(":get_mode", rigProfile.getModeInfo); insertQuery.bindValue(":get_vfo", rigProfile.getVFOInfo); insertQuery.bindValue(":get_pwr", rigProfile.getPWRInfo); insertQuery.bindValue(":rit_offset", rigProfile.ritOffset); insertQuery.bindValue(":xit_offset", rigProfile.xitOffset); insertQuery.bindValue(":get_rit", rigProfile.getRITInfo); insertQuery.bindValue(":get_xit", rigProfile.getXITInfo); insertQuery.bindValue(":default_pwr", rigProfile.defaultPWR); insertQuery.bindValue(":get_ptt", rigProfile.getPTTInfo); insertQuery.bindValue(":qsy_wiping", rigProfile.QSYWiping); insertQuery.bindValue(":get_key_speed", rigProfile.getKeySpeed); insertQuery.bindValue(":assigned_cw_key", rigProfile.assignedCWKey); insertQuery.bindValue(":key_speed_sync", rigProfile.keySpeedSync); insertQuery.bindValue(":driver", rigProfile.driver); insertQuery.bindValue(":dxSpot2Rig", rigProfile.dxSpot2Rig); insertQuery.bindValue(":ptt_type", rigProfile.pttType); insertQuery.bindValue(":ptt_port_pathname", rigProfile.pttPortPath); insertQuery.bindValue(":rts", rigProfile.rts); insertQuery.bindValue(":dtr", rigProfile.dtr); insertQuery.bindValue(":civaddr", (rigProfile.civAddr >= 0) ? rigProfile.civAddr : QVariant()); // 0x0 is valid CIV Address, NULL will be Auto insertQuery.bindValue(":share_rigctld", rigProfile.shareRigctld); insertQuery.bindValue(":rigctld_port", rigProfile.rigctldPort); insertQuery.bindValue(":rigctld_path", rigProfile.rigctldPath); insertQuery.bindValue(":rigctld_args", rigProfile.rigctldArgs); insertQuery.bindValue(":get_split", rigProfile.getSplitInfo); if ( ! insertQuery.exec() ) { qInfo() << "Station Profile DB insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); } } } else { qInfo() << "Station Profile DB delete error " << deleteQuery.lastError().text(); } saveCurProfile1(); } bool RigProfile::operator==(const RigProfile &profile) { return (profile.profileName == this->profileName && profile.model == this->model && profile.portPath == this->portPath && profile.hostname == this->hostname && profile.netport == this->netport && profile.baudrate == this->baudrate && profile.databits == this->databits && profile.stopbits == this->stopbits && profile.flowcontrol == this->flowcontrol && profile.parity == this->parity && profile.pollInterval == this->pollInterval && profile.txFreqStart == this->txFreqStart && profile.txFreqEnd == this->txFreqEnd && profile.getFreqInfo == this->getFreqInfo && profile.getModeInfo == this->getModeInfo && profile.getVFOInfo == this->getVFOInfo && profile.getPWRInfo == this->getPWRInfo && profile.ritOffset == this->ritOffset && profile.xitOffset == this->xitOffset && profile.getRITInfo == this->getRITInfo && profile.getXITInfo == this->getXITInfo && profile.defaultPWR == this->defaultPWR && profile.getPTTInfo == this->getPTTInfo && profile.QSYWiping == this->QSYWiping && profile.getKeySpeed == this->getKeySpeed && profile.assignedCWKey == this->assignedCWKey && profile.keySpeedSync == this->keySpeedSync && profile.driver == this->driver && profile.dxSpot2Rig == this->dxSpot2Rig && profile.pttType == this->pttType && profile.pttPortPath == this->pttPortPath && profile.rts == this->rts && profile.dtr == this->dtr && profile.civAddr == this->civAddr && profile.shareRigctld == this->shareRigctld && profile.rigctldPort == this->rigctldPort && profile.rigctldPath == this->rigctldPath && profile.rigctldArgs == this->rigctldArgs && profile.getSplitInfo == this->getSplitInfo ); } bool RigProfile::operator!=(const RigProfile &profile) { return !operator==(profile); } QString RigProfile::toHTMLString() const { QString ret = "" + QObject::tr("My Rig") + ": " + profileName + "
"; return ret; } RigProfile::rigPortType RigProfile::getPortType() const { FCT_IDENTIFICATION; if ( driver == Rig::OMNIRIG_DRIVER || driver == Rig::OMNIRIGV2_DRIVER ) return RigProfile::SPECIAL_OMNIRIG_ATTACHED; if ( !hostname.isEmpty() && portPath.isEmpty() ) { return RigProfile::NETWORK_ATTACHED; } return RigProfile::SERIAL_ATTACHED; } foldynl-QLog-3252ff9/data/RigProfile.h000066400000000000000000000051621517334601000175130ustar00rootroot00000000000000#ifndef QLOG_DATA_RIGPROFILE_H #define QLOG_DATA_RIGPROFILE_H #include #include #include #include #include #include "data/ProfileManager.h" class RigProfile { public: enum rigPortType { SERIAL_ATTACHED, NETWORK_ATTACHED, SPECIAL_OMNIRIG_ATTACHED }; RigProfile() { model = 1; netport = 0; baudrate = 0; databits = 0; stopbits = 0.0; pollInterval = 0; txFreqStart = 0.0; txFreqEnd = 0.0; getFreqInfo = false; getModeInfo = false; getVFOInfo = false; getPWRInfo = false; ritOffset = 0.0; xitOffset = 0.0, getRITInfo = false; getXITInfo = true; defaultPWR = 0.0, getPTTInfo = false; QSYWiping = false, getKeySpeed = false, keySpeedSync = false; driver = 0, dxSpot2Rig = false, civAddr = -1; shareRigctld = false; rigctldPort = 4532; getSplitInfo = false; }; QString profileName; QString portPath; QString hostname; QString flowcontrol; QString parity; double ritOffset; double xitOffset; double defaultPWR; QString assignedCWKey; QString pttType; QString pttPortPath; QString rts; QString dtr; QString rigctldPath; // empty = autodetect QString rigctldArgs; // additional arguments qint32 model; quint32 baudrate; float stopbits; quint32 pollInterval; float txFreqStart; float txFreqEnd; qint32 driver; quint16 netport; qint16 civAddr; // -1 = AUTO; otherwise address quint16 rigctldPort; quint8 databits; bool getFreqInfo; bool getModeInfo; bool getVFOInfo; bool getPWRInfo; bool getRITInfo; bool getXITInfo; bool getPTTInfo; bool QSYWiping; bool getKeySpeed; bool keySpeedSync; bool dxSpot2Rig; bool shareRigctld; bool getSplitInfo; bool operator== (const RigProfile &profile); bool operator!= (const RigProfile &profile); QString toHTMLString() const; rigPortType getPortType() const; private: friend QDataStream& operator<<(QDataStream& out, const RigProfile& v); friend QDataStream& operator>>(QDataStream& in, RigProfile& v); }; Q_DECLARE_METATYPE(RigProfile) class RigProfilesManager : public ProfileManagerSQL { Q_OBJECT public: explicit RigProfilesManager(); ~RigProfilesManager() { }; static RigProfilesManager* instance() { static RigProfilesManager instance; return &instance; }; void save(); }; #endif // QLOG_DATA_RIGPROFILE_H foldynl-QLog-3252ff9/data/RotProfile.cpp000066400000000000000000000121161517334601000200660ustar00rootroot00000000000000#include #include #include "RotProfile.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.data.rotprofile"); QDataStream& operator<<(QDataStream& out, const RotProfile& v) { out << v.profileName << v.model << v.portPath << v.hostname << v.netport << v.baudrate << v.databits << v.stopbits << v.flowcontrol << v.parity << v.driver; return out; } QDataStream& operator>>(QDataStream& in, RotProfile& v) { in >> v.profileName; in >> v.model; in >> v.portPath; in >> v.hostname; in >> v.netport; in >> v.baudrate; in >> v.databits; in >> v.stopbits; in >> v.flowcontrol; in >> v.parity; in >> v.driver; return in; } RotProfilesManager::RotProfilesManager() : ProfileManagerSQL("rot_profiles") { FCT_IDENTIFICATION; QSqlQuery profileQuery; if ( ! profileQuery.prepare("SELECT profile_name, model, port_pathname, hostname, netport, baudrate, databits, stopbits, flowcontrol, parity, driver FROM rot_profiles") ) { qWarning()<< "Cannot prepare select"; } if ( profileQuery.exec() ) { while (profileQuery.next()) { RotProfile profileDB; profileDB.profileName = profileQuery.value(0).toString(); profileDB.model = profileQuery.value(1).toInt(); profileDB.portPath = profileQuery.value(2).toString(); profileDB.hostname = profileQuery.value(3).toString(); profileDB.netport = profileQuery.value(4).toUInt(); profileDB.baudrate = profileQuery.value(5).toUInt(); profileDB.databits = profileQuery.value(6).toUInt(); profileDB.stopbits = profileQuery.value(7).toFloat(); profileDB.flowcontrol = profileQuery.value(8).toString(); profileDB.parity = profileQuery.value(9).toString(); profileDB.driver = profileQuery.value(10).toInt(); addProfile(profileDB.profileName, profileDB); } } else { qInfo() << "Rot Profile DB select error " << profileQuery.lastError().text(); } } RotProfilesManager *RotProfilesManager::instance() { FCT_IDENTIFICATION; static RotProfilesManager instance; return &instance; } void RotProfilesManager::save() { FCT_IDENTIFICATION; QSqlQuery deleteQuery; QSqlQuery insertQuery; if ( ! deleteQuery.prepare("DELETE FROM rot_profiles") ) { qWarning() << "cannot prepare Delete statement"; return; } if ( ! insertQuery.prepare("INSERT INTO rot_profiles(profile_name, model, port_pathname, hostname, netport, baudrate, databits, stopbits, flowcontrol, parity, driver) " "VALUES (:profile_name, :model, :port_pathname, :hostname, :netport, :baudrate, :databits, :stopbits, :flowcontrol, :parity, :driver)") ) { qWarning() << "cannot prepare Insert statement"; return; } if ( deleteQuery.exec() ) { const QStringList &keys = profileNameList(); for ( const QString &key: keys ) { const RotProfile &rigProfile = getProfile(key); insertQuery.bindValue(":profile_name", key); insertQuery.bindValue(":model", rigProfile.model); insertQuery.bindValue(":port_pathname", rigProfile.portPath); insertQuery.bindValue(":hostname", rigProfile.hostname); insertQuery.bindValue(":netport", rigProfile.netport); insertQuery.bindValue(":baudrate", rigProfile.baudrate); insertQuery.bindValue(":databits", rigProfile.databits); insertQuery.bindValue(":stopbits", rigProfile.stopbits); insertQuery.bindValue(":flowcontrol", rigProfile.flowcontrol); insertQuery.bindValue(":parity", rigProfile.parity); insertQuery.bindValue(":driver", rigProfile.driver); if ( ! insertQuery.exec() ) { qInfo() << "Station Profile DB insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); } } } else { qInfo() << "Rot Profile DB delete error " << deleteQuery.lastError().text(); } saveCurProfile1(); } bool RotProfile::operator==(const RotProfile &profile) { return (profile.profileName == this->profileName && profile.model == this->model && profile.portPath == this->portPath && profile.hostname == this->hostname && profile.netport == this->netport && profile.baudrate == this->baudrate && profile.databits == this->databits && profile.stopbits == this->stopbits && profile.flowcontrol == this->flowcontrol && profile.parity == this->parity && profile.driver == this->driver); } bool RotProfile::operator!=(const RotProfile &profile) { return !operator==(profile); } RotProfile::rotPortType RotProfile::getPortType() const { FCT_IDENTIFICATION; if ( !hostname.isEmpty() && portPath.isEmpty() ) { return RotProfile::NETWORK_ATTACHED; } return RotProfile::SERIAL_ATTACHED; } foldynl-QLog-3252ff9/data/RotProfile.h000066400000000000000000000024161517334601000175350ustar00rootroot00000000000000#ifndef QLOG_DATA_ROTPROFILE_H #define QLOG_DATA_ROTPROFILE_H #include #include #include #include #include "data/ProfileManager.h" #define DEFAULT_ROT_MODEL 1 class RotProfile { public: enum rotPortType { SERIAL_ATTACHED, NETWORK_ATTACHED }; RotProfile() { model = DEFAULT_ROT_MODEL; netport = 0; baudrate = 0; databits = 0; stopbits = 0.0; driver = 0;}; QString profileName; qint32 model; QString portPath; QString hostname; quint16 netport; quint32 baudrate; quint8 databits; float stopbits; QString flowcontrol; QString parity; qint32 driver; bool operator== (const RotProfile &profile); bool operator!= (const RotProfile &profile); rotPortType getPortType() const; private: friend QDataStream& operator<<(QDataStream& out, const RotProfile& v); friend QDataStream& operator>>(QDataStream& in, RotProfile& v); }; Q_DECLARE_METATYPE(RotProfile); class RotProfilesManager : public ProfileManagerSQL { Q_OBJECT public: explicit RotProfilesManager(); ~RotProfilesManager() { }; static RotProfilesManager* instance(); void save(); }; #endif // QLOG_DATA_ROTPROFILE_H foldynl-QLog-3252ff9/data/RotUsrButtonsProfile.cpp000066400000000000000000000101271517334601000221370ustar00rootroot00000000000000#include #include #include "RotUsrButtonsProfile.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.data.rotusrbuttonsprofile"); QDataStream& operator<<(QDataStream& out, const RotUsrButtonsProfile& v) { out << v.profileName; for( int i = 0; i < v.shortDescs.size(); i++ ) { out << v.shortDescs[i]; } for( int i = 0; i < v.bearings.size(); i++ ) { out << v.bearings[i]; } return out; } QDataStream& operator>>(QDataStream& in, RotUsrButtonsProfile& v) { in >> v.profileName; for( int i = 0; i < v.shortDescs.size(); i++ ) { in >> v.shortDescs[i]; } for( int i = 0; i < v.bearings.size(); i++ ) { in >> v.bearings[i]; } return in; } RotUsrButtonsProfilesManager::RotUsrButtonsProfilesManager() : ProfileManagerSQL("rot_user_buttons_profiles") { FCT_IDENTIFICATION; QSqlQuery profileQuery; if ( ! profileQuery.prepare("SELECT profile_name, button1_short, button1_value, button2_short, button2_value, " "button3_short, button3_value, button4_short, button4_value " "FROM rot_user_buttons_profiles") ) { qWarning()<< "Cannot prepare select"; } if ( profileQuery.exec() ) { while (profileQuery.next()) { RotUsrButtonsProfile profileDB; int column = 0; profileDB.profileName = profileQuery.value(column++).toString(); for ( int i = 0; i < profileDB.shortDescs.size(); i++ ) { profileDB.shortDescs[i] = profileQuery.value(column++).toString(); profileDB.bearings[i] = profileQuery.value(column++).toDouble(); } addProfile(profileDB.profileName, profileDB); } } else { qInfo() << "Rot User Button Profile DB select error " << profileQuery.lastError().text(); } } void RotUsrButtonsProfilesManager::save() { FCT_IDENTIFICATION; QSqlQuery deleteQuery; QSqlQuery insertQuery; if ( ! deleteQuery.prepare("DELETE FROM rot_user_buttons_profiles") ) { qWarning() << "Cannot prepare Delete statement"; return; } if ( ! insertQuery.prepare("INSERT INTO rot_user_buttons_profiles(profile_name, button1_short, button1_value, button2_short, button2_value," "button3_short, button3_value, button4_short, button4_value)" "VALUES (:profile_name, :b1_short, :b1_value, :b2_short, :b2_value," ":b3_short, :b3_value, :b4_short, :b4_value)") ) { qWarning() << "Cannot prepare Insert statement"; return; } if ( deleteQuery.exec() ) { const QStringList &keys = profileNameList(); for ( const QString &key: keys ) { const RotUsrButtonsProfile &rotUsrButtonProfile = getProfile(key); insertQuery.bindValue(":profile_name", key); for ( int i = 0; i < rotUsrButtonProfile.shortDescs.size(); i++ ) { insertQuery.bindValue(QString(":b%1_short").arg(i+1), rotUsrButtonProfile.shortDescs[i]); } for ( int i = 0; i < rotUsrButtonProfile.bearings.size(); i++ ) { insertQuery.bindValue(QString(":b%1_value").arg(i+1), rotUsrButtonProfile.bearings[i]); } if ( ! insertQuery.exec() ) { qInfo() << "Rot User Button Profile DB insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); } } } else { qInfo() << "Rot User Button Profile DB delete error " << deleteQuery.lastError().text(); } saveCurProfile1(); } bool RotUsrButtonsProfile::operator==(const RotUsrButtonsProfile &profile) { return (profile.profileName == this->profileName && profile.shortDescs == this->shortDescs && profile.bearings == this->bearings); } bool RotUsrButtonsProfile::operator!=(const RotUsrButtonsProfile &profile) { return !operator==(profile); } foldynl-QLog-3252ff9/data/RotUsrButtonsProfile.h000066400000000000000000000023021517334601000216000ustar00rootroot00000000000000#ifndef QLOG_DATA_ROTUSRBUTTONSPROFILE_H #define QLOG_DATA_ROTUSRBUTTONSPROFILE_H #include #include #include #include "data/ProfileManager.h" #define MAX_ROT_USER_BUTTONS 4 class RotUsrButtonsProfile { public: RotUsrButtonsProfile() { shortDescs.resize(MAX_ROT_USER_BUTTONS); bearings.resize(MAX_ROT_USER_BUTTONS); } QString profileName; QVector shortDescs; QVector bearings; bool operator== (const RotUsrButtonsProfile &profile); bool operator!= (const RotUsrButtonsProfile &profile); private: friend QDataStream& operator<<(QDataStream& out, const RotUsrButtonsProfile& v); friend QDataStream& operator>>(QDataStream& in, RotUsrButtonsProfile& v); }; Q_DECLARE_METATYPE(RotUsrButtonsProfile); class RotUsrButtonsProfilesManager : public ProfileManagerSQL { Q_OBJECT public: explicit RotUsrButtonsProfilesManager(); ~RotUsrButtonsProfilesManager() { }; static RotUsrButtonsProfilesManager* instance() { static RotUsrButtonsProfilesManager instance; return &instance; }; void save(); }; #endif // QLOG_DATA_ROTUSRBUTTONSPROFILE_H foldynl-QLog-3252ff9/data/SOTAEntity.h000066400000000000000000000007021517334601000174070ustar00rootroot00000000000000#ifndef QLOG_DATA_SOTAENTITY_H #define QLOG_DATA_SOTAENTITY_H #include class SOTAEntity { public: QString summitCode; QString associationName; QString regionName; QString summitName; qint32 altm; qint32 altft; double gridref1; double gridref2; double longitude; double latitude; qint16 points; qint16 bonusPoints; QDate validFrom; QDate validTo; }; #endif // QLOG_DATA_SOTAENTITY_H foldynl-QLog-3252ff9/data/SerialPort.cpp000066400000000000000000000014651517334601000200720ustar00rootroot00000000000000#include "SerialPort.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.serialport"); SerialPort::SerialPort(QObject *parent) : QObject{parent} { FCT_IDENTIFICATION; } const QString SerialPort::SERIAL_FLOWCONTROL_NONE = "none"; const QString SerialPort::SERIAL_FLOWCONTROL_HARDWARE = "hardware"; const QString SerialPort::SERIAL_FLOWCONTROL_SOFTWARE = "software"; const QString SerialPort::SERIAL_PARITY_EVEN = "even"; const QString SerialPort::SERIAL_PARITY_ODD = "odd"; const QString SerialPort::SERIAL_PARITY_MARK = "mark"; const QString SerialPort::SERIAL_PARITY_SPACE = "space"; const QString SerialPort::SERIAL_PARITY_NO = "no"; const QString SerialPort::SERIAL_SIGNAL_NONE = "none"; const QString SerialPort::SERIAL_SIGNAL_HIGH = "high"; const QString SerialPort::SERIAL_SIGNAL_LOW = "low"; foldynl-QLog-3252ff9/data/SerialPort.h000066400000000000000000000014011517334601000175250ustar00rootroot00000000000000#ifndef QLOG_DATA_SERIALPORT_H #define QLOG_DATA_SERIALPORT_H #include #include class SerialPort : public QObject { Q_OBJECT public: explicit SerialPort(QObject *parent = nullptr); static const QString SERIAL_FLOWCONTROL_NONE; static const QString SERIAL_FLOWCONTROL_SOFTWARE; static const QString SERIAL_FLOWCONTROL_HARDWARE; static const QString SERIAL_PARITY_EVEN; static const QString SERIAL_PARITY_ODD; static const QString SERIAL_PARITY_MARK; static const QString SERIAL_PARITY_SPACE; static const QString SERIAL_PARITY_NO; static const QString SERIAL_SIGNAL_NONE; static const QString SERIAL_SIGNAL_HIGH; static const QString SERIAL_SIGNAL_LOW; }; #endif // QLOG_DATA_SERIALPORT_H foldynl-QLog-3252ff9/data/SpotAlert.h000066400000000000000000000016351517334601000173670ustar00rootroot00000000000000#ifndef QLOG_DATA_SPOTALERT_H #define QLOG_DATA_SPOTALERT_H #include #include "data/WsjtxEntry.h" #include "data/DxSpot.h" class SpotAlert { public: enum ALERTSOURCETYPE { UKNOWN = 0, DXSPOT = 0b1, WSJTXCQSPOT = 0b10 }; ALERTSOURCETYPE source; QStringList ruleNameList; WsjtxEntry spot; SpotAlert() : source(DXSPOT) {}; SpotAlert(const QStringList &ruleList, const DxSpot &sourceSpot) : spot(sourceSpot) { source = SpotAlert::ALERTSOURCETYPE::DXSPOT; ruleNameList = ruleList; }; SpotAlert(const QStringList &ruleList, const WsjtxEntry &sourceWsjtx) : spot(sourceWsjtx) { source = SpotAlert::ALERTSOURCETYPE::WSJTXCQSPOT; ruleNameList = ruleList; }; const DxSpot& getDxSpot() const {return spot;}; private: }; Q_DECLARE_METATYPE(SpotAlert); #endif // QLOG_DATA_SPOTALERT_H foldynl-QLog-3252ff9/data/StationProfile.cpp000066400000000000000000000251001517334601000207400ustar00rootroot00000000000000#include "data/StationProfile.h" #include "core/debug.h" #include #include #include MODULE_IDENTIFICATION("qlog.data.stationprofile"); QDataStream& operator<<(QDataStream& out, const StationProfile& v) { out << v.profileName << v.callsign << v.locator << v.operatorName << v.operatorCallsign << v.qthName << v.iota << v.sota << v.sig << v.sigInfo << v.vucc << v.wwff << v.pota << v.ituz << v.cqz << v.dxcc << v.country << v.county << v.darcDOK; return out; } QDataStream& operator>>(QDataStream& in, StationProfile& v) { in >> v.profileName; in >> v.callsign; in >> v.locator; in >> v.operatorName; in >> v.operatorCallsign; in >> v.qthName; in >> v.iota; in >> v.sota; in >> v.sig; in >> v.sigInfo; in >> v.vucc; in >> v.wwff; in >> v.pota; in >> v.ituz; in >> v.cqz; in >> v.dxcc; in >> v.country; in >> v.county; in >> v.darcDOK; return in; } StationProfilesManager::StationProfilesManager() : ProfileManagerSQL("station_profiles") { FCT_IDENTIFICATION; QSqlQuery profileQuery; if ( ! profileQuery.prepare("SELECT profile_name, callsign, locator, " "operator_name, qth_name, iota, sota, sig, sig_info, vucc, pota, " "ituz, cqz, dxcc, country, county, operator_callsign, darc_dok " "FROM station_profiles") ) { qWarning()<< "Cannot prepare select"; } if ( profileQuery.exec() ) { while (profileQuery.next()) { StationProfile profileDB; profileDB.profileName = profileQuery.value(0).toString(); profileDB.callsign = profileQuery.value(1).toString(); profileDB.locator = profileQuery.value(2).toString(); profileDB.operatorName = profileQuery.value(3).toString(); profileDB.qthName = profileQuery.value(4).toString(); profileDB.iota = profileQuery.value(5).toString(); profileDB.sota = profileQuery.value(6).toString(); profileDB.sig = profileQuery.value(7).toString(); profileDB.sigInfo = profileQuery.value(8).toString(); profileDB.vucc = profileQuery.value(9).toString(); profileDB.pota = profileQuery.value(10).toString(); profileDB.ituz = profileQuery.value(11).toInt(); profileDB.cqz = profileQuery.value(12).toInt(); profileDB.dxcc = profileQuery.value(13).toInt(); profileDB.country = profileQuery.value(14).toString(); profileDB.county = profileQuery.value(15).toString(); profileDB.operatorCallsign = profileQuery.value(16).toString(); profileDB.darcDOK = profileQuery.value(17).toString(); addProfile(profileDB.profileName, profileDB); } } else { qInfo() << "Station Profile DB select error " << profileQuery.lastError().text(); } } void StationProfilesManager::save() { FCT_IDENTIFICATION; QSqlQuery deleteQuery; QSqlQuery insertQuery; if ( ! deleteQuery.prepare("DELETE FROM station_profiles") ) { qWarning() << "cannot prepare Delete statement"; return; } if ( ! insertQuery.prepare("INSERT INTO station_profiles(profile_name, callsign, locator, operator_name, qth_name, iota, sota, sig, sig_info, vucc, wwff, pota, ituz, cqz, dxcc, country, county, operator_callsign, darc_dok) " "VALUES (:profile_name, :callsign, :locator, :operator_name, :qth_name, :iota, :sota, :sig, :sig_info, :vucc, :wwff, :pota, :ituz, :cqz, :dxcc, :country, :county, :operator_callsign, :darc_dok)") ) { qWarning() << "cannot prepare Insert statement"; return; } if ( deleteQuery.exec() ) { const QStringList &keys = profileNameList(); for ( const QString &key : keys ) { StationProfile stationProfile = getProfile(key); insertQuery.bindValue(":profile_name", key); insertQuery.bindValue(":callsign", stationProfile.callsign); insertQuery.bindValue(":locator", stationProfile.locator); insertQuery.bindValue(":operator_name", stationProfile.operatorName); insertQuery.bindValue(":qth_name", stationProfile.qthName); insertQuery.bindValue(":iota", stationProfile.iota); insertQuery.bindValue(":sota", stationProfile.sota); insertQuery.bindValue(":sig", stationProfile.sig); insertQuery.bindValue(":sig_info", stationProfile.sigInfo); insertQuery.bindValue(":vucc", stationProfile.vucc); insertQuery.bindValue(":wwff", stationProfile.wwff); insertQuery.bindValue(":pota", stationProfile.pota); insertQuery.bindValue(":ituz", stationProfile.ituz); insertQuery.bindValue(":cqz", stationProfile.cqz); insertQuery.bindValue(":dxcc", stationProfile.dxcc); insertQuery.bindValue(":country", stationProfile.country); insertQuery.bindValue(":county", stationProfile.county); insertQuery.bindValue(":operator_callsign", stationProfile.operatorCallsign); insertQuery.bindValue(":darc_dok", stationProfile.darcDOK); if ( ! insertQuery.exec() ) { qInfo() << "Station Profile DB insert error " << insertQuery.lastError().text() << insertQuery.lastQuery(); } } } else { qInfo() << "Station Profile DB delete error " << deleteQuery.lastError().text(); } saveCurProfile1(); } StationProfile StationProfilesManager::findByCallsign(const QString &callsign) { FCT_IDENTIFICATION; qCDebug(function_parameters) << callsign; const QStringList &names = profileNameList(); for ( const QString &name : names ) { StationProfile profile = getProfile(name); if ( profile.callsign.compare(callsign, Qt::CaseInsensitive) == 0 ) return profile; } return StationProfile(); } bool StationProfile::operator==(const StationProfile &profile) { return (profile.profileName == this->profileName && profile.callsign == this->callsign && profile.locator == this->locator && profile.operatorName == this->operatorName && profile.qthName == this->qthName && profile.iota == this->iota && profile.sota == this->sota && profile.sig == this->sig && profile.sigInfo == this->sigInfo && profile.vucc == this->vucc && profile.wwff == this->wwff && profile.pota == this->pota && profile.ituz == this->ituz && profile.cqz == this->cqz && profile.dxcc == this->dxcc && profile.country == this->country && profile.county == this->county && profile.operatorCallsign == this->operatorCallsign && profile.darcDOK == this->darcDOK ); } bool StationProfile::operator!=(const StationProfile &profile) { return !operator==(profile); } QString StationProfile::toHTMLString() const { QString ret = "" + QObject::tr("Logging Station Callsign") + ": " + callsign + "
" + ((!locator.isEmpty()) ? "" + QObject::tr("My Gridsquare") + ": " + locator + "
" : "") + ((!operatorName.isEmpty()) ? "" + QObject::tr("Operator Name") + ": " + operatorName + "
" : "") + ((!operatorCallsign.isEmpty()) ? "" + QObject::tr("Operator Callsign") + ": " + operatorCallsign + "
" : "") + ((!qthName.isEmpty()) ? "" + QObject::tr("My City") + ": " + qthName + "
" : "") + ((!country.isEmpty()) ? "" + QObject::tr("My Country") + ": " + country + "
" : "") + ((!county.isEmpty()) ? "" + QObject::tr("My County") + ": " + county + "
" : "") + ((!iota.isEmpty()) ? "" + QObject::tr("My IOTA") + ": " + iota + "
" : "") + ((!sota.isEmpty()) ? "" + QObject::tr("My SOTA") + ": " + sota + "
" : "" ) + ((!sig.isEmpty()) ? "" + QObject::tr("My Special Interest Activity") + ": " + sig + "
" : "" )+ ((!sigInfo.isEmpty()) ? "" + QObject::tr("My Spec. Interes Activity Info") + ": " + sigInfo + "
" : "" )+ ((!vucc.isEmpty()) ? "" + QObject::tr("My VUCC Grids") + ": " + vucc + "
" : "") + ((!wwff.isEmpty()) ? "" + QObject::tr("My WWFF") + ": " + wwff + "
" : "") + ((!pota.isEmpty()) ? "" + QObject::tr("My POTA Ref") + ": " + pota : "") + ((!pota.isEmpty()) ? "" + QObject::tr("My DARC DOK") + ": " + darcDOK : "") + ((ituz != 0) ? "" + QObject::tr("My ITU") + ": " + QString::number(ituz) : "") + " " + ((cqz != 0) ? "" + QObject::tr("My CQZ") + ": " + QString::number(cqz) : "") + " " + ((dxcc != 0) ? "" + QObject::tr("My DXCC") + ": " + QString::number(dxcc) : ""); return ret; } QString StationProfile::getContactInnerJoin() const { QStringList ret({"contacts.station_callsign = station_profiles.callsign", "contacts.my_gridsquare = station_profiles.locator"}); auto addIfNoEmpty = [&](const QString &field, const QString& contact, const QString &profile) { if ( ! field.isEmpty() ) ret << "contacts." + contact + " = station_profiles." + profile; }; auto addIfNoEmptyNumber = [&](int field, const QString& contact, const QString &profile) { if ( field ) ret << "contacts." + contact + " = station_profiles." + profile; }; addIfNoEmpty(operatorName, "my_name_intl", "operator_name"); addIfNoEmpty(qthName, "my_city_intl", "qth_name"); addIfNoEmpty(iota, "my_iota", "iota"); addIfNoEmpty(sota, "my_sota", "sota"); addIfNoEmpty(sig, "my_sig_intl", "sig"); addIfNoEmpty(sigInfo, "my_sig_info_intl", "sig_info"); addIfNoEmpty(vucc, "my_vucc_grids", "vucc"); addIfNoEmpty(wwff, "my_wwff_ref", "wwff"); addIfNoEmpty(pota, "my_pota_ref", "pota"); addIfNoEmptyNumber(ituz, "my_itu_zone", "ituz"); addIfNoEmptyNumber(cqz, "my_cq_zone", "cqz"); addIfNoEmptyNumber(dxcc, "my_dxcc", "dxcc"); // skipping Country - depends on dxcc addIfNoEmpty(county, "my_cnty", "county"); addIfNoEmpty(operatorCallsign, "operator", "operator_callsign"); addIfNoEmpty(darcDOK, "my_darc_dok", "darc_doc"); return "(" + ret.join(" AND ") + ")"; } foldynl-QLog-3252ff9/data/StationProfile.h000066400000000000000000000027241517334601000204140ustar00rootroot00000000000000#ifndef QLOG_DATA_STATIONPROFILE_H #define QLOG_DATA_STATIONPROFILE_H #include #include #include #include #include #include #include "data/ProfileManager.h" class StationProfile { public: StationProfile() : ituz(0), cqz(0), dxcc(0) {}; QString profileName; QString callsign; QString locator; QString operatorName; QString operatorCallsign; QString qthName; QString iota; QString pota; QString sota; QString sig; QString sigInfo; QString vucc; QString wwff; int ituz; int cqz; int dxcc; QString country; QString county; QString darcDOK; bool operator== (const StationProfile &profile); bool operator!= (const StationProfile &profile); QString toHTMLString() const; QString getContactInnerJoin() const; private: friend QDataStream& operator<<(QDataStream& out, const StationProfile& v); friend QDataStream& operator>>(QDataStream& in, StationProfile& v); }; Q_DECLARE_METATYPE(StationProfile) class StationProfilesManager : public ProfileManagerSQL { Q_OBJECT public: explicit StationProfilesManager(); ~StationProfilesManager() {}; static StationProfilesManager* instance() { static StationProfilesManager instance; return &instance; }; void save(); StationProfile findByCallsign(const QString &callsign); }; #endif // QLOG_DATA_STATIONPROFILE_H foldynl-QLog-3252ff9/data/ToAllSpot.h000066400000000000000000000004031517334601000173230ustar00rootroot00000000000000#ifndef QLOG_DATA_TOALLSPOT_H #define QLOG_DATA_TOALLSPOT_H #include #include "data/Dxcc.h" class ToAllSpot { public: QDateTime time; DxccEntity dxcc_spotter; QString spotter; QString message; }; #endif // QLOG_DATA_TOALLSPOT_H foldynl-QLog-3252ff9/data/UpdatableSQLRecord.cpp000066400000000000000000000046011517334601000214210ustar00rootroot00000000000000#include #include "UpdatableSQLRecord.h" #include "core/debug.h" MODULE_IDENTIFICATION("qlog.core.updatableqslrecord"); UpdatableSQLRecord::UpdatableSQLRecord(int interval, QObject *parent) : QObject{parent}, interval(interval) { FCT_IDENTIFICATION; connect(&timer, &QTimer::timeout, this, &UpdatableSQLRecord::emitStoreRecord); } UpdatableSQLRecord::~UpdatableSQLRecord() { FCT_IDENTIFICATION; timer.stop(); } void UpdatableSQLRecord::updateRecord(const QSqlRecord &record) { FCT_IDENTIFICATION; if ( internalRecord.isEmpty() ) { internalRecord = record; qCDebug(runtime) << "Record is empty, starting timer" << interval; timer.start(interval); return; } else if ( !matchQSO(QSOMatchingType, record) ) { qCDebug(runtime) << "Records do not match"; timer.stop(); emitStoreRecord(); internalRecord = record; } else { qCDebug(runtime) << "Records match"; timer.stop(); for ( int i = 0; i < record.count(); ++i ) { const QString &fieldName = record.fieldName(i); if ( !internalRecord.contains(fieldName) ) internalRecord.append(record.field(i)); else if ( !record.value(i).toString().isEmpty() && internalRecord.value(fieldName).toString().isEmpty() ) internalRecord.setValue(fieldName, record.value(i)); } } qCDebug(runtime) << "starting timer" << interval; timer.start(interval); } void UpdatableSQLRecord::emitStoreRecord() { FCT_IDENTIFICATION; timer.stop(); if ( internalRecord.isEmpty() ) return; qCDebug(runtime) << "emitting record"; emit recordReady(internalRecord); internalRecord.clear(); } bool UpdatableSQLRecord::matchQSO(const MatchingType matchingType, const QSqlRecord &record) { FCT_IDENTIFICATION; const QStringList &fields = matchingFields.value(matchingType); for ( const QString &fieldName : fields ) { qCDebug(runtime) << "compare field name " << fieldName << "In value" << internalRecord.value(fieldName) << "New value" << record.value(fieldName); if ( internalRecord.value(fieldName) != record.value(fieldName)) return false; } return true; } foldynl-QLog-3252ff9/data/UpdatableSQLRecord.h000066400000000000000000000015621517334601000210710ustar00rootroot00000000000000#ifndef QLOG_DATA_UPDATABLESQLRECORD_H #define QLOG_DATA_UPDATABLESQLRECORD_H #include #include #include #include class UpdatableSQLRecord : public QObject { Q_OBJECT public: explicit UpdatableSQLRecord(int interval = 500, QObject *parent = nullptr); ~UpdatableSQLRecord(); void updateRecord(const QSqlRecord &record); signals: void recordReady( QSqlRecord ); private slots: void emitStoreRecord(); private: enum MatchingType{ QSOMatchingType }; QHash matchingFields { {QSOMatchingType, {"callsign", "mode", "submode"}} }; bool matchQSO(const MatchingType, const QSqlRecord &); QSqlRecord internalRecord; QTimer timer; int interval; }; #endif // QLOG_DATA_UPDATABLESQLRECORD_H foldynl-QLog-3252ff9/data/WCYSpot.h000066400000000000000000000004521517334601000167560ustar00rootroot00000000000000#ifndef QLOG_DATA_WCYSPOT_H #define QLOG_DATA_WCYSPOT_H #include class WCYSpot { public: QDateTime time; quint16 KIndex; quint16 expK; quint16 AIndex; quint16 RIndex; quint16 SFI; QString SA; QString GMF; QString Au; }; #endif // QLOG_DATA_WCYSPOT_H foldynl-QLog-3252ff9/data/WWFFEntity.h000066400000000000000000000007101517334601000174110ustar00rootroot00000000000000#ifndef QLOG_DATA_WWFFENTITY_H #define QLOG_DATA_WWFFENTITY_H #include class WWFFEntity { public: QString reference; QString status; QString name; QString program; QString dxcc; QString state; QString county; QString continent; QString iota; QString iaruLocator; double latitude; double longitude; QString iucncat; QDate validFrom; QDate validTo; }; #endif // QLOG_DATA_WWFFENTITY_H foldynl-QLog-3252ff9/data/WWVSpot.h000066400000000000000000000003711517334601000167770ustar00rootroot00000000000000#ifndef QLOG_DATA_WWVSPOT_H #define QLOG_DATA_WWVSPOT_H #include class WWVSpot { public: QDateTime time; quint16 SFI; quint16 AIndex; quint16 KIndex; QString info1; QString info2; }; #endif // QLOG_DATA_WWVSPOT_H foldynl-QLog-3252ff9/data/WsjtxDecode.h000066400000000000000000000020361517334601000176710ustar00rootroot00000000000000#ifndef QLOG_DATA_WSJTXDECODE_H #define QLOG_DATA_WSJTXDECODE_H #include #include class WsjtxDecode { public: QString id, mode, message; bool is_new, low_confidence, off_air; QTime time; qint32 snr; quint32 df; double dt; operator QString() const { return QString("WsjtxDecode: ") + "(" + "ID: " + id + "; " + "IsNew: " + QString::number(is_new) + "; " + "Time: " + time.toString() + "; " + "SNR: " + QString::number(snr) + "; " + "DeltaTime: " + QString::number(dt) + "; " + "DeltaFreq: " + QString::number(df) + "; " + "Mode: " + mode + "; " + "Message: " + message + "; " + "LowConfidence: " + QString::number(low_confidence) + "; " + "OffAir: " + QString::number(off_air) + "; " + ")"; } }; #endif // QLOG_DATA_WSJTXDECODE_H foldynl-QLog-3252ff9/data/WsjtxEntry.h000066400000000000000000000024201517334601000176040ustar00rootroot00000000000000#ifndef QLOG_DATA_WSJTXENTRY_H #define QLOG_DATA_WSJTXENTRY_H #include "data/WsjtxDecode.h" #include "data/DxSpot.h" class WsjtxEntry : public DxSpot { public: WsjtxDecode decode; QString grid; double distance; QDateTime receivedTime; QString decodedMode; WsjtxEntry() : DxSpot(), distance(0.0){}; WsjtxEntry(const DxSpot &other) : DxSpot(other), distance(0.0) {}; operator QString() const { return QString("WsjtxEntry ") + "Country: " + QString::number(dxcc.dxcc) + " " + "CQZ" + QString::number(dxcc.cqz) + " " + "ITUZ" + QString::number(dxcc.ituz) + " " + "Status: " + QString::number(status) + " " + "Band: " + band + " " + "ModeGroup: " + (BandPlan::isFTxMode(decodedMode) ? BandPlan::MODE_GROUP_STRING_FTx : BandPlan::MODE_GROUP_STRING_DIGITAL ) + " " + "spotter Country: " + QString::number(dxcc_spotter.dxcc) + " " + "Continent: " + dxcc.cont + " " + "Spotter Continent: " + dxcc_spotter.cont + " " + "Callsign: " + callsign + " " + "Message: " + decode.message + " " + "DX Member: " + memberList2StringList().join(", "); }; }; #endif // QLOG_DATA_WSJTXENTRY_H foldynl-QLog-3252ff9/data/WsjtxLog.h000066400000000000000000000027121517334601000172300ustar00rootroot00000000000000#ifndef QLOG_DATA_WSJTXLOG_H #define QLOG_DATA_WSJTXLOG_H #include #include class WsjtxLog { public: QString id, dx_call, dx_grid, mode, rprt_sent, rprt_rcvd; QString tx_pwr, comments, name, op_call, my_call, my_grid, prop_mode; QString exch_sent, exch_rcvd; QDateTime time_on, time_off; quint64 tx_freq; operator QString() const { return QString("WsjtxLog: ") + "(" + "ID: " + id + "; " + "DateTimeOff: " + time_off.toString() + "; " + "DXCall: " + dx_call + "; " + "DXGrid: " + dx_grid + "; " + "TXFreq: " + QString::number(tx_freq) + "; " + "Mode: " + mode + "; " + "RrpSent: " + rprt_sent + "; " + "RrpRcvd: " + rprt_rcvd + "; " + "TxPower: " + tx_pwr + "; " + "Comments: " + comments + "; " + "Name: " + name + "; " + "DateTimeOn: " + time_on.toString() + "; " + "OpCall: " + op_call + "; " + "MyCall: " + my_call + "; " + "MyGrid: " + my_grid + "; " + "ExchSent: " + exch_sent + "; " + "ExchRcvd: " + exch_rcvd + "; " + "ADIFPropMode: " + prop_mode + "; " + ")"; } }; #endif // QLOG_DATA_WSJTXLOG_H foldynl-QLog-3252ff9/data/WsjtxLogADIF.h000066400000000000000000000006101517334601000176470ustar00rootroot00000000000000#ifndef QLOG_DATA_WSJTXLOGADIF_H #define QLOG_DATA_WSJTXLOGADIF_H #include class WsjtxLogADIF { public: QString id, log_adif; operator QString() const { return QString("WsjtxLogADIF") + "(" + "ID: " + id + ";" + "ADIF: " + log_adif + ";" + ")"; } }; #endif // QLOG_DATA_WSJTXLOGADIF_H foldynl-QLog-3252ff9/data/WsjtxStatus.h000066400000000000000000000036651517334601000200020ustar00rootroot00000000000000#ifndef QLOG_DATA_WSJTXSTATUS_H #define QLOG_DATA_WSJTXSTATUS_H #include class WsjtxStatus { public: QString id, mode, tx_mode, sub_mode; QString dx_call, dx_grid, de_call, de_grid; QString report; quint64 dial_freq; qint32 rx_df, tx_df; bool tx_enabled, transmitting, decoding; bool tx_watchdog, fast_mode; quint8 special_op_mode; quint32 freq_tolerance, tr_period; QString conf_name, tx_message; operator QString() const { return QString("WsjtxStatus: ") + "(" + "ID: " + id + "; " + "Dial: " + QString::number(dial_freq) + "; " + "Mode: " + mode + "; " + "DXCall: " + dx_call + "; " + "Report: " + report + "; " + "TXMode: " + tx_mode + "; " + "TXEnabled: " + QString::number(tx_enabled) + "; " + "Transmitting: " + QString::number(transmitting) + "; " + "Decoding: " + QString::number(decoding) + "; " + "RxDF: " + QString::number(rx_df) + "; " + "TxDF: " + QString::number(tx_df) + "; " + "DECall: " + de_call + "; " + "DEGrid: " + de_grid + "; " + "DXGrid: " + dx_grid + "; " + "TXWatchdog: " + QString::number(tx_watchdog) + "; " + "SubMode: " + sub_mode + "; " + "FastMode: " + QString::number(fast_mode) + "; " + "SpecOpMode: " + QString::number(special_op_mode) + "; " + "FreqTolerance: "+ QString::number(freq_tolerance) + "; " + "TRPeriod: " + QString::number(tr_period) + "; " + "ConfName: " + conf_name + "; " + "TXMessage: " + tx_message + "; " + ")"; } }; #endif // QLOG_DATA_WSJTXSTATUS_H foldynl-QLog-3252ff9/debian/000077500000000000000000000000001517334601000156055ustar00rootroot00000000000000foldynl-QLog-3252ff9/debian/changelog000066400000000000000000001433761517334601000174750ustar00rootroot00000000000000qlog (0.50.0-1) UNRELEASED; urgency=low * [NEW] - Added Split detection * [NEW] - Added Developer and Support tools (PR #991 @aa5sh @foldynl) * [NEW] - Added a simple QSL label printing dialog (issue #562) * [NEW] - Added Cabrillo contest export * [NEW] - Added direct labeling of QSL Requested and QSL Received to the QSO context menu (PR #982 @aa5sh) * [NEW] - DXCC Submission Report (PR #967 @aa5sh) * [NEW] - DXC - Search pre-fills the callsign from New Contact if callsign is present * [NEW] - Settings - Added Danger Zone tab with Delete all passwords and QSOs * [CHANGED] - Mutex-free Omnirig1 and Omnirig2 * [CHANGED] - POTA/SOTA/WWFF/SAT list are download from QLog LOV-repo * [CHANGED] - Used an external lib for CSV parsing for LOV Download * [CHANGED] - Import - ADIF import updates DXCC only if it is missing in the QSO (issue #983) * [REMOVED] - Import - ADIF import does not include the option to update DXCC during the import - no longer needed * Fixed Callsign disappears when calling a DX in a split via VFO-B (issue #799) * Fixing Rendering issue (issue #989) * Updated debian packaging (PR @979 thx @dawkagaming) * Hamlib rigctld switching between VFO A/B doesnt change the band mode - added workaround (issue #999) * Awards internal redesign * Removed AN from the WAC award (issue #1010) -- foldynl Sun, 26 Apr 2026 10:25:10 +0200 qlog (0.49.1-1) UNRELEASED; urgency=low * Fixed Online Map OSM Access Blocked banner (issue #956) * Fixed Package build process issue - openssl-dev is missing (issue #957) * Fixed Missing dependence for QTKeychain (issue #964) * Added French Translation (PR #969 thx @fillods) -- foldynl Thu, 19 Mar 2026 12:18:46 +0100 qlog (0.49.0-1) UNRELEASED; urgency=low * [NEW] - Added Pack and Unpack Data and Setting - Computer to Computer Migration (issue #535) * [NEW] - Added Rig Sharing via Rigctld (PR #736 issue #159 @aa5sh @foldynl) * [NEW] - Added QSL Gallery * [NEW] - QSO Filter - Added REGEXP operator * [NEW] - Settings - TQSL - Added Path auto-detect and validation * [NEW] - Upload QSO - Added LoTW Station Location Combo (PR #929 @TrgoSk @foldynl) * [NEW] - QSO Export - Added Station Profile Filter * [NEW] - BandMap shows emergency frequencies (issue #462) * [NEW] - Added Speed Up Down Macros - WinKey and CWDaemon (issue #491) * [NEW] - Settings Winkey v2 - Added PaddleOnly Sidetone (issue #739) * [NEW] - Settings Winkey v2 and CWDaemon - Added Sidetone Freq * [NEW] - All County fields contain Completer for Ukraine, US, Japan, NZ, Spanish, Russia (PR #785 @aa5sh @foldynl) * [NEW] - Added County Awards for Ukraine, US, Japan, NZ, Spanish, Russia (PR #785 @aa5sh @foldynl) * [NEW] - ADIF 3.1.7 - Added new modes FT2, FREEDATA, RIBBIT_PIX, RIBBIT_SMS (issue #934) * [CHANGED] - Generic FTx for FT8/FT4 (FT2) in Alert and DXC filter (issue #937) * [CHANGED] - LoTW QSL matching algorithm uses Mode and Mode Group matching (issue #942) * [CHANGED] - Reduced download period for DXCC Entities from 21 to 7 days * LogbookWidget: Delete Performance Optimization * Fixed Awards POTA Activator Filter * Fixed man page * Fixing SATmode Activity is blank (issue #948) -- foldynl Fri, 13 Mar 2026 18:56:51 +0100 qlog (0.48.0-1) UNRELEASED; urgency=low * [NEW] - Rig Widget - tuning rig with mouse (issue #855) * [NEW] - Awards - Added User Filter Combo (issue #870) * [NEW] - Statistics - Added User Filter; new Dialog layout (issue #870) * [NEW] - Alerts - Added detailed Log Status settings (issue #817) * [NEW] - Settings - Enable/Disable sending color-coded status indicators back to WSJT-X (issue #885 @aa5sh @foldynl) * [CHANGED] - Omnirig Drivers: Removed QT AXContainers - pure Windows API code * [CHANGED] - Enabled Chekbox in Alerts Table (issue #867) * [CHANGED] - Serial Port Completer contains Horizontal ScrollBar * [CHANGED] - TCI - Settings - Default PWR defines the maximum output power * Fixed Omnirig drivers keep sending frequency change (issue #872) * Fixed ADIF import does not accept a default operator name (issue #884) * Fixed HamQTH URL from http to https (PR #886 @aa5sh) * Fixed Missing Band value when QSO from FLDigi (issue #892) -- foldynl Fri, 30 Jan 2026 16:28:43 +0100 qlog (0.47.1-1) UNRELEASED; urgency=low * [CHANGED] - DXC - VE7CC-type Cluster is correctly detected (PR #851 @kyleboyle) * [CHANGED] - Chat - Changed ON4KST URL (issue #857) * Fixed missing clear button for Search Callsign (issue #753) * Fixed Updated QSOs are not sent to wavelog (issue #847) * Fixed Fixed Omnirig(v2) getFreq, getVFO, setFreq (issue #853) * Fixed ADI Header does not follow ADIF Spec (issue #859) * Fixed OmniRig settings are not saved (issue #862) -- foldynl Fri, 19 Dec 2025 15:56:45 +0100 qlog (0.47.0-1) UNRELEASED; urgency=low * [NEW] - Adds theme options - native, light, dark (PR #718 @kyleboyle) * [NEW] - Implemented ADIF 3.1.6 * [NEW] - ADIF 3.1.6 - Added new modes FSK and MTONE * [NEW] - ADIF 3.1.6 - Added new contest IDs * [NEW] - ADIF 3.1.6 - Added new column EQSL_AG (Import/Export only) * [NEW] - Statistics, QSODetail contain deleted DXCC Entities (PR #728 @aa5sh @foldynl) * [NEW] - Settings Hamlib - Added support to define CIV Addr for Icom and Ten-Tec (issue #747) * [NEW] - Settings Hamlib - Added RTS and DTR control (PR #809 @aa5sh) * [NEW] - Settings GUI - Added options to switch distance unit * [NEW] - Added Linux manpage (PR #791 @dawkagaming) * [NEW] - Added a link to the GitHub release notes under Help-Whats New * [NEW] - Added workaround for WriteLog - always call callbook lookups (PR #833 @sjwoodr) * [NEW] - Awards - Added Not-Confirmed filter (PR #836 @aa5sh) * [NEW] - Rotator Widget - Added buttons to change button profiles * [CHANGED] - Settings - Added network loop detection for WSJTX Forward (issue #815 @aa5sh @foldynl) * [CHANGED] - Rotator - Rotator timeout is set to 5s (PR #823 @aa5sh) * [CHANGED] - Double Spin Boxes - the decimal separator is forced to be a period * [DELETED] - WSJTX Widget - Removed Freq and Mode * Fixed QSODetail - Anti-meridian bug on map (issue #786) * Fixed Statistics: Center maps on QTH longitude (issue #824) * Fixed OmniRig disconnecting when its status changed unexpectedly (issue #832) -- foldynl Sat, 6 Dec 2025 12:59:15 +0100 qlog (0.46.2-1) UNRELEASED; urgency=high * Fixed Spaces after QRZ.com name (issue #767) * Fixed SPID Rot1Prog Rotator more 360 deg (issue #775) * Fixed build instructions on Debian (PR #777 @leventelist) * Fixed Bandmap truncated output despite having space (issue #779) * Fixed Statistics - Anti-meridian bug on map (issue #786) * Fixed Binary file in the tarballs (issue #794) * Fixed LOTW and eQSL upload status updated even when nothing is uploaded (issue #807) * Fixed Imported QSOs contain incorrect My DXCC info (issue #812) * Fixed Statistics Dialog does not show confirmed grids -- foldynl Fri, 31 Oct 2025 15:24:57 +0100 qlog (0.46.1-1) UNRELEASED; urgency=low * Fixed QSO filter incorrectly displays inserted date (issue #752) * Fixed Logbook Search Icon is not centered (issue #753) * Fixed Using CQRLog API Key for Clublog (issue #759) * Fixed Online Service Password leaking via debug files (issue #760) * Fixed Tabs are not showed properly (PR #762 @aa5sh) * Fixed inability to edit Power in QSO Detail (issue #763) -- foldynl Fri, 26 Sep 2025 17:14:06 +0200 qlog (0.46.0-1) UNRELEASED; urgency=low * [NEW] - NewContact: POTA/SOTA/WWFF/IOTA info is taken from the nearest spot (@aa5sh @foldynl) * [NEW] - DXSpots are sent to Flex Radio (PR #694 @aa5sh) * [NEW] - CWConsole - Added support for automatic periodic sending of CW Macros (issue #708) * [NEW] - Added mapping of Winkey hardware buttons to CW macro keys F1–F4 (issue #711) * [NEW] - Added Search Types to the Logbook Search Editbox (issue #733) * [NEW] - Rig - Periodic Rig status reporting independent of its changes (PR #730 @aa5sh) * [NEW] - Settings - Serial Port Completer for MacOS and Linux (PR #737 @aa5sh) * [NEW] - Hamlib - Attempt to send Power On when connecting the Rig * [NEW] - POTA Spots Info is received from the API at api.pota.app to improve POTA detection * [CHANGED] - Logbook Search Filter Widget - Added Search Widget * [CHANGED] - QSO Detail Country boxes use the new Search Filter Widget * [CHANGED] - NewContact - RST field uses the Overwrite Mode * [CHANGED] - NewContact - Default cursor position in RST is at the first character * [CHANGED] - Setting Dialog - Modes - Default Report can define cursor position * [CHANGED] - HamlibRot - Changed Poll Interval from 500 to 2000ms * Fixed DUPE is not detected for the first Contest QSO (issue #699) * Fixed FREQ_RX/BAND_RX is present only when RX and TX freqs are different (issue #714) * Fixed Repeated log recording (issue #722) * Fixed QSO Filter contains untranslated QSO items (issue #732) -- foldynl Fri, 12 Sep 2025 16:58:08 +0200 qlog (0.45.0-1) UNRELEASED; urgency=low * [NEW] - Single Dialog for Upload/Download Online Services (issue #448) * [NEW] - Added option to swap paddles to Winkey settings (issue #676) * [NEW] - Added native support for the FLRig interface (issue #679) * [NEW] - Added New Version Notification - only for MacOS and Windows (PR #669 @aa5sh) * [NEW] - QRZ Upload - Added support for multiple API Keys * [NEW] - Logbook - Added highlighting to the filter button when a filter is active * [NEW] - WSJTX - Filtered label is shown when filter is enabled * [NEW] - DXC - Filtered label is shown when filter is enabled * [NEW] - Added support to Upload Cloudlog/Wavelog * [NEW] - Add JS8 to legacy_modes.json (issue #677) * [CHANGED] - Unification Settings storage * [CHANGED] - Calculate distances according to IARU rules * Fixed missing Wsjtx Spot values in the AlertWindow -- foldynl Fri, 11 Jul 2025 16:17:43 +0200 qlog (0.44.1-1) UNRELEASED; urgency=low * Fixed Rotator Widget Seg Fault for new users (issue #666) -- foldynl Sun, 11 May 2025 07:30:56 +0200 qlog (0.44.0-1) UNRELEASED; urgency=low * [NEW] - Activity Manager - Added SKCC, UKSMG and FISTS as Dynamic Fields * [NEW] - QSO - FISTS, SKCC, and UKSMG are auto-filled from MembershipQE (issue #628) * [NEW] - Rotator - Added QSO destination needle (issue #644) * [NEW] - QSO Detail - Adds grayline and short path (PR #653 @kyleboyle) * [CHANGED] - Rotator - Needle colors correspond to the online map (issue #644) * Fixed TCI cw_macros must contain RigID (issue #663) * Fixed TCI setKeySpeed sets keyer and macros speed (issue #663) * Fixed Data mode missing in rig control window - rigctld (issue #660 @aa5sh) * Improved DXC Mode detection * Updated Simplified Chinese translation -- foldynl Fri, 9 May 2025 17:05:38 +0200 qlog (0.43.1-1) UNRELEASED; urgency=low * Fixed Click on PHONE DX Spots sets wrong mode (issue #453) * Fixed No freq via Omnirig for IC7400 (issue #639) -- foldynl Sat, 19 Apr 2025 10:05:24 +0200 qlog (0.43.0-1) UNRELEASED; urgency=low * [NEW] - Added support to receive QSOs from CSN SAT Device (PR #610 @aa5sh) * [NEW] - Bandmap - Multiple independent bandmap windows (PR #593 @kyleboyle @foldynl) * [NEW] - Winkey Keyer driver currently supports v1 and v2 hardware * [NEW] - QSO Detail - QSLs QSLr Msg is editable * [NEW] - Activity Manager - Added new dynamic field - QSL Message Send * [CHANGED] - HamlibDrv - Enabled Power, RIT, XIT, Morse for RIG Netctl * [CHANGED] - QSO Detail - QSLMSG replaced by QSLMSG_RCVD (issue #633) * [CHANGED] - eQSL Upload - Added an option to choose a QSLMsg field * [CHANGED] - eQSL Download - eQSL QSLMSG is stored to QLog QSLMSG_RCVD * [CHANGED] - eQSL Download - Added QSLMSG_RCVD merging - eQSL message is appended * Fixed Speed pot doesn't seem to work with a WinKeyer; double chars (issue #618) * Fixed BandMap Spots colour change after a QSO (issue #632) * Fixed Incorrect Field Mapping for Received eQSL Messages (issue #633) -- foldynl Fri, 4 Apr 2025 14:19:18 +0200 qlog (0.42.2-1) UNRELEASED; urgency=low * Fixed Logbook country translations (issue #608) * Fixed Unexpected dialog when QSO after contest (issue #614) * Fixed Statistics Widget does not display NULL continents (@aa5sh) * Fixed Statistics Widget does not display NULL Band, Mode * Fixed Statistics Widget TOP10 does not display removed DXCCs * Fixed Statistics Widget TOP10 does not display translated country names * Fixed Awards Widget does not display removed DXCCs -- foldynl Fri, 7 Mar 2025 15:19:11 +0100 qlog (0.42.1-1) UNRELEASED; urgency=low * Fixed Unexpected timezone info (issue #600) * Fixed DXCC Statistics picks more entities (issue #601) * Fixed a crash when no internet connection -- foldynl Sat, 22 Feb 2025 11:45:02 +0100 qlog (0.42.0-1) UNRELEASED; urgency=low * [NEW] - Awards - Added Slots - total over each band (issue #538) * [NEW] - Awards - Added Grid Award - 2/4/6 Chars grid (issue #564) * [NEW] - Settings - Added options to switch 12/24 time and date format (issue #573) * [NEW] - Activity Manager - Added new dynamic fields - Rig (issue #575) * [NEW] - LoTW Import - Fill missing information also for confirmed QSOs (@aa5sh) * [NEW] - Added CW macro QTH * [NEW] - DXC - Added 15min Trend * [CHANGED] - Changed IOTA LOV Source, the official web is used * [CHANGED] - CSV Export: Time and Date formats use ISO8601 format (issue #562) * [CHANGED] - Settings - Renamed Shortcuts to GUI tab * [CHANGED] - LOV - Improved LOV download performance (PR #582 @aa5sh) * Partial fix Windows State/Size does not save in case of fullscreen (issue #418) * Fixing TCI error when you change Rig (issue #526) * Fixed DXCC Award total worked confirmed counts included deleted entities (PR #588 @aa5sh) * Fixed Raspberry PI Flatpak - Import Select file dialog crashes (issue #589) * Suppressed the ability to edit Contest fields after the start (issue #590) -- foldynl Fri, 14 Feb 2025 18:45:25 +0100 qlog (0.41.1-1) UNRELEASED; urgency=low * Fixed compilation issue under Debian 12 (issue #571) * Fixed Incorrect GPL version in rpm/deb packages (issue #572) * Fixed MacOS floating utility window bug (PR #576 @kyleboyle) * Updated IT translation -- foldynl Tue, 21 Jan 2025 14:00:52 +0100 qlog (0.41.0-1) UNRELEASED; urgency=low * [NEW] - Logbook - Added a new context menu item - Update QSO from Callbook (issue #450 @aa5sh) * [NEW] - DIGI mode is used in case of DXC Digi Spots (issue #480) * [NEW] - DXC - Retrieve information about SOTA, POTA, IOTA and WWFF from comment (issue #482) * [NEW] - Alert - Added SOTA, POTA, IOTA and WWFF filter * [NEW] - Added the COM Port Completer for Windows platform (issue #490) * [NEW] - Settings - Added DXCC Confirmed By options (issue #508) * [NEW] - Added POTA Export Formatter (activator/hunter) (PR #514 @kyleboyle) * [NEW] - CW Console - CW Halt with the user-defined shortcut (issue #518) * [NEW] - Added an input parameter to save debug message to file * [NEW] - Logbook - Added sorting function to logbook table columns (PR #540 @kyleboyle) * [NEW] - Network Notification - Added Rig Status Notification * [NEW] - Implemented ADIF 3.1.5 * [NEW] - ADIF 3.1.5 - Added new submodes FSKH245 and FSKH105 for HELL * [NEW] - ADIF 3.1.5 - Added new contest IDs * [NEW] - ADIF 3.1.5 - Added new columns (Import/Export only) * [NEW] - ADIF 3.1.5 - Added My DARC DOK to Station Profile * [CHANGED] - Settings: disabled band and mode name modification * [CHANGED] - DX Stats contain all enabled bands (issue #538) * [CHANGED] - Removed Freq, TimeDate On/Off Data Type Indicators (issue #552) * [CHANGED] - ADIF 3.1.5 - VUCC and MY_VUCC can contain 6 or 4-chars locators * [CHANGED] - Stop exporting default value N for qsl_rcvd, qsl_sent, lotw/dcl/eslq_qsl_rcvd/sent * [CHANGED] - Extended QSL/Import Dupe matching rule to Callsign, Band, Mode, Time and Sat_Name (issue #563) * Fixed MacOS - keep floating windows visible on app unfocus (issue #530) * Fixed Contest Filter ignores the first QSO (issue #529) * Fixed It is not possible to quit Qlog with detached widgets Rot and Rig (issue #534) * Fixed ADX/CSV/JSON do not export non-ASCII chars (issue #542) * Fixed Checking the 60m checkbox in cluster filters allows 160m spots to appear (issue #543 @aa5sh) * Fixed Problems uploading to QRZ.com (issue #559 PR #561 @aa5sh) * Fixed DX Stat screen is jumping up/down * Fixed Omnirig drivers: Digi modes are not correclty recognized -- foldynl Sat, 11 Jan 2025 09:26:36 +0100 qlog (0.40.1-1) UNRELEASED; urgency=low * Fixed Bands - Added missing 8m band (issue #515) * Fixed CW Console - EXCSTR does not work properly (issue #517) * Fixed Activity Manager - Missing Propagation Mode None (issue #519) * Fixed QSO Filter - filter fields with random order (PR #525 @aa5sh) * Fixed TCI error when you change Rig (issue #526) * Fixed NewContact - satellite mode too wide (issue #527) -- foldynl Fri, 29 Nov 2024 12:07:56 +0100 qlog (0.40.0-1) UNRELEASED; urgency=low * [NEW] - Activity Manager - merged Layout Manager and profiles (issue #408) * [NEW] - Activity Manager - Added new dynamic fields - Contest fields, RX/TX Power * [NEW] - Added light support for contests (issue #345) * [NEW] - Added CW macros EXCHSTR, EXCHNR, EXCHNRN * [NEW] - Export Filter - Added user filter combo (original idea PR #476 @aa5sh) * [NEW] - New Contact - Added expand/collapse button to QSO field tab widget (PR #495 @kyleboyle) * [NEW] - Alert - Added CQZ and ITUZ filters * [NEW] - KSTChat - Added a new 40MHz room (PR #496 @kyleboyle) * [NEW] - Station Profile contains Operator Callsign (issue #441 @kyleboyle) * [NEW] - Station Profile contains County (issue #493 @kyleboyle) * [NEW] - Statistics - Adds time of day and better qso mapping (PR #501 @kyleboyle) * [NEW] - Bandmap - Tooltip shows a spotter callsign (PR #507 @Skittlebrau) * [CHANGED] - New Contact - Renamed DXCC Tab to DX Stats contains DXCC and Station Statistics (issue #477) * [CHANGED] - QSL Import dialog - Detail text is selectable by mouse and keyboard * [CHANGED] - Removed Main Menu Layout; Activity Manager is in the bottom-left corner * [CHANGED] - Removed Keep Options from the Equipment Menu - use Activity Manager for it * Fixed issue when CW is always selected after Settings exiting or connecting the Rig * Updated Timezone definition file - version 2024b -- foldynl Sun, 24 Nov 2024 09:12:01 +0100 qlog (0.39.0-1) UNRELEASED; urgency=low * [NEW] - DXC - Added Full-text search * [NEW] - Select S in RST Edit when focused (issue #454) * [NEW] - Alerts - Added Member Column * [CHANGED] - HamlibDrv Rig/Rot- Added multiplatform reliable sleep * [CHANGED] - Changed Backup policy * [CHANGED] - Logbook page size - improved performance * [CHANGED] - Logbook - CTRL-A (Select All) is disabled * [CHANGED] - Awards - Bands are displayed based on the Settings (issue #452) * [CHANGED] - WSJTX - More reliable detection of CQ stations (PR #471 @aa5sh) * [CHANGED] - WSJTX - SOTA/POTA/WWFF/SIG are being added to the logged QSO (PR #463 @aa5sh) * [CHANGED] - Stats - Add a confirmation dialog for displaying over 50k QSOs on the map * [CHANGED] - New Contact - Starting QSO Timer when Rig online and WSJTX Update Callsign Status is received * [CHANGED] - Added a postponed handling for Rig soft errors (issue #472) * Fixed WSJT-X does not emit band change if rig is disconnected (issue #447) * Fixed Wrong import of ADIF file of another log program (issue #455) * Fixed WSJTX log record is stored incorrectly if it contains non-ASCII chars(issue #458) * Fixed ADIF import does not import records with old DXCC Entities (issue #459) * Fixed ADIF import incorrectly uses Station Profile parameters (issue #461) * Fixed Logbook - QSO Table Column Width Does Not Stick (issue #464) * Fixed Alerts Window displays OOB Spots (issue #469) * Fixed Field values from past QSOs are used incorrectly in case of WSJTX QSOs (#issue 470) -- foldynl Sat, 5 Oct 2024 13:33:52 +0200 qlog (0.38.0-1) UNRELEASED; urgency=low * [NEW] - Logbook - Added Send DX Spot to the QSO Context Menu * [NEW] - DX Filter - Added Dedup Time/Freq difference setting (@aa5sh) * [NEW] - Rig Setting - Added RTS/DTR PTT Type support (issue #353) * [NEW] - Bandmap - Scrollbar position is saved per band (issue #415) * [NEW] - New Contact - Added a dynamic value completer for SIG field (issue #425) * [NEW] - Awards - Added SOTA/POTA/WWFF (@aa5sh issue #311) * [NEW] - Awards - Added Not-Worked Filter * [NEW] - New Contact - Added Long Path Azimuth info * [NEW] - POTA Fields allow a comma-delimited list of one or more POTA Refs * [NEW] - WSJTX tunes freq/mode like Rig if rig is disconnected * [CHANGED] - Alert Widget is a Dock Widget (issue #399) * [CHANGED] - QLog adds more information from callbook for WSJTX QSOs (issues #403 #405 #420) * [CHANGED] - File Open dialogs are not a native dialog under Linux (issue #427) * [CHANGED] - Profiles transferred to DB * [CHANGED] - LOV last_dates transferred to DB * [CHANGED] - DX Cluster - Login Callsign is always the base Callsign * [REMOVED] - Setting DXCC Date * Fix for MacOS Layout Geometry Restore (@aa5sh) * Fixed TQSL does not block GUI thread * Fixed MacOS build process (@aa5sh) -- foldynl Thu, 29 Aug 2024 11:11:09 +0200 qlog (0.37.2-1) UNRELEASED; urgency=low * Fixed Field QSL Send Via should be retained (issue #413) * Fixed Set rotator position fails if azimuth > 180 (issue #417) * Fixed Windows State/Size does not save in case of fullscreen (issue #418) * Fixed Significant rounding during azimuth calculation (issue #422) * Updated Simplified Chinese translation * Updated Spanish translaction * Added Italian translation (thx IK1VQY) -- foldynl Fri, 26 Jul 2024 13:54:11 +0200 qlog (0.37.1-1) UNRELEASED; urgency=low * Fixed QSO Table Callsign filter is not filled properly (issue #401) * Fixed DXC zero frequency for last QSO in case of FT8 QSOs (issue #404) * Fixed Callsign Context Menu does not work (issue #409) * Fixed QSO Detail Save and Edit buttons are not translated (issue #410) -- foldynl Wed, 10 Jul 2024 21:18:45 +0200 qlog (0.37.0-1) UNRELEASED; urgency=low * [NEW] - Added Shortcuts Editor (issue #293) * [NEW] - Added QO100 Bandplan to correctly categorize the DX Spots * [NEW] - Improveded detection of SH/DX SHF Spots * [NEW] - Online Map - Added WSJTX CQ Spots * [NEW] - WSJTX - Sortable View * [NEW] - Alerts - Sortable View * [NEW] - Added Spanish translation (thx LU1IDC) * [NEW[ - Added Search Callsign Clear Button (issue #396) * [CHANGED] - QRZ auth should be over POST with form data (issue #389) * [CHANGED] - Big CTY file is used * [CHANGED] - Callbook Country DXCC ID is used in case of difference from Big CTY * [CHANGED] - Removed ALT+W and CTRL+DEL shortcuts * [CHANGED] - Removed New Contact and Save Contact from Logbook Main Menu * Fixed Guantanamo KG4 Issue (issue #372) * Fixed QRZ Lookup Not Including Full Name - History (issue #388) * Fixed Spot Last QSO contains TX freq, should contain RX freq (issue #390) * Fixed Spot Last QSO must contain Freq in kHz (issue #391) * Fixed Bandmap select previous selected callsign issue (issue #394) * Fixed Malfunctioning tuning of WSJTX Alert spot * Fixed DXCC Status for FT4 Spots incorrectly identified in WSJTX -- foldynl Mon, 1 Jul 2024 16:01:04 +0200 qlog (0.36.0-1) UNRELEASED; urgency=low * [NEW] - WSJTX: Added support to received ADIF QSO Log record * [NEW] - Sat mode is derived from RX/TX Freq * [NEW] - Logbook filters change color when enabled * [NEW] - Frequency input boxes PageUp/Dn switches the band (issue #360) * [NEW] - CTRL + PgUp/Dn switch band on the connected rig - global shortcut (issue #360) * [NEW] - Added number of filtered QSOs (issue #374) * Fixed Callbook query does not work (issue #377) * Fixed Logbook columns are reordered after Delete (issue #383) * Fixed Missing Republic of Kosovo flag (issue #384) -- foldynl Fri, 7 Jun 2024 15:44:02 +0200 qlog (0.35.2-1) UNRELEASED; urgency=low * Improved delete performance; added delete progress bar (issue #351) * Fixed Password with plus is incorrectly sent to online services (issue #366) * Fixed Compilation issue under v4.6 (issue #368) * Fixed Network Rig configuration is not saved (issue #370) -- foldynl Tue, 21 May 2024 19:57:13 +0200 qlog (0.35.1-1) UNRELEASED; urgency=low * Fixed Free QRZ callbook - Name is not populating (issue #363) * Fixed Incorrect CW segment freqs (issue #365) -- foldynl Mon, 6 May 2024 19:28:13 +0200 qlog (0.35.0-1) UNRELEASED; urgency=low * [NEW] - Added Rot Interface PSTRotator Network * [NEW] - Added QSO/QSL Since option to eQSL Dialog * [NEW] - Bandmap - Current Mode segment visualisation * [NEW] - CW Console - Added Word/Whole mode switch * [NEW] - Added Callbook Profile Image Widget * [NEW] - ASCII conversion based on Text-Unidecode/iconv algorithm (issue #316 #350) * [NEW] - ITU/CQ Zones can be defined in Station Profile (issue #358) * [CHANGED] - Spacebar is used as a focus changer for fields where space is not allowed * [CHANGED] - Focus does not select text in the input fields * [CHANGED] - Force XCB under Linux Wayland * [CHANGED] - Bandmap - Added Callsign/Freq/Mode to tooltip (issue #355) * Fixed incorrect ADIF date format for clublog_qso_upload_date (issue #342) * Fixed The last name from Callbooks queries (issue #346) -- foldynl Fri, 3 May 2024 13:12:36 +0200 qlog (0.34.0-1) UNRELEASED; urgency=low * [NEW] - Rotator Widget - Azimuth by Clicking * [NEW] - Rotator Widget - QSO button provides Short/Long Path (issue #330) * [NEW] - Equipment Menu - Added Keep Options between application restart (issue #331) * Fixed TCI - Thetis Connection issue (issue #327) * Fixed TCI - Spots To Rig are not displayed (issue #328) * Fixed Bandmap unintentionally emits frequency labels (issue #333) * Fixed Failing to load grid square for G and EI SOTA summits (issue #336) * Fixed HRDLog On-Air message is not sent (issue #337) * Fixed Offline Map - Improved Path drawing -- foldynl Mon, 25 Mar 2024 13:54:20 +0100 qlog (0.33.1-1) UNRELEASED; urgency=critical * Fixed Rotator offline map is incorrectly centered (issue #324) * Fixed Hamlib integration not working (issue #325) * Fixed issue when Hamlib reopen rig caused Initialization Error * Fixed issue when Omnirig Drv did not emit rigIsReady signal -- foldynl Sat, 9 Mar 2024 13:37:01 +0100 qlog (0.33.0-1) UNRELEASED; urgency=low * [NEW] - Added Rig Interface TCI * [NEW] - Callbook search can be temporarily paused * Improved DXC Mode recognition * Fixed Modal dialog blinks - Windows platform (issue #315) * Fixed LoTW and eQSL download are only QSLs dowloads - button label changed (issue #318) * Fixed i18n: Country Names and Prop-modes are translated (issue #322) -- foldynl Fri, 8 Mar 2024 11:49:26 +0100 qlog (0.32.0-1) UNRELEASED; urgency=low * [NEW] - Added Rig Interface Omnirig v1 (Windows only) * [NEW] - Added Rig Interface Omnirig v2 (Windows only) * [NEW] - Clublog - Added Clear Clublog and reupload QSOs * [NEW] - Clublog - Added Real-time Insert/Update/Delete * [CHANGED] - Clublog - Upload callsign is derived from the Current Profile Callsign * Fixed clang linker failed issue (issue #301) * Fixed SAT Mode U/U missing (issue #308 PR #309 thanks ea5wa) * Fixed Multiple QSO selection. Callsigns modified by mistake (issue #310) * Fixed Callbook query cache is not properly cleared when Callbook settings change (issue #313) -- foldynl Sat, 10 Feb 2024 17:31:58 +0100 qlog (0.31.0-1) UNRELEASED; urgency=low * [NEW] - DXC - Improved Mode recognition * [NEW] - DXC - Switch Rig mode based on DXC Spot Mode (issue #217) * [NEW] - DXC - Added Spot Country Column (issue #273) * [NEW] - DXC - Added Menu for server management * [NEW] - DXC - Added Auto-connect to server * [NEW] - DXC - Added Keep QSOs Context Menu * [NEW] - DXC - Added Clear QSO Context Menu * [NEW] - DXC - Added support for SH/DX response parsing * [NEW] - DXC - Added support for username, password for connection * [CHANGED] - DXC - Commands Combo changed to function button with selectable function * [CHANGED] - DXC - DX Spot is prepared via DXC Command Line, Remark dialog was removed * [NEW] - Online Map - IBP station double-click tunes freq and switch Rig mode * [NEW] - Main Window - Current profile name is shown (issue #282) * [NEW] - Import - Details can be saved to file (issue #284) * [NEW] - Added Simplified Chinese translation (PR #285 thank BG7JAF) * [NEW] - New Contact - Enter saves QSO if QSO time is running (issue #293 - partial) * [NEW] - New Contact - Callsign Enter event saves QSO if no Callbook is active - Pileup Mode (issue #293) * [NEW] - RIG Widget - RIT/XIT are displayed with user-friendly units (issue #294) * [CHANGED] - SAT List download - Shortened download period for SAT list from 30 to 7 days * Fixed ADI Import is too slow (issue #270) * Improved Import/Export Performance * Fixed Missing Satellite Mode SX (issue #291) * Fixed QSO Detail - Issue when Sat-Name field was always disabled * Fixed RPM build - Installed (but unpackaged) metainfo file issue -- foldynl Fri, 5 Jan 2024 11:23:36 +0100 qlog (0.30.0-1) UNRELEASED; urgency=low * [NEW] - QSL Images are stored in the database * [NEW] - Added AppStream Metainfo File (PR #262 thanks AsciiWolf) * [NEW] - Added (WPX) prefix (issue #263) * [NEW] - Added WPX Award statistics * [NEW] - Added support for external translation files(issue #275) * [CHANGED] - Removed QSOID from Export dialog column setting (issue #258) * Fixed Date editor does not support NULL value in Logbook Direct Editor (issue #256) * Fixed duplicate entry in Windows Add or Remove - only Window platform (issue #260) * Fixed RST fields revert to 59 after changing them (issue #261) * Fixed Cannot change TQSL Path in Settings - flatpak (issue #271) -- foldynl Fri, 1 Dec 2023 16:23:18 +0100 qlog (0.29.2-1) UNRELEASED; urgency=low * Fixed QLog is already running error popup on MacOS (issue #257 thanks rjesson) -- foldynl Mon, 13 Nov 2023 14:46:57 +0100 qlog (0.29.1-1) UNRELEASED; urgency=low * Fixed QSL cards tooltip are not displayed under qt6.5 (issue #248) * Fixed Distance unit is not displayed in QSO Info under Windows (issue #250) * Fixed Editing STATION_CALLSIGN can cause unwanted change in QSO Detail (issue #251) * Fixed QSO Detail Operator Name containes an incorrect value (issue #252) * Fixed Calls with VE, VA are coding as Amsterdam & St Paul Islands instead of Canada (issue #253) * Fixed LoTW QSL import reports unmatched QSOs sometime (issue #254) -- foldynl Fri, 10 Nov 2023 08:50:15 +0100 qlog (0.29.0-1) UNRELEASED; urgency=low * [NEW] - Added user-defined layout for New QSO Detail widget * [NEW] - Main window State and Geometry can be saved to layout profile * [NEW] - Awards - Added WAS * [NEW] - Awards - WAZ/ITU/WAC show all possible values * [NEW] - Distance unit (km/miles) is controlled by OS Locale * [CHANGED] - Removed SAT Tab - field can be added via Layout Editor * Improved Import QSO performance * Fixed QLog crashes if POTA, SOTA or WWFF contain incorrect values (issue #245) * Fixed QSOs are not uploaded to QRZ and HRDLog if fields contain HTML delimiter strings (issue #247) -- foldynl Fri, 20 Oct 2023 15:58:36 +0200 qlog (0.28.0-1) UNRELEASED; urgency=low * [NEW] - Added ON4KST Chat Support * [NEW] - Added Az BeamWidth and Az Offset to Antenna Profile * [NEW] - Double-Clicking the IBP callsign in the online map tunes the frequency * Fixed Browse button should open an expecting folder (issue #241) * Fixed Reword QSL buttons and Settings in QSO Details and Settings (issue #242) -- foldynl Fri, 22 Sep 2023 16:26:02 +0200 qlog (0.27.0-1) UNRELEASED; urgency=low * [NEW] - Added HRDLog Support * Fixed Text field alignment (issue #233) * Fixed Rig/Rot Connection port type selection (issue #235) * Fixed Incorrect Distance Value in WSJTX Widget (issue #236) * Fixed Incorrect WSJTX locator target on the map (issue #237) -- foldynl Mon, 21 Aug 2023 19:32:02 +0200 qlog (0.26.0-1) UNRELEASED; urgency=low * [NEW] - Added user-defined layout for New QSO widget * [NEW] - Pressing Spacebar in Callsign field skips RST fields * [NEW] - Added user-defined URL for web lookup (issue #230) * Fixed WSJTX QSOs should have an Operator Name from Callbook (issue #223) * Fixed US call area suffixes not handled correctly (issue #226 thanks Florian) * Fixed QSO Filter Detail allows to save an empty Filter Name (issue #228) -- foldynl Sun, 30 Jul 2023 19:27:08 +0200 qlog (0.25.1-1) UNRELEASED; urgency=low * Fixed Unexpected mode change when Setting Dialog is saved (issue #222) * Fixed QSL_SENT field has an incorrect ADIF name (issue #225) -- foldynl Mon, 17 Jul 2023 13:49:01 +0200 qlog (0.25.0-1) UNRELEASED; urgency=low * [NEW] - Export - Added CSV Format * [NEW] - Export - Added Type of Export Generic/QSLs (issue #209) * [NEW] - Export - Added Exported Columns Setting * [NEW] - Export - All export formats use the ADIF field name convention * [CHANGED] - Export - JSON format contains a header - JSON format change * [CHANGED] - Default Statistics Interval is curr_date-1 and curr_day * Fixed Errors from Secure Storage are not shown (issue #216) * Fixed RX/TX Bands are uneditable when RX/TX freqs are missing (issue #220) -- foldynl Tue, 4 Jul 2023 15:05:16 +0200 qlog (0.24.0-1) UNRELEASED; urgency=low * Fixed Incorrect FT4 mode-submode (issue #212) * Fixed CONTESTIA mode should be CONTESTI (issue #213) * Fixed Context menu deselects NewContactEditLine (issue #215) * Fixed incorrect WSJTX Filter initialization (issue #218) -- foldynl Fri, 16 Jun 2023 12:20:54 +0200 qlog (0.23.0-1) UNRELEASED; urgency=low * [NEW] - Added CWDaemon Keyer Support * [NEW] - Added FLDigi Keyer Support * [NEW] - Online Map - based on locale, the map language is selected (Only EN, FR, GE supported - issue #180) * Fixed After entering longer QTH, the field content is not left-aligned (issue #157) * Fixed wrong QSO Time in case of JTDX (issue #204) * Fixed QSL Sent Date fields are not filled if QSL Sent Status fields are Y (issue #207) -- foldynl Fri, 9 Jun 2023 12:00:00 +0200 qlog (0.22.0-1) UNRELEASED; urgency=low * [NEW] - ADIF Import - My Profile is used to define default values * [NEW] - ADIF Import - Checking a minimal set of input fields (start_time, call, band, mode, station_callsign) * [NEW] - ADIF Import - Added Import Result Summary + Import Detail Info * [NEW] - Main Menu - Added Help -> Mailing List. * [NEW] - Export - Filter for the exported QSOs * [CHANGE] - Renamed Locator to Gridsquare * Fixed Some anomalies in the input and processing of QSLr Date (issue #192) * Fixed User unfriedly CW Keyer Error (issue #194) * Fixed ADIF import (issue #196) * Fixed Operator field is incorrectly used (issue #197) * Fixed Crash if an unknown POTA & SOTA/WWFF Setting is entered (issue #198) * Fixed FLDIGI cannot connect QLog (issue #199) * Fixed if ADIF record is missing band info, add this from freq field (thx DJ5CW) -- foldynl Sun, 7 May 2023 10:00:00 +0200 qlog (0.21.0-1) UNRELEASED; urgency=low * [NEW] - Rotator - Added Used-Defined Buttons * [NEW] - Rotator - Added Destination Azimuth Needle * [NEW] - Online Map - Added Antenna Beam Path * [NEW] - Rig - Combos are disbled when disconnected * [NEW] - Club Member Lists (issue #60) * [NEW] - Alert Table shows rule names * [CHANGED] - Alerts, DXC and WSJTX Network Notifications * Fixed Antenna Azimuth Negative Value (issue #191) * Fixed CTY file is not loaded when duplicate record (issue #193) -- foldynl Tue, 16 Apr 2023 10:00:00 +0200 qlog (0.20.0-1) UNRELEASED; urgency=low * [NEW] - Added MUF Layer to online map * [NEW] - Added International Beacon Project (IBP) Beacons to online map * [NEW] - Centering the map on the current profile at start (issue #185) * Fixed incorrect ADIF interpretation of _SENT fields (issue #176) * Fixed Awards Dialog, Table double click for ITU/CQZ/WAZ/IOTA shows incorrect QSOs (issue #177) * Fixed ADIF double-type fields when 0.0 is currently mapped to NULL (issue #178) * Fixed QSO Detail to save NULL instead of empty string (issue #179) * Fixed ADIF Import default _INTL values are now stored correctly (issue #183) * Fixed Maps show an incorrect path if from/to grids are the same (issue #186) * Fixed Online Maps incorrect Bounds if Bandmap callsign double-click (issue #188) * Updated German translation (thx DL2KI) -- foldynl Tue, 14 Mar 2023 20:00:00 +0100 qlog (0.19.0-1) UNRELEASED; urgency=low * [NEW] - Added Aurora Layer to online map * [NEW] - Logbook - filter options are saved and restored * [NEW] - Map Setting is saved and restored (issue #140) * [NEW] - QSO Duration (issue #158) * [NEW] - DX Cluster uses monospace font (issue #164) * [NEW] - Awards - if click on the Entity/band the logbook filter is set (issue #168) * [NEW] - WSJTX - Added Multicast support (issue #172) * Fixed WWFF LOV Download (issue #169) -- foldynl Fri, 17 Feb 2023 15:00:00 +0100 qlog (0.18.0-1) UNRELEASED; urgency=low * [NEW] - ADIF 3.1.4 updates * Added new modes FREEDV and M17 * Added new band (submm) * Adopted Altitude (for SOTA only) * Adopted POTA (includes POTA List) * Adopted Gridsquare_ext (only import/export) * Adopted Hamlogeu_* (only import/export) * Adopted HamQTH_* (only import/export) * [NEW] - Added new DXCC Status and color for it - Confirmed * [NEW] - New Contact - Tab selection is saved * [NEW] - Grid can contain 8-characters * [NEW] - User filter can contain NULL value * [NEW] - Compilation - added variables for external sources * [NEW] - My DXCC/CQZ/ITUZ/Country is filled * [NEW] - Alerts - Added Aging (issue #153) * [NEW] - Alerts - Added DXCC Status Color (issue #153) * [NEW] - DXC - Added Log Status to filter (issue #154) * [NEW] - DXC - Added Spot deduplication to filter (issue #154) * [NEW] - WSJTX - Added CQ-Spot Filter (issue #155) * [NEW] - QSO Detail contains DXCC Tab (issue #156) * [CHANGED] - New QSO DXCC Tab reworked (issue #144) * [CHANGED] - All DXCC Stats are computed based on My DXCC instead of My Callsign * [CHANGED] - Station Profile Setting layout -- foldynl Sun, 15 Jan 2023 15:00:00 +0100 qlog (0.17.0-1) UNRELEASED; urgency=low * [NEW] - NetPort and Polling interval can be defined for NET Rigs * [NEW] - NetPort can be defined for NET Rots * [NEW] - Added Saving Bandmap Zoom per band (issue #137) * [NEW] - CW speed synchronisation (issue #139) * Fixed Missing callbook data when callsign has prefix (issue #133) * Fixed Winkey2 echo chars are incorrectly displayed in CW Console (issue #141) * [CHANGED] - Online Map - Gray-Line is enabled by default * Update Timezone database -- foldynl Sun, 18 Dec 2022 10:00:00 +0100 qlog (0.16.0-1) UNRELEASED; urgency=low * [NEW] - SOTA/IOTA lists updated regularly * [NEW] - Added WWFF list, updated regularly * [NEW] - QTH/Grid are filled based on SOTA/WWFF * [NEW] - DXC/WSJTX columns are movable, added column visibility setting * [NEW] - DXC/WSJTX columns layout is saved * [NEW] - Added Wiki&Report Issue links to Help section * [NEW] - About dialog contains run-time information * [NEW] - Solar Info as a ToolTip * [NEW] - QSO Manual Entry Mode * Fixed Bandmap unlogical animation when band is changed (issue #128) * Fixed Bandmap marks are not displayed correctly when RIT/XI (issue #131) * Fixed Setting Dialog size * Update Timezone database -- foldynl Sun, 20 Nov 2022 10:00:00 +0200 qlog (0.15.0-1) UNRELEASED; urgency=low * Fixed Keeping the Bandmap RX mark always visible when centre RX is disabled (issue #115) * Fixed Equipment Menu: Swapped Connect Keyer and Rig (issue #122) * Fixed Callsign is deleted when clicking bandmap (issue #126) * Fixed typo in the Map layer menu (issue #127) * Fixed compilation issues & warning under QT6 - preparation for QT6 migration -- foldynl Sun, 16 Oct 2022 19:00:00 +0200 qlog (0.14.1-1) UNRELEASED; urgency=low * Fixed CW Console - HALT Button is not enabled under Ubuntu flavours (issue #124) -- foldynl Sun, 2 Oct 2022 10:00:00 +0200 qlog (0.14.0-1) UNRELEASED; urgency=low * [NEW] CW Console (Winkey2, Morse over CAT support) * [NEW] DX Cluster pre-defined commands (send last spot, get stats) * [NEW] Added DX Cluster Views (Spots, WCY, WWV, ToALL) * [NEW] Implemented DX Cluster Reconnection * [NEW] Remember last used DX Cluster * [CHANGED] - UI unifications - Rot/Rig/DXC * Fixed COM port validation for Windows platform * Fixed Reconnecting (DXC/Callbook) (issue #110) * Fixed DX Cluster crashes when DXC server is not connected and a command is sent (issue #111) * Fixed Bandmap callsign selection not fully works (issue #116) -- foldynl Thu, 29 Sep 2022 18:00:00 +0200 qlog (0.13.0-1) UNRELEASED; urgency=low * [NEW] QSY Contact Wiping (issue #100) * [NEW] Timeoff is highlighted when QSO timer is running (issue #100) * [NEW] Callsign whisperer * [NEW] Bandmap - Spot's color is recalculated when QSO is saved * [NEW] BandMap - CTRL + Wheel zooming * [NEW] BandMap - Zooming via buttons keeps a focus on centre freq * [NEW] BandMap - DX Spot's Comment as a tooltip * [CHANGED] BandMap - UI Layout * Fixed MacOS builds (PR #102) (thx gerbert) * Fixed templates under MacOS (PR #101) (thx gerbert) * Fixed WindowsOS Installer - Unable to upgrade version -- foldynl Sat, 6 Aug 2022 18:00:00 +0200 qlog (0.12.0-1) UNRELEASED; urgency=low * [NEW] Statistics - Show ODX on the map * [EXPERIMENTAL] Support for QT Styles (issue #88) * [CHANGED] - Removed F2 as a shortcut for QSO field editing * Next fixing of a high CPU load when DXC is processed (issue #52) * Fixed QSO fields from prev QSOs when Prefix - Callsign - Suffix (issue #90) * Fixed Chaotic QSO start time (issue #93) * Offline maps - Lighter colors, night sky removed, Sun position removed (issue #97) * Fixed incorrect A-Index colort (issue #98) * Fixed Stats Widget - percents - does not reflect date range (issue #99) * Fixed potential LogParam Cache issue * Import/Export polishing -- foldynl Fri, 15 Jul 2022 18:00:00 +0200 qlog (0.11.0-1) UNRELEASED; urgency=low * [NEW] QSO Detail/Edit Dialog * [NEW] Added mW power Support * [NEW] Implemented ADIF 3.1.3 * [NEW] Rigwidget saves last used freq for bands * Fixed Rig Combo size when Rig Profile name is long (issue #31) * Fixed CQZ, ITUZ do not validate whether their entered value is a number (issue #75) * Fixed vucc, myvucc must be uppercase - Edit mode (issue #76) * Fixed Greyline-Map is very dark (issue #78) * Fixed DX Country is not saved properly when name is between S-Z (issue #79) * Fixed Bandmap call selection - only left mouse button (issue #82) * Fixed My Notes Copy & Paste - Rich Text (issue #83) * Fixed Font appearance in the context menu (issue #84) -- foldynl Sun, 26 Jun 2022 8:00:00 +0200 qlog (0.10.0-1) UNRELEASED; urgency=low * [NEW] Bandmap shows XIT/RIT Freq * [NEW] Bandmap RX Mark Center (issue #69) * [NEW] Getting PTT State from RIG - only for CAT-controlled rigs * [NEW] PTT Shortchut - only for CAT-controlled rigs * Fixed Lost internet conneciton is not detected properly (issue #56) * Fixed Cannot manually edit QSO Date&Time (issue #66) * Fixed Field contents in capital letters (issue #67) * Fixed Band RX is not updated when RX Freq is edited (issue #72) * Fixed Stat Windget does not handle a date range correctly (issue #73) * Fixed eQSL card is incorreclty handled when a callsign contains special characters (issue #74) -- foldynl Sun, 5 Jun 2022 12:00:00 +0200 qlog (0.9.0-1) UNRELEASED; urgency=low * [NEW] User-defined Spot Alerts * [NEW] User filter contains a new operator "Starts with" * [NEW] a real local time is showed for the DX callsign (issue #45) * [NEW] Lotw/eQSL registration info is shown from callbooks * [NEW] Added shortcuts for menu and tabs * [NEW] Bandmap - Switching a band view via Bandmap context menu (issue #57) * [CHANGED] - Network Notification format * Fixed issue with My Notes multiple lines edit/show mode (issue 39) * Fixed issue when GUI froze when Rig disconnect was called (issue #50) * Partially fixed a high CPU load when DXC is processed (issue #52) * Fixed crashes under Debian "bullseye" - 32bit (issue #55) * Fixed Bandmap Callsign selection margin (issue #61) * Fixed issue when it was not possible to enter RX/TX freq manually -- foldynl Fri, 20 May 2022 08:00:00 +0200 qlog (0.8.0-1) UNRELEASED; urgency=low * RIT/XIT offset enable/disable detection (issue #26) * Fixed Rig Setting, Data Bits (issue #28) * Added default PWR for Rig profile (issue #30) * Fixed issue when GUI freezes during Rig connection (issue #32 & #33) * Fixed issue with an incorrect value of A-Index (issue #34) * Fixed ADI Import - incorrect _INTL fields import (issue #35) * Fixed isuue with an editing of bands in Setting dialog (#issue 36) * Fixed issue with hamlib when get_pwr crashes for a network rig (issue #37) * Improved new QSO fields are filled from prev QSO (issue #40) * Added mode for a network Rig (issue #41) * Fixed warning - processing a new request but the previous one hasn't been completed (issue #42) * Fixed Info widget when Country name is long (issue #43) * Reordered column visibility Tabs (issue #46) * Improved Rig tunning when XIT/RIT is enabled (issue #47) -- foldynl Fri, 22 Apr 2022 08:00:00 +0200 qlog (0.7.0-1) UNRELEASED; urgency=low * [NEW] - Ant/Rig/Rot Profiles * [NEW] - Rig widget shows additional information * [NEW] - Rig widget Band/Mode/Profile Changer * [NEW] - Rot profile Changer * [NEW] - AZ/EL are stored when Rot is connected * Fixed an issue with Statistic widget (issue #25) * Fixed Rot AZ current value (issue #22) -- foldynl Fri, 8 Apr 2022 12:00:00 +0200 qlog (0.6.5-1) UNRELEASED; urgency=low * Fixed missing modes in Setting Dialog (issue #11) * Fixed Station Profile text color in dark mode (issue #10) * Fixed DXCluster Server Combo (issue #12) * Fixed TAB focus on QSO Fields (issue #14) -- foldynl Thu, 10 Mar 2022 20:35:00 +0200 qlog (0.6.0-1) UNRELEASED; urgency=low * [NEW] QSL - added import a file with QSL - QSLr column * Fixed QLog start when Band is 3cm (too long start time due to the Bandmap drawing) (issue #6) * Fixed Rotator Widget Warning - map transformation issue (issue #8) * Changed Bandmap window narrow size (issue #3) * Changed User Filter Widget size * Removed Units from Logbook widget * Removed UTC string * Renamed RSTs, RSTr etc. (issue #4) * Renamed Main Menu Services->Service and Station->Equipment * Internal - reworked Service networking signal handling -- foldynl Sun, 5 Mar 2022 08:00:00 +0200 qlog (0.5.0-1) UNRELEASED; urgency=low * DB: Started to use *_INTL fields * DB: Added all ADIF-supported modes/submodes * GUI: Dark Mode * GUI: TIme format controlled by Locale * Import/Export: ADI do not export UTF-8 characters and *_INTL fields * Import/Export: ADX exports UTF-8 characters and *_INTL fields * Import/Export: Added Import of ADX file format * Logbook: Shows QSO summary as a Callsign's tooltip * Logbook: QSO time is shown with seconds; added timezone * New QSO: Added My notes - free text for your personal notes * Backup: Change backup format form ADI to ADX (ADX supports UTF-8) * Settings: WSJTX Port is changable -- foldynl Sat, 19 Feb 2022 12:00:00 +0200 log (0.4.0-1) UNRELEASED; urgency=low * Stats: Added Show on Map - QSOs and Worked&Confirmed Grids * Stats: Stats are refreshed after every QSO * WSJTX: Remove TRX/Monitoring Status * Added Split mode - RX/TX RIG Offset * Added export of selected QSOs * Fixed FLdigi interface * CPPChecks & Clazy cleanup -- foldynl Sun, 9 Jan 2022 12:00:00 +0200 qlog (0.3.0-1) UNRELEASED; urgency=low * Rework Station Profile - stored in DB, new fields * Added VUCC fields support * Added BandMap marks (CTRL+M) * Clublog is uploaded the same way as EQSL and LOTW (modified QSO are resent) * Clublog real-time upload is temporary disabled * Added QRZ suppor - upload QSO and Callsign query * Callbook cooperation - Primary&Secondary - Secondary used when Primary did not find -- foldynl Sun, 19 Dec 2021 12:00:00 +0200 qlog (0.2.0-1) UNRELEASED; urgency=low * Fork changes * Many GUI Changes * Added Online Map * Secure Storage for passwords * Improved Logging * CTY and SAT Name auto-update * Added Station Profile * Reworked Stats * Added Awards * Added Czech Translation * many other changes -- foldynl Sat, 27 Nov 2021 19:07:01 +0200 qlog (0.1.0-1) UNRELEASED; urgency=low * Initial release - non-public -- foldynl Thu, 26 Aug 2021 19:50:55 +0200 foldynl-QLog-3252ff9/debian/control000066400000000000000000000015621517334601000172140ustar00rootroot00000000000000Source: qlog Section: hamradio Priority: optional Maintainer: Ladislav Foldyna Uploaders: Ladislav Foldyna Vcs-Browser: https://github.com/foldynl/QLog Vcs-Git: https://github.com/foldynl/QLog.git Build-Depends: debhelper (>= 10.0.0), debhelper-compat (= 13), qtbase5-dev, libsqlite3-dev, libhamlib-dev, libqt5charts5-dev, qtchooser, qttools5-dev-tools, libqt5keychain1, qt5keychain-dev, qtwebengine5-dev, libqt5serialport5-dev, pkg-config, libqt5websockets5-dev, zlib1g-dev, libssl-dev Standards-Version: 4.5.0 Package: qlog Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring | kwalletmanager Description: Qt Logging program for hamradio operators QLog is an Amateur Radio logging application for Linux, Windows and Mac OS. It is based on the Qt 5 framework and uses SQLite as database backend. foldynl-QLog-3252ff9/debian/copyright000066400000000000000000000753211517334601000175500ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: qlog Upstream-Contact: Ladislav Foldyna Files: * Copyright: 2020, Thomas Gatzweiler 2021-2026, Ladislav Foldyna 2025, Michael Morgan AA5SH 2025, Kyle Boyle 2018-2019, Bertold Van den Bergh 2026, Stephane Fillod License: GPL-3+ Files: debian/* Copyright: 2021-2026, Ladislav Foldyna 2025-2026, Dawid Kulas License: GPL-3+ The package for qlog was put together first by Ladislav Foldyna Files: res/io.github.foldynl.QLog.metainfo.xml Copyright: 2023-2026, Ladislav Foldyna 2023-2025, AsciiWolf License: CC0-1.0 Files: core/zonedetect.* Copyright: 2018, Bertold Van den Bergh 2022-2023, Ladislav Foldyna License: BSD-3-Clause Files: devtools/timezones/* Copyright: 2018, Bertold Van den Bergh 2022-2024, Ladislav Foldyna License: ODbL-1.0 Files: ui/component/SwitchButton.h ui/component/SwitchButton.cpp ui/component/ButtonStyle.h Copyright: 2018-2020, Iman Ahmadvand 2025, Ladislav Foldyna License: GPL-3+ Files: core/csv.hpp Copyright: 2017-2024 Vincent Lau 2017-2019 Martin Moene (string-view lite, embedded) License: Expat Files: devtools/timezones/builder/builder.cpp Copyright: 2018, Bertold Van den Bergh 2022-2024, Ladislav Foldyna License: BSD-3-Clause License: GPL-3+ 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 3 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, see . . Comment: On Debian systems, the full text of the GNU General Public License version 3 can be found in the file '/usr/share/common-licenses/GPL-3'. License: CC0-1.0 To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. . You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see . Comment: On Debian systems, the full text of the CC0 1.0 Universal license can be found in the file '/usr/share/common-licenses/CC0-1.0'. License: BSD-3-Clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. . * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: ODbL-1.0 ### Preamble . The Open Database License (ODbL) is a license agreement intended to allow users to freely share, modify, and use this Database while maintaining this same freedom for others. Many databases are covered by copyright, and therefore this document licenses these rights. Some jurisdictions, mainly in the European Union, have specific rights that cover databases, and so the ODbL addresses these rights, too. Finally, the ODbL is also an agreement in contract for users of this Database to act in certain ways in return for accessing this Database. . Databases can contain a wide variety of types of content (images, audiovisual material, and sounds all in the same database, for example), and so the ODbL only governs the rights over the Database, and not the contents of the Database individually. Licensors should use the ODbL together with another license for the contents, if the contents have a single set of rights that uniformly covers all of the contents. If the contents have multiple sets of different rights, Licensors should describe what rights govern what contents together in the individual record or in some other way that clarifies what rights apply. . Sometimes the contents of a database, or the database itself, can be covered by other rights not addressed here (such as private contracts, trade mark over the name, or privacy rights / data protection rights over information in the contents), and so you are advised that you may have to consult other documents or clear other rights before doing activities not covered by this License. . ------ . The Licensor (as defined below) . and . You (as defined below) . agree as follows: . ### 1.0 Definitions of Capitalised Words . "Collective Database" - Means this Database in unmodified form as part of a collection of independent databases in themselves that together are assembled into a collective whole. A work that constitutes a Collective Database will not be considered a Derivative Database. . "Convey" - As a verb, means Using the Database, a Derivative Database, or the Database as part of a Collective Database in any way that enables a Person to make or receive copies of the Database or a Derivative Database. Conveying does not include interaction with a user through a computer network, or creating and Using a Produced Work, where no transfer of a copy of the Database or a Derivative Database occurs. "Contents" - The contents of this Database, which includes the information, independent works, or other material collected into the Database. For example, the contents of the Database could be factual data or works such as images, audiovisual material, text, or sounds. . "Database" - A collection of material (the Contents) arranged in a systematic or methodical way and individually accessible by electronic or other means offered under the terms of this License. . "Database Directive" - Means Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended or succeeded. . "Database Right" - Means rights resulting from the Chapter III ("sui generis") rights in the Database Directive (as amended and as transposed by member states), which includes the Extraction and Re-utilisation of the whole or a Substantial part of the Contents, as well as any similar rights available in the relevant jurisdiction under Section 10.4. . "Derivative Database" - Means a database based upon the Database, and includes any translation, adaptation, arrangement, modification, or any other alteration of the Database or of a Substantial part of the Contents. This includes, but is not limited to, Extracting or Re-utilising the whole or a Substantial part of the Contents in a new Database. . "Extraction" - Means the permanent or temporary transfer of all or a Substantial part of the Contents to another medium by any means or in any form. . "License" - Means this license agreement and is both a license of rights such as copyright and Database Rights and an agreement in contract. . "Licensor" - Means the Person that offers the Database under the terms of this License. . "Person" - Means a natural or legal person or a body of persons corporate or incorporate. . "Produced Work" - a work (such as an image, audiovisual material, text, or sounds) resulting from using the whole or a Substantial part of the Contents (via a search or other query) from this Database, a Derivative Database, or this Database as part of a Collective Database. . "Publicly" - means to Persons other than You or under Your control by either more than 50% ownership or by the power to direct their activities (such as contracting with an independent consultant). . "Re-utilisation" - means any form of making available to the public all or a Substantial part of the Contents by the distribution of copies, by renting, by online or other forms of transmission. . "Substantial" - Means substantial in terms of quantity or quality or a combination of both. The repeated and systematic Extraction or Re-utilisation of insubstantial parts of the Contents may amount to the Extraction or Re-utilisation of a Substantial part of the Contents. . "Use" - As a verb, means doing any act that is restricted by copyright or Database Rights whether in the original medium or any other; and includes without limitation distributing, copying, publicly performing, publicly displaying, and preparing derivative works of the Database, as well as modifying the Database as may be technically necessary to use it in a different mode or format. . "You" - Means a Person exercising rights under this License who has not previously violated the terms of this License with respect to the Database, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. . Words in the singular include the plural and vice versa. . ### 2.0 What this License covers . 2.1. Legal effect of this document. This License is: . a. A license of applicable copyright and neighbouring rights; . b. A license of the Database Right; and . c. An agreement in contract between You and the Licensor. . 2.2 Legal rights covered. This License covers the legal rights in the Database, including: . a. Copyright. Any copyright or neighbouring rights in the Database. The copyright licensed includes any individual elements of the Database, but does not cover the copyright over the Contents independent of this Database. See Section 2.4 for details. Copyright law varies between jurisdictions, but is likely to cover: the Database model or schema, which is the structure, arrangement, and organisation of the Database, and can also include the Database tables and table indexes; the data entry and output sheets; and the Field names of Contents stored in the Database; . b. Database Rights. Database Rights only extend to the Extraction and Re-utilisation of the whole or a Substantial part of the Contents. Database Rights can apply even when there is no copyright over the Database. Database Rights can also apply when the Contents are removed from the Database and are selected and arranged in a way that would not infringe any applicable copyright; and . c. Contract. This is an agreement between You and the Licensor for access to the Database. In return you agree to certain conditions of use on this access as outlined in this License. . 2.3 Rights not covered. . a. This License does not apply to computer programs used in the making or operation of the Database; . b. This License does not cover any patents over the Contents or the Database; and . c. This License does not cover any trademarks associated with the Database. . 2.4 Relationship to Contents in the Database. The individual items of the Contents contained in this Database may be covered by other rights, including copyright, patent, data protection, privacy, or personality rights, and this License does not cover any rights (other than Database Rights or in contract) in individual Contents contained in the Database. For example, if used on a Database of images (the Contents), this License would not apply to copyright over individual images, which could have their own separate licenses, or one single license covering all of the rights over the images. . ### 3.0 Rights granted . 3.1 Subject to the terms and conditions of this License, the Licensor grants to You a worldwide, royalty-free, non-exclusive, terminable (but only under Section 9) license to Use the Database for the duration of any applicable copyright and Database Rights. These rights explicitly include commercial use, and do not exclude any field of endeavour. To the extent possible in the relevant jurisdiction, these rights may be exercised in all media and formats whether now known or created in the future. . The rights granted cover, for example: . a. Extraction and Re-utilisation of the whole or a Substantial part of the Contents; . b. Creation of Derivative Databases; . c. Creation of Collective Databases; . d. Creation of temporary or permanent reproductions by any means and in any form, in whole or in part, including of any Derivative Databases or as a part of Collective Databases; and . e. Distribution, communication, display, lending, making available, or performance to the public by any means and in any form, in whole or in part, including of any Derivative Database or as a part of Collective Databases. . 3.2 Compulsory license schemes. For the avoidance of doubt: . a. Non-waivable compulsory license schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; . b. Waivable compulsory license schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, . c. Voluntary license schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. . 3.3 The right to release the Database under different terms, or to stop distributing or making available the Database, is reserved. Note that this Database may be multiple-licensed, and so You may have the choice of using alternative licenses for this Database. Subject to Section 10.4, all other rights not expressly granted by Licensor are reserved. . ### 4.0 Conditions of Use . 4.1 The rights granted in Section 3 above are expressly made subject to Your complying with the following conditions of use. These are important conditions of this License, and if You fail to follow them, You will be in material breach of its terms. . 4.2 Notices. If You Publicly Convey this Database, any Derivative Database, or the Database as part of a Collective Database, then You must: . a. Do so only under the terms of this License or another license permitted under Section 4.4; . b. Include a copy of this License (or, as applicable, a license permitted under Section 4.4) or its Uniform Resource Identifier (URI) with the Database or Derivative Database, including both in the Database or Derivative Database and in any relevant documentation; and . c. Keep intact any copyright or Database Right notices and notices that refer to this License. . d. If it is not possible to put the required notices in a particular file due to its structure, then You must include the notices in a location (such as a relevant directory) where users would be likely to look for it. . 4.3 Notice for using output (Contents). Creating and Using a Produced Work does not require the notice in Section 4.2. However, if you Publicly Use a Produced Work, You must include a notice associated with the Produced Work reasonably calculated to make any Person that uses, views, accesses, interacts with, or is otherwise exposed to the Produced Work aware that Content was obtained from the Database, Derivative Database, or the Database as part of a Collective Database, and that it is available under this License. . a. Example notice. The following text will satisfy notice under Section 4.3: . Contains information from DATABASE NAME, which is made available here under the Open Database License (ODbL). . DATABASE NAME should be replaced with the name of the Database and a hyperlink to the URI of the Database. "Open Database License" should contain a hyperlink to the URI of the text of this License. If hyperlinks are not possible, You should include the plain text of the required URI's with the above notice. . 4.4 Share alike. . a. Any Derivative Database that You Publicly Use must be only under the terms of: . i. This License; . ii. A later version of this License similar in spirit to this License; or . iii. A compatible license. . If You license the Derivative Database under one of the licenses mentioned in (iii), You must comply with the terms of that license. . b. For the avoidance of doubt, Extraction or Re-utilisation of the whole or a Substantial part of the Contents into a new database is a Derivative Database and must comply with Section 4.4. . c. Derivative Databases and Produced Works. A Derivative Database is Publicly Used and so must comply with Section 4.4. if a Produced Work created from the Derivative Database is Publicly Used. . d. Share Alike and additional Contents. For the avoidance of doubt, You must not add Contents to Derivative Databases under Section 4.4 a that are incompatible with the rights granted under this License. . e. Compatible licenses. Licensors may authorise a proxy to determine compatible licenses under Section 4.4 a iii. If they do so, the authorised proxy's public statement of acceptance of a compatible license grants You permission to use the compatible license. . . 4.5 Limits of Share Alike. The requirements of Section 4.4 do not apply in the following: . a. For the avoidance of doubt, You are not required to license Collective Databases under this License if You incorporate this Database or a Derivative Database in the collection, but this License still applies to this Database or a Derivative Database as a part of the Collective Database; . b. Using this Database, a Derivative Database, or this Database as part of a Collective Database to create a Produced Work does not create a Derivative Database for purposes of Section 4.4; and . c. Use of a Derivative Database internally within an organisation is not to the public and therefore does not fall under the requirements of Section 4.4. . 4.6 Access to Derivative Databases. If You Publicly Use a Derivative Database or a Produced Work from a Derivative Database, You must also offer to recipients of the Derivative Database or Produced Work a copy in a machine readable form of: . a. The entire Derivative Database; or . b. A file containing all of the alterations made to the Database or the method of making the alterations to the Database (such as an algorithm), including any additional Contents, that make up all the differences between the Database and the Derivative Database. . The Derivative Database (under a.) or alteration file (under b.) must be available at no more than a reasonable production cost for physical distributions and free of charge if distributed over the internet. . 4.7 Technological measures and additional terms . a. This License does not allow You to impose (except subject to Section 4.7 b.) any terms or any technological measures on the Database, a Derivative Database, or the whole or a Substantial part of the Contents that alter or restrict the terms of this License, or any rights granted under it, or have the effect or intent of restricting the ability of any person to exercise those rights. . b. Parallel distribution. You may impose terms or technological measures on the Database, a Derivative Database, or the whole or a Substantial part of the Contents (a "Restricted Database") in contravention of Section 4.74 a. only if You also make a copy of the Database or a Derivative Database available to the recipient of the Restricted Database: . i. That is available without additional fee; . ii. That is available in a medium that does not alter or restrict the terms of this License, or any rights granted under it, or have the effect or intent of restricting the ability of any person to exercise those rights (an "Unrestricted Database"); and . iii. The Unrestricted Database is at least as accessible to the recipient as a practical matter as the Restricted Database. . c. For the avoidance of doubt, You may place this Database or a Derivative Database in an authenticated environment, behind a password, or within a similar access control scheme provided that You do not alter or restrict the terms of this License or any rights granted under it or have the effect or intent of restricting the ability of any person to exercise those rights. . 4.8 Licensing of others. You may not sublicense the Database. Each time You communicate the Database, the whole or Substantial part of the Contents, or any Derivative Database to anyone else in any way, the Licensor offers to the recipient a license to the Database on the same terms and conditions as this License. You are not responsible for enforcing compliance by third parties with this License, but You may enforce any rights that You have over a Derivative Database. You are solely responsible for any modifications of a Derivative Database made by You or another Person at Your direction. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. . ### 5.0 Moral rights . 5.1 Moral rights. This section covers moral rights, including any rights to be identified as the author of the Database or to object to treatment that would otherwise prejudice the author's honour and reputation, or any other derogatory treatment: . a. For jurisdictions allowing waiver of moral rights, Licensor waives all moral rights that Licensor may have in the Database to the fullest extent possible by the law of the relevant jurisdiction under Section 10.4; . b. If waiver of moral rights under Section 5.1 a in the relevant jurisdiction is not possible, Licensor agrees not to assert any moral rights over the Database and waives all claims in moral rights to the fullest extent possible by the law of the relevant jurisdiction under Section 10.4; and . c. For jurisdictions not allowing waiver or an agreement not to assert moral rights under Section 5.1 a and b, the author may retain their moral rights over certain aspects of the Database. . Please note that some jurisdictions do not allow for the waiver of moral rights, and so moral rights may still subsist over the Database in some jurisdictions. . ### 6.0 Fair dealing, Database exceptions, and other rights not affected . 6.1 This License does not affect any rights that You or anyone else may independently have under any applicable law to make any use of this Database, including without limitation: . a. Exceptions to the Database Right including: Extraction of Contents from non-electronic Databases for private purposes, Extraction for purposes of illustration for teaching or scientific research, and Extraction or Re-utilisation for public security or an administrative or judicial procedure. . b. Fair dealing, fair use, or any other legally recognised limitation or exception to infringement of copyright or other applicable laws. . 6.2 This License does not affect any rights of lawful users to Extract and Re-utilise insubstantial parts of the Contents, evaluated quantitatively or qualitatively, for any purposes whatsoever, including creating a Derivative Database (subject to other rights over the Contents, see Section 2.4). The repeated and systematic Extraction or Re-utilisation of insubstantial parts of the Contents may however amount to the Extraction or Re-utilisation of a Substantial part of the Contents. . ### 7.0 Warranties and Disclaimer . 7.1 The Database is licensed by the Licensor "as is" and without any warranty of any kind, either express, implied, or arising by statute, custom, course of dealing, or trade usage. Licensor specifically disclaims any and all implied warranties or conditions of title, non-infringement, accuracy or completeness, the presence or absence of errors, fitness for a particular purpose, merchantability, or otherwise. Some jurisdictions do not allow the exclusion of implied warranties, so this exclusion may not apply to You. . ### 8.0 Limitation of liability . 8.1 Subject to any liability that may not be excluded or limited by law, the Licensor is not liable for, and expressly excludes, all liability for loss or damage however and whenever caused to anyone by any use under this License, whether by You or by anyone else, and whether caused by any fault on the part of the Licensor or not. This exclusion of liability includes, but is not limited to, any special, incidental, consequential, punitive, or exemplary damages such as loss of revenue, data, anticipated profits, and lost business. This exclusion applies even if the Licensor has been advised of the possibility of such damages. . 8.2 If liability may not be excluded by law, it is limited to actual and direct financial loss to the extent it is caused by proved negligence on the part of the Licensor. . ### 9.0 Termination of Your rights under this License . 9.1 Any breach by You of the terms and conditions of this License automatically terminates this License with immediate effect and without notice to You. For the avoidance of doubt, Persons who have received the Database, the whole or a Substantial part of the Contents, Derivative Databases, or the Database as part of a Collective Database from You under this License will not have their licenses terminated provided their use is in full compliance with this License or a license granted under Section 4.8 of this License. Sections 1, 2, 7, 8, 9 and 10 will survive any termination of this License. . 9.2 If You are not in breach of the terms of this License, the Licensor will not terminate Your rights under it. . 9.3 Unless terminated under Section 9.1, this License is granted to You for the duration of applicable rights in the Database. . 9.4 Reinstatement of rights. If you cease any breach of the terms and conditions of this License, then your full rights under this License will be reinstated: . a. Provisionally and subject to permanent termination until the 60th day after cessation of breach; . b. Permanently on the 60th day after cessation of breach unless otherwise reasonably notified by the Licensor; or . c. Permanently if reasonably notified by the Licensor of the violation, this is the first time You have received notice of violation of this License from the Licensor, and You cure the violation prior to 30 days after your receipt of the notice. . Persons subject to permanent termination of rights are not eligible to be a recipient and receive a license under Section 4.8. . 9.5 Notwithstanding the above, Licensor reserves the right to release the Database under different license terms or to stop distributing or making available the Database. Releasing the Database under different license terms or stopping the distribution of the Database will not withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. . ### 10.0 General . 10.1 If any provision of this License is held to be invalid or unenforceable, that must not affect the validity or enforceability of the remainder of the terms and conditions of this License and each remaining provision of this License shall be valid and enforced to the fullest extent permitted by law. . 10.2 This License is the entire agreement between the parties with respect to the rights granted here over the Database. It replaces any earlier understandings, agreements or representations with respect to the Database. . 10.3 If You are in breach of the terms of this License, You will not be entitled to rely on the terms of this License or to complain of any breach by the Licensor. . 10.4 Choice of law. This License takes effect in and will be governed by the laws of the relevant jurisdiction in which the License terms are sought to be enforced. If the standard suite of rights granted under applicable copyright law and Database Rights in the relevant jurisdiction includes additional rights not granted under this License, these additional rights are granted in this License in order to meet the terms of this License. License: Expat 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. foldynl-QLog-3252ff9/debian/rules000077500000000000000000000000501517334601000166600ustar00rootroot00000000000000#!/usr/bin/make -f %: dh $@ --parallel foldynl-QLog-3252ff9/debian/source/000077500000000000000000000000001517334601000171055ustar00rootroot00000000000000foldynl-QLog-3252ff9/debian/source/format000066400000000000000000000000141517334601000203130ustar00rootroot000000000000003.0 (quilt) foldynl-QLog-3252ff9/debian/watch000066400000000000000000000001131517334601000166310ustar00rootroot00000000000000Version: 5 Template: Github Owner: foldynl Project: QLog #Release-Only: yesfoldynl-QLog-3252ff9/devtools/000077500000000000000000000000001517334601000162225ustar00rootroot00000000000000foldynl-QLog-3252ff9/devtools/ADIF/000077500000000000000000000000001517334601000167255ustar00rootroot00000000000000foldynl-QLog-3252ff9/devtools/ADIF/all_ADIF_fields_example.adi000066400000000000000000000063731517334601000240110ustar00rootroot00000000000000### QLog ADIF Export 3.1.4 Gene 0.20.0 20230324 081527 123 Main St. 35 1900 10 45 20 S AL WAS WAS 20M 40M N1MM 599 A 20220101 Y New Haven Nice signal! SA N1CON NAQP-SSB United States 5 DXCC DXCC HX 500 291 john.doe@example.com K1ABC 20220101 20220101 Y Y 1234 5678 Y 14200 7050 FN31pr FN31 K2XYZ 20230101 Y 20230101 Y 20220101 Y EU-001 001 8 3 N041 30.000 N041 30.000 20220101 20220101 Y Y 3 SSB GEM 1900 GP AL New Haven JA Gun United States 5 291 1234 FN31pr AA EU-001 001 8 N041 30.000 N041 30.000 John Doe 06511 K-5033 Icom IC-7300 SIG INFO SOTA Connecticut Main St. CT-009 FN80 WWFF Jane Smith Had a great QSO! 5 10 K1ABC K1ABC W1AW K-5033 A SAT 20220101 Y Tnx QSO! 20220101 20220101 Y D Y B BURO Y 20220101 20220101 Y New Haven AI Icom IC-7300 59 59 100 FM SO-50 70 59 USB N 1234 W1/HA-001 7050 7.050 Connecticut K1ABC 599 5.99 LSB Y 12345 1200 1100 100 1234 CT-009 ON FN31 http://all.com WWFF-OK11 ALT 20240101 20240202 I Y TEST CPU ALT DOK MY TEST DP 20240303 Y QSLR MSG U foldynl-QLog-3252ff9/devtools/ADIF/min_ADIF_fields_example.adi000066400000000000000000000003231517334601000240110ustar00rootroot00000000000000### QLog ADIF Export 3.1.4 QLog 0.20.0 20230324 081527 SO1TEST 20230101 132300 40m CW foldynl-QLog-3252ff9/devtools/ADIF/test_intl.adi000066400000000000000000000007721517334601000214170ustar00rootroot00000000000000### QLog ADIF Export 3.1.4 QLog 0.20.0 20230324 081527 SO1TEST 20230501 132300 40m CW com Rig from GP GP_INTL SO1TESTT 20230501 132300 40m CW com com_intl SO1TESTS 20230501 132300 40m CW foldynl-QLog-3252ff9/devtools/TCISimulator/000077500000000000000000000000001517334601000205415ustar00rootroot00000000000000foldynl-QLog-3252ff9/devtools/TCISimulator/client.html000066400000000000000000000045121517334601000227070ustar00rootroot00000000000000 WebSocket Test

foldynl-QLog-3252ff9/devtools/TCISimulator/server.py000077500000000000000000000144621517334601000224330ustar00rootroot00000000000000#!/usr/bin/env python3 """ TCI WebSocket simulator This script implements a minimal TCI-like WebSocket server that accepts multiple client connections and broadcasts status updates to all connected clients. How it works - Starts a WebSocket server on TCP port 8000. - When a client connects, the server immediately sends a set of capability/status messages (limits, device info, supported modulations) and a READY message. - Incoming messages are parsed as simple "COMMAND:arg1,arg2,..." frames and mapped to handlers. Supported commands include: VFO, TRX, MODULATION, DRIVE, RIT_OFFSET, RIT_ENABLE, XIT_OFFSET, XIT_ENABLE, and CW_MACROS_SPEED. - The server keeps an internal state (frequency, TX/RX, modulation, drive, RIT/XIT settings, CW speed). When a command updates the state, the server broadcasts the corresponding response/status frame to all connected clients. Notes - This is a simulator: it does not control real radio hardware; it only maintains and publishes state. - Each connection creates its own SimpleTCI state instance; broadcasting still goes to all clients. - Messages are terminated with ';' when sent to clients. """ import asyncio import websockets clients = set() class SimpleTCI: def __init__(self): self.currFreq = 14000000 self.currTrx = False self.currModulation = "USB" self.currDrive = 20 self.currRITOffset = 0 self.currRITEnable = False self.currCWSpeed = 20 self.currXITOffset = 0 self.currXITEnable = False async def sendTCIMessage(self, msg: str): print(f"Sending msg: {msg}") await asyncio.sleep(0.1) dead = set() for ws in clients: try: await ws.send(msg + ";") except Exception: dead.add(ws) for ws in dead: clients.discard(ws) async def VFOCommand(self, args, getNum): if len(args) > getNum: self.currFreq = args[2] await self.sendTCIMessage(f"vfo:0,0,{self.currFreq}") async def TRXCommand(self, args, getNum): if len(args) > getNum: self.currTrx = (args[1].lower() == "true") await self.sendTCIMessage(f"trx:0,{self.currTrx}") async def MODULATIONCommand(self, args, getNum): if len(args) > getNum: self.currModulation = args[1].upper() await self.sendTCIMessage(f"modulation:0,{self.currModulation}") async def DRIVECommand(self, args, getNum): if len(args) > getNum: self.currDrive = args[1] await self.sendTCIMessage(f"drive:0,{self.currDrive}") async def RITOFFSETCommand(self, args, getNum): if len(args) > getNum: self.currRITOffset = args[1] await self.sendTCIMessage(f"rit_offset:0,{self.currRITOffset}") async def RITENABLECommand(self, args, getNum): if len(args) > getNum: self.currRITEnable = (args[1].lower() == "true") await self.sendTCIMessage(f"rit_enable:0,{self.currRITEnable}") async def XITOFFSETCommand(self, args, getNum): if len(args) > getNum: self.currXITOffset = args[1] await self.sendTCIMessage(f"xit_offset:0,{self.currXITOffset}") async def XITENABLECommand(self, args, getNum): if len(args) > getNum: self.currXITEnable = (args[1].lower() == "true") await self.sendTCIMessage(f"xit_enable:0,{self.currXITEnable}") async def CWMACROSSPEEDCommand(self, args, getNum): if len(args) > getNum: self.currCWSpeed = args[0] await self.sendTCIMessage(f"cw_macros_speed:0,{self.currCWSpeed}") def _processCommand(self, argString, getArgsNum): stripArgs = argString.replace(";", "") args = stripArgs.split(",") if len(args) < getArgsNum: return None return args async def handleMessage(self, data: str): commandString = data.split(":") print(f"Received: {commandString}") if len(commandString) < 2: return command = commandString[0].upper() payload = commandString[1] if command == "VFO": args = self._processCommand(payload, 2) if args: await self.VFOCommand(args, 2) elif command == "TRX": args = self._processCommand(payload, 1) if args: await self.TRXCommand(args, 1) elif command == "MODULATION": args = self._processCommand(payload, 1) if args: await self.MODULATIONCommand(args, 1) elif command == "DRIVE": args = self._processCommand(payload, 1) if args: await self.DRIVECommand(args, 1) elif command == "RIT_OFFSET": args = self._processCommand(payload, 1) if args: await self.RITOFFSETCommand(args, 1) elif command == "RIT_ENABLE": args = self._processCommand(payload, 1) if args: await self.RITENABLECommand(args, 1) elif command == "XIT_OFFSET": args = self._processCommand(payload, 1) if args: await self.XITOFFSETCommand(args, 1) elif command == "XIT_ENABLE": args = self._processCommand(payload, 1) if args: await self.XITENABLECommand(args, 1) elif command == "CW_MACROS_SPEED": args = self._processCommand(payload, 0) if args is not None: await self.CWMACROSSPEEDCommand(args, 0) async def handler(websocket, path=None): clients.add(websocket) tci = SimpleTCI() print(websocket.remote_address, "connected") await tci.sendTCIMessage("VFO_LIMITS:10000,30000000;TRX_COUNT:2") await tci.sendTCIMessage("DEVICE:SunSDR2DX;MODULATIONS_LIST:AM,SAM,LSB,USB,CW,NFM,WFM;PROTOCOL:ExpertSDR3,1.9") await tci.sendTCIMessage("VFO:0,0,14000000;TRX:0,false;MODULATION:0,USB;RIT_OFFSET:0,-50;RIT_ENABLE:0,false") await tci.sendTCIMessage("READY") try: async for message in websocket: await tci.handleMessage(message) finally: clients.discard(websocket) print(websocket.remote_address, "closed") async def main(): host = "0.0.0.0" # nebo "127.0.0.1" jen pro localhost port = 8000 print(f"TCI Server Simulator listening on ws://{host}:{port}") async with websockets.serve(handler, host, port): await asyncio.Future() # run forever if __name__ == "__main__": asyncio.run(main()) foldynl-QLog-3252ff9/devtools/cabrillo/000077500000000000000000000000001517334601000200115ustar00rootroot00000000000000foldynl-QLog-3252ff9/devtools/cabrillo/generate_cabrillo_templates.py000077500000000000000000000272101517334601000261070ustar00rootroot00000000000000#!/usr/bin/env python3 """ Generate Cabrillo template SQL for QLog from formats.dat. Source: https://codeberg.org/kq4mhe/adif2cabrillo/raw/branch/main/resources/formats.dat Usage: python3 generate_cabrillo_templates.py -- diff since last run python3 generate_cabrillo_templates.py --full -- all templates Downloads formats.dat automatically. SQL goes to stdout. State is kept in formats.dat.state next to this script. Field mapping: All field-name mappings live in FIELD_MAP below. Format: "name": (sent_db, rcvd_db, formatter [, sent_label, rcvd_label]) "name": None -- skip this field Examples: "freq": ("freq", "freq", "freq_khz"), -- common field "call": ("station_callsign", "callsign", "upper", -- with explicit labels "My Call", "Call Rcvd"), "exch": ("stx_string", "srx_string", ""), -- exchange field "t": None, -- ignored Fields not listed produce "-- REVIEW" in the SQL output. To fix a REVIEW, just add the field name to FIELD_MAP. """ import os import re import sys import urllib.request SOURCE_URL = ("https://codeberg.org/kq4mhe/adif2cabrillo" "/raw/branch/main/resources/formats.dat") SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) DAT_PATH = os.path.join(SCRIPT_DIR, "formats.dat") STATE_PATH = os.path.join(SCRIPT_DIR, "formats.dat.state") # --------------------------------------------------------------------------- # Built-in contest IDs — only these are emitted as builtin templates. # Top 10 most popular worldwide contests by participation. # --------------------------------------------------------------------------- BUILTIN_CONTEST_IDS = { "CQ-WW-CW", "CQ-WW-SSB", "CQ-WPX-CW", "CQ-WPX-SSB", "CQ-WW-RTTY", "ARRL-DX-CW", "ARRL-DX-SSB", "IARU-HF", "ARRL-VHF-JAN", "CQ-VHF", } # --------------------------------------------------------------------------- # Field mapping: "name" -> (sent_db, rcvd_db, formatter [, sent_lbl, rcvd_lbl]) # "name" -> None means skip # --------------------------------------------------------------------------- FIELD_MAP = { # Common (non-directional) "freq": ("freq", "freq", "freq_khz"), "mo": ("mode", "mode", "mode_cabrillo"), "date": ("start_time", "start_time", "date_yyyy_mm_dd"), "time": ("start_time", "start_time", "time_hhmm"), # Callsigns "call": ("station_callsign", "callsign", "upper", "My Call", "Call Rcvd"), "callsign": ("station_callsign", "callsign", "upper", "My Call", "Call Rcvd"), # RST "rst": ("rst_sent", "rst_rcvd", ""), # Gridsquare "grid": ("my_gridsquare", "gridsquare", "upper"), # Serial number fields (map to stx / srx) "nr": ("stx", "srx", ""), "number": ("stx", "srx", ""), "num": ("stx", "srx", ""), "ser": ("stx", "srx", ""), "stx": ("stx", "srx", ""), "srx": ("stx", "srx", ""), # Exchange fields (map to stx_string / srx_string) "exch": ("stx_string", "srx_string", ""), "exchange": ("stx_string", "srx_string", ""), "exc": ("stx_string", "srx_string", ""), "ex1": ("stx_string", "srx_string", ""), "ex2": ("stx_string", "srx_string", ""), "ex3": ("stx_string", "srx_string", ""), "sec": ("stx_string", "srx_string", ""), "p": ("stx_string", "srx_string", ""), "ck": ("stx_string", "srx_string", ""), "zn": ("stx_string", "srx_string", ""), "age": ("stx_string", "srx_string", ""), "name": ("stx_string", "srx_string", ""), "qth": ("stx_string", "srx_string", ""), # Transmitter ID (fixed value, not from DB) "t": ("", "", "transmitter_id", "t", "t"), } DEFAULT_FIELDS = ["freq", "mo", "date", "time", "call", "rst", "exch", "call", "rst", "exch", "t"] # --------------------------------------------------------------------------- # Mapping logic # --------------------------------------------------------------------------- def map_field(name, is_sent, is_common): """Map field name to (db_field, formatter, label, needs_review) or None to skip.""" low = name.lower() entry = FIELD_MAP.get(low) if entry is None and low in FIELD_MAP: return None # explicitly skipped if entry is None: # Unknown field -> default to exchange db = "stx_string" if is_sent else "srx_string" sfx = "Sent" if is_sent else "Rcvd" return (db, "", f"{name.title()} {sfx}", False) sent_db, rcvd_db, formatter = entry[0], entry[1], entry[2] db = sent_db if is_sent else rcvd_db if len(entry) >= 5: label = entry[3] if is_sent else entry[4] elif is_common: label = name.title() else: sfx = "Sent" if is_sent else "Rcvd" label = f"{name.title()} {sfx}" return (db, formatter, label, False) def guess_mode(name): u = name.upper() if u.endswith("-CW"): return "CW" if u.endswith("-SSB") or u.endswith("-PH"): return "SSB" if "RTTY" in u or u.endswith("-RY"): return "RTTY" if "PSK" in u or "DIGI" in u or "FT8" in u: return "DIGI" if u.endswith("-FM"): return "FM" return "MIXED" # --------------------------------------------------------------------------- # Parsing helpers # --------------------------------------------------------------------------- def parse_names(line): names = [] for part in line.strip().split(","): m = re.match(r"^\s*([\w-]+)\s*\(([\w-]+)\)\s*$", part) if m: names += [m.group(1), m.group(2)] else: clean = re.sub(r"\s*\(.*?\)", "", part).strip() if clean: names.append(clean) return names def is_name(line): s = line.strip() if not s or s.startswith(("QSO:", "****", "[x")): return False if s[0].isdigit() and s.replace(" ", "").isdigit(): return False return "info sent" not in s.lower() def is_format(line): s = line.strip() return (s.startswith(("QSO:", "****")) and ("***" in s or "yyyy" in s or "nnnn" in s)) def is_header(line): s = line.strip().lower() return (s.startswith("qso:") and not is_format(line) and ("freq" in s or "call" in s)) def tokens(line): t = line.split() return t[1:] if t and t[0] in ("QSO:", "****") else t def esc(s): return s.replace("'", "''") def make_sig(fld, fmt_tok): return " ".join(f"{f}:{len(t)}" for f, t in zip(fld, fmt_tok) if FIELD_MAP.get(f.lower()) is not None or f.lower() not in FIELD_MAP) def load_state(path): state = {} if not os.path.isfile(path): return state with open(path, "r") as f: for line in f: line = line.strip() if line: parts = line.split("\t", 1) state[parts[0]] = parts[1] if len(parts) > 1 else "" return state def save_state(path, state): with open(path, "w") as f: for cid in sorted(state): f.write(f"{cid}\t{state[cid]}\n") def download(): print(f"Downloading {SOURCE_URL} ...", file=sys.stderr) urllib.request.urlretrieve(SOURCE_URL, DAT_PATH) print(f"Saved to {DAT_PATH}", file=sys.stderr) # --------------------------------------------------------------------------- # Main # --------------------------------------------------------------------------- def main(): full = "--full" in sys.argv download() prev = {} if full else load_state(STATE_PATH) with open(DAT_PATH, "r", encoding="utf-8", errors="replace") as f: lines = f.readlines() new_state = {} new_count = changed_count = skip_count = 0 # Collect: (contest_name, display_name, mode, [(pos, db, width, fmt, lbl), ...]) emit_list = [] i = 0 while i < len(lines): line = lines[i].rstrip() if not is_name(line): i += 1 continue names = parse_names(line) if not names or names[0].startswith("Standard"): i += 1 continue hdr = fmt = None j = i + 1 while j < min(i + 10, len(lines)): l = lines[j].rstrip() if is_name(l): break if not hdr and is_header(l): hdr = l if not fmt and is_format(l): fmt = l j += 1 if not fmt: i = j continue fmt_tok = tokens(fmt) fld = tokens(hdr) if hdr else list(DEFAULT_FIELDS[:len(fmt_tok)]) while len(fld) < len(fmt_tok): fld.append("unknown") n = min(len(fld), len(fmt_tok)) fld = fld[:n] fmt_tok = fmt_tok[:n] sig = make_sig(fld, fmt_tok) # Only process ADIF contest IDs names = [n for n in names if n in BUILTIN_CONTEST_IDS] if not names: i = j continue for name in names: new_state[name] = sig # Classify: new / changed / unchanged emit_names = [] for name in names: if name not in prev: emit_names.append(name) new_count += 1 elif prev[name] != sig: emit_names.append(name) changed_count += 1 else: skip_count += 1 if not emit_names: i = j continue # Find sent/rcvd boundary at second call/callsign calls = [k for k in range(n) if fld[k].lower() in ("call", "callsign")] sent0 = calls[0] if calls else n rcvd0 = calls[1] if len(calls) >= 2 else n # Build columns cols = [] pos = 0 for k in range(n): is_common = k < sent0 is_sent = k < rcvd0 mapped = map_field(fld[k], is_sent, is_common) if mapped is None: continue pos += 1 db, fmtr, lbl, _ = mapped cols.append((pos, db, len(fmt_tok[k]), fmtr, lbl)) for name in emit_names: emit_list.append((name, name.replace("-", " "), guess_mode(name), cols)) i = j # -- Generate SQL ------------------------------------------------------- out = ["-- Generated by devtools/cabrillo/generate_cabrillo_templates.py", "-- Source: " + SOURCE_URL, ""] if not emit_list: out.append("-- Nothing to emit.") else: for cid, display, mode, cols in emit_list: e = esc(cid) ed = esc(display) out.append( f"DELETE FROM cabrillo_templates " f"WHERE name = '{ed}';") out.append( f"INSERT INTO cabrillo_templates " f"(name, contest_name_for_header, " f"default_category_mode) VALUES " f"('{ed}', '{e}', '{esc(mode)}');") for p, db, w, fmtr, lbl in cols: out.append( f"INSERT INTO cabrillo_template_columns " f"(template_id, position, db_field, width, formatter, label) " f"SELECT id, {p}, '{esc(db)}', {w}, '{esc(fmtr)}', " f"'{esc(lbl)}' FROM cabrillo_templates " f"WHERE name = '{ed}';") out.append("") save_state(STATE_PATH, new_state) print("\n".join(out)) parts = [] if full: parts.append(f"{new_count} templates [full]") else: parts.append(f"{new_count} new, {changed_count} changed, " f"{skip_count} unchanged") print(", ".join(parts), file=sys.stderr) if __name__ == "__main__": main() foldynl-QLog-3252ff9/devtools/deployment/000077500000000000000000000000001517334601000204025ustar00rootroot00000000000000foldynl-QLog-3252ff9/devtools/deployment/finalize_release.sh000077500000000000000000000106711517334601000242470ustar00rootroot00000000000000#!/usr/bin/env bash # The script finalizes the release and edits the changlog in deployment scripts. # # Usage: # ./devtools/deployment/finalize_release.sh # # Must be executed from the QLog root directory. # Changelog is the single source of truth. set -uo pipefail ROOTDIR=. CHANGELOG="${ROOTDIR}/Changelog" QLOG_PRO="${ROOTDIR}/QLog.pro" if [ ! -f "${QLOG_PRO}" ]; then echo "ERROR: QLog.pro not found. Run this script from the QLog root directory." exit 1 fi # --- Checks --- DEB_CHANGELOG="${ROOTDIR}/debian/changelog" RPM_SPEC="${ROOTDIR}/rpm_spec/qlog.spec" METAINFO="${ROOTDIR}/res/io.github.foldynl.QLog.metainfo.xml" INSTALLER_PKG="${ROOTDIR}/installer/packages/de.dl2ic.qlog/meta/package.xml" INSTALLER_CFG="${ROOTDIR}/installer/config/config.xml" # Cleanup temp files on exit TMPFILE=$(mktemp) trap 'rm -f "${TMPFILE}"' EXIT if ! head -n 1 "${CHANGELOG}" | grep -q '^TBC - '; then echo "ERROR: Changelog does not start with 'TBC'. Already finalized?" exit 1 fi # --- Extract data --- QLOG_VERSION=$(head -n 1 "${CHANGELOG}" | awk '{print $3}') RELEASE_DATE_ISO=$(date "+%Y-%m-%d") RELEASE_DATE_CHANGELOG=$(date "+%Y/%m/%d") RELEASE_DATE_DEB=$(date "+%a, %-d %b %Y %T %z") RELEASE_DATE_RPM=$(date "+%a %b %-d %Y") # Changelog entries: lines from 2nd line until first empty line ENTRIES=$(sed -n '2,/^$/{ /^$/d; p }' "${CHANGELOG}") echo "Preparing release ${QLOG_VERSION} (${RELEASE_DATE_ISO})" # --- Helper --- xml_escape() { sed 's/&/\&/g; s//\>/g' } # --- QLog.pro --- echo " QLog.pro" sed -i "s/VERSION = .*/VERSION = ${QLOG_VERSION}/" "${QLOG_PRO}" # --- Changelog --- echo " Changelog" sed -i "s#^TBC - #${RELEASE_DATE_CHANGELOG} - #" "${CHANGELOG}" # --- DEB Changelog --- echo " debian/changelog" { echo "qlog (${QLOG_VERSION}-1) UNRELEASED; urgency=low" echo "${ENTRIES}" | sed 's/^-/ */' echo "" echo " -- foldynl ${RELEASE_DATE_DEB}" echo "" cat "${DEB_CHANGELOG}" } > "${TMPFILE}" cp "${TMPFILE}" "${DEB_CHANGELOG}" # --- RPM Changelog --- echo " rpm_spec/qlog.spec" { echo "* ${RELEASE_DATE_RPM} Ladislav Foldyna - ${QLOG_VERSION}-1" echo "${ENTRIES}" echo "" } > "${TMPFILE}" sed -i -e "/%changelog/{r ${TMPFILE}" -e '}' "${RPM_SPEC}" # --- Appstream Metainfo --- echo " res/io.github.foldynl.QLog.metainfo.xml" { echo " " echo " " echo "
    " echo "${ENTRIES}" | sed 's/^- //' | xml_escape | sed 's/^/
  • /; s/$/<\/li>/' echo "
" echo "
" echo "
" } > "${TMPFILE}" sed -i -e "/ /{r ${TMPFILE}" -e '}' "${METAINFO}" appstreamcli validate "${METAINFO}" # --- Qt Installer files --- echo " installer/packages/.../package.xml" sed -i "s/.*<\/Version>/${QLOG_VERSION}-1<\/Version>/" "${INSTALLER_PKG}" sed -i "s/.*<\/ReleaseDate>/${RELEASE_DATE_ISO}<\/ReleaseDate>/" "${INSTALLER_PKG}" echo " installer/config/config.xml" sed -i "s/.*<\/Version>/${QLOG_VERSION}<\/Version>/" "${INSTALLER_CFG}" # --- Summary --- echo "" echo "Release ${QLOG_VERSION} finalized. Changed files:" echo " - ${QLOG_PRO}" echo " - ${CHANGELOG}" echo " - ${DEB_CHANGELOG}" echo " - ${RPM_SPEC}" echo " - ${METAINFO}" echo " - ${INSTALLER_PKG}" echo " - ${INSTALLER_CFG}" # --- Commit --- echo "" read -r -p "Commit changes? [y/N] " confirm if [[ ! "${confirm}" =~ ^[Yy]$ ]]; then echo "Aborted." exit 0 fi git commit -a -m "Preparation for release ${QLOG_VERSION}" echo "Changes committed." # --- Push, merge to master --- BRANCH=$(git rev-parse --abbrev-ref HEAD) echo "" echo "Pushing ${BRANCH}..." git push origin "${BRANCH}" echo "Switching to master and merging ${BRANCH}..." git checkout master git pull git merge "${BRANCH}" # --- Tag and push --- TAG="v${QLOG_VERSION}" echo "" echo "Wait for GitHub Actions to pass, then confirm." echo "" read -r -p "Tag and push ${TAG}? [y/N] " confirm if [[ ! "${confirm}" =~ ^[Yy]$ ]]; then echo "Aborted. To tag manually later:" echo " git tag -a ${TAG} -m \"Release ${QLOG_VERSION}\"" echo " git push --atomic origin master ${TAG}" exit 0 fi git tag -a "${TAG}" -m "Release ${QLOG_VERSION}" git push --atomic origin master "${TAG}" echo "" echo "Tag ${TAG} pushed. You can now create the GitHub release:" echo " ./devtools/deployment/create_github_release.sh" foldynl-QLog-3252ff9/devtools/timezones/000077500000000000000000000000001517334601000202375ustar00rootroot00000000000000foldynl-QLog-3252ff9/devtools/timezones/README.md000066400000000000000000000007751517334601000215270ustar00rootroot00000000000000# Database files Please download the database files [here](https://cdn.bertold.org/zonedetect/db/db.zip) or create them using the builder. To use the builder, first install [shapelib](https://github.com/OSGeo/shapelib), then: cd builder ./makedb.sh This will create database files in `out` and `out_v1`, as well as a `db.zip` containing both directories. The files in the folder out\_v1/ use a newer format and use less space to encode the same information. QLog uses out\_v1/timezone21.bin foldynl-QLog-3252ff9/devtools/timezones/builder/000077500000000000000000000000001517334601000216655ustar00rootroot00000000000000foldynl-QLog-3252ff9/devtools/timezones/builder/builder.cpp000066400000000000000000000626641517334601000240350ustar00rootroot00000000000000/* * Copyright (c) 2018, Bertold Van den Bergh (vandenbergh@bertold.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the author nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTOR 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 #include #include #include #include #include #include #include #include #include #include unsigned version = 1; const double Inf = std::numeric_limits::infinity(); std::unordered_map alpha2ToName; std::unordered_map tzidToAlpha2; void errorFatal(std::string what) { std::cerr<& output, int64_t valueIn, bool handleNeg = true) { uint64_t value = valueIn; if(handleNeg) { value = encodeSignedToUnsigned(valueIn); } int bytesUsed = 0; do { uint8_t byteOut = value & 0x7F; if(value >= 128) { byteOut |= 128; } output.push_back(byteOut); bytesUsed ++; value >>= 7; } while(value); return bytesUsed; } uint64_t encodePointTo64(int64_t lat, int64_t lon){ assert_(lat || lon, "Tried to encode 0,0. This is not allowed"); uint64_t latu=encodeSignedToUnsigned(lat); uint64_t lonu=encodeSignedToUnsigned(lon); assert_(latu < (uint64_t)1<<32, "Unsigned lat overflow"); assert_(lonu < (uint64_t)1<<32, "Unsigned lat overflow"); uint64_t point = 0; for(uint8_t i=31; i<=31; i--){ point <<= 2; if(latu & (1< pointMap_; struct Point { static Point* GetPoint(double dlat = 0, double dlon = 0, unsigned int precision = 32){ int64_t lat = doubleToFixedPoint(dlat, 90, precision); int64_t lon = doubleToFixedPoint(dlon, 180, precision); uint64_t key = encodePointTo64(lat, lon); if(pointMap_.count(key)){ return pointMap_[key]; } Point* p = new Point(lat, lon); p->key_ = key; pointMap_[key] = p; return p; } Point(int64_t lat = 0, int64_t lon = 0) { lat_ = lat; lon_ = lon; } std::tuple value() { return std::make_tuple(lat_, lon_); } int encodePointBinary(std::vector& output) { int bytesUsed = encodeVariableLength(output, lat_); bytesUsed += encodeVariableLength(output, lon_); return bytesUsed; } int64_t lat_; int64_t lon_; uint64_t key_; PolygonData* parent_ = nullptr; int index_ = 0; bool encoded_ = false; uint64_t encodedOffset_ = 0; }; struct PolygonData { Point boundingMin; Point boundingMax; std::vector points_; unsigned long fileIndex_ = 0; unsigned long metadataId_; Point* lastPoint_ = nullptr; void processPoint(Point* p) { if(p->lat_ < boundingMin.lat_) { boundingMin.lat_ = p->lat_; } if(p->lon_ < boundingMin.lon_) { boundingMin.lon_ = p->lon_; } if(p->lat_ > boundingMax.lat_) { boundingMax.lat_ = p->lat_; } if(p->lon_ > boundingMax.lon_) { boundingMax.lon_ = p->lon_; } /* Don't encode duplicate points */ if(lastPoint_ == p){ return; } lastPoint_ = p; points_.push_back(p); } PolygonData(unsigned long id): boundingMin(INT64_MAX, INT64_MAX), boundingMax(INT64_MIN, INT64_MIN), metadataId_(id) { } struct LineSegment { std::vector points_; Point* prevPoint_; PolygonData* parent_; bool sameDirection(int64_t x1, int64_t y1, int64_t x2, int64_t y2){ if(!x2 && !y2){ return false; } if((x1 > 0 && x2 < 0) || (x1 < 0 && x2 > 0)){ return false; } if((y1 > 0 && y2 < 0) || (y1 < 0 && y2 > 0)){ return false; } if(x1 == 0){ return x2 == 0; } return y2 == (y1*x2/x1); } unsigned int encodeDelta(std::vector& output, PolygonData* mark = nullptr, int start = 0, int end = -1){ unsigned int numPoints = 0; if(end < 0){ end = points_.size()-1; } int64_t accDiffLat = 0, accDiffLon = 0; int64_t prevDiffLat = 0, prevDiffLon = 0; int64_t prevLat, prevLon; Point* prevPoint = prevPoint_; if(start > 0){ prevPoint = points_[start-1]; } std::tie(prevLat, prevLon) = prevPoint->value(); auto encodePoint = [&](bool force = false){ /* Encode accumulator. * After this the position is equal to that of the previous point */ if(accDiffLat || accDiffLon || force){ if(version == 0){ encodeVariableLength(output, accDiffLat); encodeVariableLength(output, accDiffLon); }else{ encodeVariableLength(output, encodePointTo64(accDiffLat, accDiffLon), false); } numPoints++; } /* Mark points as encoded if we mark and we are the parent */ if(mark && prevPoint->parent_ == mark){ prevPoint->encoded_ = true; prevPoint->encodedOffset_ = output.size(); } /* Reset accumulator */ accDiffLat = 0; accDiffLon = 0; }; for(int i = start; i<=end; i++){ Point* point = points_[i]; int64_t lat, lon; std::tie(lat, lon) = point->value(); /* Calculate difference */ int64_t diffLat = lat - prevLat; int64_t diffLon = lon - prevLon; /* Encode delta */ if(!sameDirection(diffLat, diffLon, prevDiffLat, prevDiffLon)){ encodePoint(); } accDiffLat += diffLat; accDiffLon += diffLon; /* Store previous values */ prevDiffLat = diffLat; prevDiffLon = diffLon; prevLat = lat; prevLon = lon; prevPoint = point; } /* Encode remainder if needed */ encodePoint(version == 0); return numPoints; } bool encodeReference(std::vector& output){ /* Search for first marked point */ int end = -1, start = -1; for(int i=0; iencoded_){ start = i; break; } } for(int i=points_.size()-1; i>=0; i--){ if(points_[i]->encoded_){ end = i; break; } } if(end < 0 || start < 0){ /* Only unencoded points, then we can only delta encode it ourself */ return false; } /* Encode delta until where we can refer */ encodeDelta(output, nullptr, 0, start); /* Add reference marker if it is still needed */ if(start != end){ uint64_t startRef = points_[start]->encodedOffset_; uint64_t endRef = points_[end]->encodedOffset_; output.push_back(0); output.push_back(1); encodeVariableLength(output, startRef, false); int64_t diff = endRef - startRef; encodeVariableLength(output, diff, true); } /* Encode delta till the end of the segment */ encodeDelta(output, nullptr, end+1); return true; } }; unsigned int encodeBinaryData(std::vector& output) { std::vector lines_; PolygonData* currentParent = nullptr; LineSegment* segment = nullptr; /* Step 1: Encode first point */ Point* prevPoint = points_[0]; if(version == 0){ prevPoint->encodePointBinary(output); }else{ encodeVariableLength(output, prevPoint->key_, false); } int direction = 0; /* Step 2: Go through the list of points and check which ones already exist. * We skip the first and last one since the first one is already encoded * and the last one is identical to the first */ for(int i=1; iparent_){ point->parent_ = this; point->index_ = i; } bool newSegment = false; if(point->parent_ == currentParent){ if(direction == 0){ direction = point->index_ - prevPoint->index_; if(direction > 1 || direction < -1){ newSegment = true; } }else{ if(point->index_ != prevPoint->index_ + direction){ newSegment = true; } } } if(point->parent_ != currentParent || newSegment){ if(segment){ lines_.push_back(segment); } currentParent = point->parent_; segment = new LineSegment(); segment->prevPoint_ = prevPoint; segment->parent_ = currentParent; direction = 0; } segment->points_.push_back(point); prevPoint = point; } if(segment){ lines_.push_back(segment); } unsigned int v0Points = 1; /* Step 3: Encode segments */ for(LineSegment* segment: lines_){ if(segment->parent_ == this || version == 0){ /* If we are the parent of the segment we must encode and mark it */ v0Points += segment->encodeDelta(output, this); }else{ /* We are not the parent, we can encode it or refer to it, depending on * which takes less bytes. In any case we should not mark it. */ std::vector delta; segment->encodeDelta(delta); std::vector reference; bool possible = segment->encodeReference(reference); if(!possible || delta.size() <= reference.size()){ output.insert(std::end(output), std::begin(delta), std::end(delta)); }else{ output.insert(std::end(output), std::begin(reference), std::end(reference)); } } } if (version != 0){ /* Step 4: Write end marker */ output.push_back(0); output.push_back(0); } return v0Points; } }; void encodeStringToBinary(std::vector& output, std::string& input) { encodeVariableLength(output, input.size(), false); for(unsigned int i=0; i usedStrings_; struct MetaData { void encodeBinaryData(std::vector& output) { for(std::string& str: data_) { if(str.length() >= 256) { std::cout << "Metadata string is too long\n"; exit(1); } if(!usedStrings_.count(str)) { usedStrings_[str] = output.size(); encodeStringToBinary(output, str); } else { encodeVariableLength(output, usedStrings_[str] + 256, false); } } } std::vector data_; unsigned long fileIndex_; }; std::vector polygons_; std::vector metadata_; std::vector fieldNames_; unsigned int decodeVariableLength(uint8_t* buffer, int64_t* result, bool handleNeg = true) { int64_t value = 0; unsigned int i=0, shift = 0; do { value |= (buffer[i] & 0x7F) << shift; shift += 7; } while(buffer[i++] & 0x80); if(!handleNeg) { *result = value; } else { *result = (value & 1)?-(value/2):(value/2); } return i; } void readMetaDataTimezone(DBFHandle dataHandle) { /* Specify field names */ fieldNames_.push_back("TimezoneIdPrefix"); fieldNames_.push_back("TimezoneId"); fieldNames_.push_back("CountryAlpha2"); fieldNames_.push_back("CountryName"); /* Parse attribute names */ for(int i = 0; i < DBFGetRecordCount(dataHandle); i++) { metadata_[i].data_.resize(4); for(int j = 0; j < DBFGetFieldCount(dataHandle); j++) { char fieldTitle[12]; int fieldWidth, fieldDecimals; DBFFieldType eType = DBFGetFieldInfo(dataHandle, j, fieldTitle, &fieldWidth, &fieldDecimals); fieldTitle[11] = 0; std::string fieldTitleStr(fieldTitle); if( eType == FTString ) { if(fieldTitleStr == "tzid") { std::string data = DBFReadStringAttribute(dataHandle, i, j); size_t pos = data.find('/'); if (pos == std::string::npos) { metadata_[i].data_.at(0) = data; } else { metadata_[i].data_.at(0) = data.substr(0, pos) + "/"; metadata_[i].data_.at(1) = data.substr(pos + 1, std::string::npos); } if(tzidToAlpha2.count(data)) { metadata_[i].data_.at(2) = tzidToAlpha2[data]; if(alpha2ToName.count(metadata_[i].data_.at(2))) { metadata_[i].data_.at(3) = alpha2ToName[metadata_[i].data_.at(2)]; } else { std::cout< parseAlpha2ToName(DBFHandle dataHandle) { std::unordered_map result; for(int i = 0; i < DBFGetRecordCount(dataHandle); i++) { std::string alpha2, name; for(int j = 0; j < DBFGetFieldCount(dataHandle); j++) { char fieldTitle[12]; int fieldWidth, fieldDecimals; DBFFieldType eType = DBFGetFieldInfo(dataHandle, j, fieldTitle, &fieldWidth, &fieldDecimals); fieldTitle[11] = 0; std::string fieldTitleStr(fieldTitle); if( eType == FTString ) { if(fieldTitleStr == "ISO_A2" || fieldTitleStr == "WB_A2") { std::string tmp = DBFReadStringAttribute(dataHandle, i, j); if(tmp != "-99" && alpha2 == "") { alpha2 = tmp; } } else if(fieldTitleStr == "NAME_LONG") { name = DBFReadStringAttribute(dataHandle, i, j); } } } if(alpha2 != "") { result[alpha2]=name; } } result["GF"]="French Guiana"; result["GP"]="Guadeloupe"; result["BQ"]="Bonaire"; result["MQ"]="Martinique"; result["SJ"]="Svalbard and Jan Mayen Islands"; result["NO"]="Norway"; result["CX"]="Christmas Island"; result["CC"]="Cocos Islands"; result["YT"]="Mayotte"; result["RE"]="Réunion"; result["TK"]="Tokelau"; result["TW"]="Taiwan"; return result; } std::unordered_map parseTimezoneToAlpha2(std::string path) { std::unordered_map result; //TODO: Clean solution... #include "zoneToAlpha.h" return result; } int main(int argc, char ** argv ) { if(argc != 7) { std::cout << "Wrong number of parameters\n"; return 1; } tzidToAlpha2 = parseTimezoneToAlpha2("TODO"); char tableType = argv[1][0]; std::string path = argv[2]; std::string outPath = argv[3]; unsigned int precision = strtol(argv[4], NULL, 10); std::string notice = argv[5]; version = strtol(argv[6], NULL, 10); if(version > 1){ std::cout << "Unknown version\n"; return 1; } DBFHandle dataHandle = DBFOpen("naturalearth/ne_10m_admin_0_countries_lakes", "rb" ); alpha2ToName = parseAlpha2ToName(dataHandle); DBFClose(dataHandle); dataHandle = DBFOpen(path.c_str(), "rb" ); if( dataHandle == NULL ) { errorFatal("Could not open attribute file\n"); } metadata_.resize(DBFGetRecordCount(dataHandle)); std::cout << "Reading "<nSHPType != 3 && shapeObject->nSHPType != 5 && shapeObject->nSHPType != 13 && shapeObject->nSHPType != 15) { std::cout<<"Unsupported shape object ("<< SHPTypeName(shapeObject->nSHPType) <<")\n"; continue; } int partIndex = 0; PolygonData* polygonData = nullptr; for(int j = 0; j < shapeObject->nVertices; j++ ) { if(j == 0 || j == shapeObject->panPartStart[partIndex]) { totalPolygons++; if(polygonData) { /* Commit it */ polygons_.push_back(polygonData); } polygonData = new PolygonData(i); if(partIndex + 1 < shapeObject->nParts) { partIndex++; } } Point* p = Point::GetPoint(shapeObject->padfY[j], shapeObject->padfX[j], precision); polygonData->processPoint(p); } if(polygonData) { /* Commit it */ polygons_.push_back(polygonData); } SHPDestroyObject(shapeObject); } } SHPClose(shapeHandle); std::cout<<"Parsed "<boundingMin.lat_ < b->boundingMin.lat_; }); /* Encode data section and store pointers */ std::vector outputData; for(PolygonData* polygon: polygons_) { polygon->fileIndex_ = outputData.size(); if(version == 0){ std::vector tmpData; unsigned int numPoints = polygon->encodeBinaryData(tmpData); encodeVariableLength(outputData, numPoints, false); outputData.insert(std::end(outputData), std::begin(tmpData), std::end(tmpData)); }else{ polygon->encodeBinaryData(outputData); } } std::cout << "Encoded data section into "< outputMeta; for(MetaData& metadata: metadata_) { metadata.fileIndex_ = outputMeta.size(); metadata.encodeBinaryData(outputMeta); } std::cout << "Encoded metadata into "< outputBBox; int64_t prevFileIndex = 0; int64_t prevMetaIndex = 0; for(PolygonData* polygon: polygons_) { polygon->boundingMin.encodePointBinary(outputBBox); polygon->boundingMax.encodePointBinary(outputBBox); encodeVariableLength(outputBBox, metadata_.at(polygon->metadataId_).fileIndex_ - prevMetaIndex); prevMetaIndex = metadata_[polygon->metadataId_].fileIndex_; encodeVariableLength(outputBBox, polygon->fileIndex_ - prevFileIndex, false); prevFileIndex = polygon->fileIndex_; } std::cout << "Encoded bounding box section into "< outputHeader; outputHeader.push_back('P'); outputHeader.push_back('L'); outputHeader.push_back('B'); outputHeader.push_back(tableType); outputHeader.push_back(version); outputHeader.push_back(precision); outputHeader.push_back(fieldNames_.size()); for(unsigned int i=0; i release rem %~nx0 release -> release rem %~nx0 clean -> clean release rem %~nx0 rebuild -> clean + release rem %~nx0 deploy -> windeployqt + binarycreator rem %~nx0 all -> rebuild + deploy rem ============================================================ rem ============================================================ rem - The script is executed in cmd.exe on Windows. rem - The Visual Studio environment init batch (VS_VCVARS) must exist. rem - It must support the selected target (VS_ARCH), e.g. x86_amd64 for x64 builds. rem - The Qt MSVC kit root (QT_BASE) must exist and contain: rem - %QT_BASE%\bin\qmake.exe rem - %QT_BASE%\bin\windeployqt.exe rem - The jom executable (JOM) must exist (used for qmake_all and Makefile.Release). rem - The Qt Installer Framework bin directory (QTIFW_BIN) must exist and contain: rem - binarycreator.exe rem - The QMake project file (PRO) must exist and be readable. rem - The working/build directory must be writable (Makefile.Release will be generated). rem rem - Hamlib must be present under %DEVROOT%\hamlib-w64-%HAMLIBVERSION% derived from HAMLIBVERSION: rem - Expected headers: %HAMLIBROOT%\include\ rem - Expected libraries: %HAMLIBROOT%\lib\msvc\ rem rem - vcpkg packages root (VCPKG_PACKAGES) must exist and contain required packages: rem - %VCPKG_PACKAGES%\%QTKEYCHAIN_PKG%\include and ...\lib rem - %VCPKG_PACKAGES%\%PTHREAD_PKG%\include and ...\lib rem - %VCPKG_PACKAGES%\%ZLIB_PKG%\include and ...\lib rem rem ============================================================ set "ROOT=%~dp0" if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" for %%I in ("%ROOT%\..\..\..") do set "DEVROOT=%%~fI" rem === CONFIGURATION === rem -- VC Compiler Settings set "VS_VCVARS=C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" rem -- QT Settings set "QT_BASE=C:\Qt\6.10.2\msvc2022_64" set "QTIFW_BIN=C:\Qt\Tools\QtInstallerFramework\4.6\bin" set "JOM=C:\Qt\Tools\QtCreator\bin\jom\jom.exe" rem -- Project Settings set "PROJECT_BASE=%DEVROOT%\QLog" for /f "tokens=3" %%V in ('findstr /R /C:"^VERSION *= *" "%PROJECT_BASE%\QLog.pro"') do set "QLOG_VERSION=%%V" set "INSTALLER_BASE=%DEVROOT%\qlog_build\qlog-installer-%QLOG_VERSION%" set "INSTALLER_SEQ=0" if exist "%INSTALLER_BASE%.exe" ( :seq_loop set /a INSTALLER_SEQ+=1 if exist "%INSTALLER_BASE%-!INSTALLER_SEQ!.exe" goto :seq_loop ) if %INSTALLER_SEQ%==0 ( set "INSTALLER_OUT=%INSTALLER_BASE%.exe" ) else ( set "INSTALLER_OUT=%INSTALLER_BASE%-!INSTALLER_SEQ!.exe" ) rem -- Libs Settings set "VCPKG_PACKAGES=%DEVROOT%\vcpkg\packages" set "VCPKG_QTKEYCHAIN_PKG=qtkeychain-qt6_x64-windows" set "VCPKG_PTHREAD_PKG=pthreads_x64-windows" set "VCPKG_ZLIB_PKG=zlib_x64-windows" rem -- Hamlib Settings set "HAMLIBVERSION_MAJOR=4" set "HAMLIBVERSION_MINOR=7" set "HAMLIBVERSION_PATCH=0" rem === END OF CONFIGURATION === set "VS_ARCH=x86_amd64" set "QMAKE=%QT_BASE%\bin\qmake.exe" set "WINDEPLOYQT=%QT_BASE%\bin\windeployqt.exe" set "BINARYCREATOR=%QTIFW_BIN%\binarycreator.exe" set "PRO=%PROJECT_BASE%\QLog.pro" set "BUILDROOT=%PROJECT_BASE%\build\deployment" set "HAMLIBVERSION=%HAMLIBVERSION_MAJOR%.%HAMLIBVERSION_MINOR%.%HAMLIBVERSION_PATCH%" set "HAMLIBROOT=%DEVROOT%\hamlib-w64-%HAMLIBVERSION%" set "HAMLIBINCLUDEPATH=%HAMLIBROOT%\include" set "HAMLIBLIBPATH=%HAMLIBROOT%\lib\msvc" set "HAMLIBBINPATH=%HAMLIBROOT%\bin" set "QTKEYCHAININCLUDEPATH=%VCPKG_PACKAGES%\%VCPKG_QTKEYCHAIN_PKG%\include" set "QTKEYCHAINLIBPATH=%VCPKG_PACKAGES%\%VCPKG_QTKEYCHAIN_PKG%\lib" set "QTKEYCHAINBINPATH=%VCPKG_PACKAGES%\%VCPKG_QTKEYCHAIN_PKG%\bin" set "PTHREADINCLUDEPATH=%VCPKG_PACKAGES%\%VCPKG_PTHREAD_PKG%\include" set "PTHREADLIBPATH=%VCPKG_PACKAGES%\%VCPKG_PTHREAD_PKG%\lib" set "ZLIBINCLUDEPATH=%VCPKG_PACKAGES%\%VCPKG_ZLIB_PKG%\include" set "ZLIBLIBPATH=%VCPKG_PACKAGES%\%VCPKG_ZLIB_PKG%\lib" set "ZLIBBINPATH=%VCPKG_PACKAGES%\%VCPKG_ZLIB_PKG%\bin" set "DEPLOY_DIR=%BUILDROOT%\installer\packages\de.dl2ic.qlog\data" set "INSTALLER_CONFIG=%BUILDROOT%\installer\config\config.xml" set "INSTALLER_PACKAGES=%BUILDROOT%\installer\packages" set "OPENSSLROOT=%DEVROOT%\openssl-3.0\x64" rem === Action === set "ACTION=%~1" if /I "%ACTION%"=="" set "ACTION=release" if not exist "%BUILDROOT%" mkdir "%BUILDROOT%" pushd "%BUILDROOT%" >nul rem === Initialize MSVC environment === echo === Initializing MSVC environment (%VS_ARCH%) === call "%VS_VCVARS%" %VS_ARCH% if errorlevel 1 goto :fail if /I "%ACTION%"=="clean" goto :clean if /I "%ACTION%"=="rebuild" goto :rebuild if /I "%ACTION%"=="release" goto :release if /I "%ACTION%"=="deploy" goto :deploy if /I "%ACTION%"=="all" goto :all echo Unknown action: %ACTION% echo Usage: %~nx0 [release^|clean^|rebuild^|deploy^|all] goto :fail rem ============================================================ rem BUILD STEPS rem ============================================================ :qmake echo === Running qmake === "%QMAKE%" "%PRO%" -spec win32-msvc ^ "CONFIG+=qtquickcompiler" ^ "HAMLIBINCLUDEPATH=%HAMLIBINCLUDEPATH%" ^ "HAMLIBLIBPATH=%HAMLIBLIBPATH%" ^ "HAMLIBVERSION_MAJOR=%HAMLIBVERSION_MAJOR%" ^ "HAMLIBVERSION_MINOR=%HAMLIBVERSION_MINOR%" ^ "HAMLIBVERSION_PATCH=%HAMLIBVERSION_PATCH%" ^ "QTKEYCHAININCLUDEPATH=%QTKEYCHAININCLUDEPATH%" ^ "QTKEYCHAINLIBPATH=%QTKEYCHAINLIBPATH%" ^ "PTHREADINCLUDEPATH=%PTHREADINCLUDEPATH%" ^ "PTHREADLIBPATH=%PTHREADLIBPATH%" ^ "ZLIBINCLUDEPATH=%ZLIBINCLUDEPATH%" ^ "ZLIBLIBPATH=%ZLIBLIBPATH%" ^ "OPENSSLINCLUDEPATH=%OPENSSLROOT%/include" ^ "OPENSSLLIBPATH=%OPENSSLROOT%/lib" if errorlevel 1 exit /b 10 echo === jom qmake_all === "%JOM%" qmake_all if errorlevel 1 exit /b 11 exit /b 0 :clean call :qmake if errorlevel 1 goto :fail echo === Cleaning (Makefile.Release) === "%JOM%" -f Makefile.Release clean if errorlevel 1 goto :fail del /F /Q "%BUILDROOT%\release\qlog.exe" >nul rmdir /S /Q "%BUILDROOT%\installer" >nul goto :ok :release call :qmake if errorlevel 1 goto :fail echo === Building Release (Makefile.Release) === "%JOM%" -f Makefile.Release if errorlevel 1 goto :fail goto :ok :rebuild call :qmake if errorlevel 1 goto :fail echo === Cleaning (Makefile.Release) === "%JOM%" -f Makefile.Release clean if errorlevel 1 goto :fail echo === Building Release (Makefile.Release) === "%JOM%" -f Makefile.Release if errorlevel 1 goto :fail goto :ok rem ============================================================ rem DEPLOYMENT STEPS rem ============================================================ :deploy echo === Deployment === rem Ensure tools are reachable (only for this process) set "PATH=%QT_BASE%\bin;%QTIFW_BIN%;%PATH%" if not exist "%BUILDROOT%\release\qlog.exe" ( echo ERROR: "%BUILDROOT%\release\qlog.exe" not found. echo Check DEPLOY_DIR: "%DEPLOY_DIR%" goto :fail ) robocopy "%PROJECT_BASE%\installer" "%BUILDROOT%\installer" /MIR if errorlevel 8 ( echo ERROR: Cannot ROBOCOPY installer goto :fail ) mkdir "%DEPLOY_DIR%" rem ***************** rem Copy QLog Binary rem ***************** copy /Y "%BUILDROOT%\release\qlog.exe" "%DEPLOY_DIR%\qlog.exe" if errorlevel 1 ( echo ERROR: Cannot copy qlog.exe to "%DEPLOY_DIR%" goto :fail ) rem *********** rem Copy Hamlib rem *********** copy /Y "%HAMLIBBINPATH%\*.dll" "%DEPLOY_DIR%" if errorlevel 1 ( echo ERROR: Cannot copy Hamlib DLL to "%DEPLOY_DIR%" goto :fail ) copy /Y "%HAMLIBBINPATH%\rigctld.exe" "%DEPLOY_DIR%" if errorlevel 1 ( echo ERROR: Cannot copy rigctld.exe to "%DEPLOY_DIR%" goto :fail ) rem **************** rem Copy QtKeychain rem **************** copy /Y "%QTKEYCHAINBINPATH%\*.dll" "%DEPLOY_DIR%" if errorlevel 1 ( echo ERROR: Cannot copy QTKeychain DLL to "%DEPLOY_DIR%" goto :fail ) rem **************** rem Copy zlib rem **************** copy /Y "%ZLIBBINPATH%\*.dll" "%DEPLOY_DIR%" if errorlevel 1 ( echo ERROR: Cannot copy zlib DLL to "%DEPLOY_DIR%" goto :fail ) rem **************** rem Copy OpenSSL rem **************** copy /Y "%OPENSSLROOT%\bin\*.dll" "%DEPLOY_DIR%" if errorlevel 1 ( echo ERROR: Cannot copy OpenSSL DLL to "%DEPLOY_DIR%" goto :fail ) rem **************** rem Deploy rem **************** pushd "%DEPLOY_DIR%" >nul if errorlevel 1 ( echo ERROR: Cannot enter DEPLOY_DIR: "%DEPLOY_DIR%" goto :fail ) echo --- windeployqt (release) --- "%WINDEPLOYQT%" -release --openssl-root "%OPENSSLROOT%" --skip-plugin-types qmltooling,position,qml,qsqlpsql,qsqlodbc,qsqlmimer "qlog.exe" if errorlevel 1 ( popd >nul goto :fail ) popd >nul if not exist "%BINARYCREATOR%" ( echo ERROR: binarycreator.exe not found: "%BINARYCREATOR%" goto :fail ) echo --- binarycreator --- "%BINARYCREATOR%" -f -c "%INSTALLER_CONFIG%" -p "%INSTALLER_PACKAGES%" "%INSTALLER_OUT%" if errorlevel 1 goto :fail goto :ok :all call :rebuild if errorlevel 1 goto :fail call :deploy if errorlevel 1 goto :fail goto :ok rem ============================================================ rem END rem ============================================================ :ok popd >nul endlocal exit /b 0 :fail set "EC=%errorlevel%" if "%EC%"=="0" set "EC=1" echo. echo FAILED with errorlevel %EC% popd >nul endlocal exit /b %EC% foldynl-QLog-3252ff9/devtools/windowsMake/tests.bat000066400000000000000000000131331517334601000223450ustar00rootroot00000000000000@echo off setlocal EnableExtensions EnableDelayedExpansion rem ============================================================ rem Build + Run all unit tests for QLog (MSVC + Qt) rem Usage: rem %~nx0 -> build (release) + run rem %~nx0 all -> build (release) + run rem %~nx0 build -> build only (release) rem %~nx0 run -> run existing binaries rem %~nx0 clean -> clean build directory rem %~nx0 rebuild -> clean + build + run rem ============================================================ rem Notes: rem - This script is executed in cmd.exe on Windows. rem - It expects MSVC environment init batch (VS_VCVARS) and Qt qmake. rem - QTKEYCHAIN/HAMLIB/ZLIB paths are passed through like in make.bat. rem ============================================================ set "ROOT=%~dp0" if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" for %%I in ("%ROOT%\..\..\..") do set "DEVROOT=%%~fI" rem === CONFIGURATION (keep in sync with make.bat) === rem -- VC Compiler Settings set "VS_VCVARS=C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" set "VS_ARCH=x86_amd64" rem -- QT Settings set "QT_BASE=C:\Qt\6.10.2\msvc2022_64" set "JOM=C:\Qt\Tools\QtCreator\bin\jom\jom.exe" rem -- Project Settings set "PROJECT_BASE=%DEVROOT%\QLog" set "PRO=%PROJECT_BASE%\tests\tests.pro" set "BUILDROOT=%PROJECT_BASE%\build\tests" rem -- Libs Settings set "VCPKG_PACKAGES=%DEVROOT%\vcpkg\packages" set "VCPKG_QTKEYCHAIN_PKG=qtkeychain-qt6_x64-windows" set "VCPKG_PTHREAD_PKG=pthreads_x64-windows" set "VCPKG_ZLIB_PKG=zlib_x64-windows" rem -- Hamlib Settings set "HAMLIBVERSION_MAJOR=4" set "HAMLIBVERSION_MINOR=7" set "HAMLIBVERSION_PATCH=0" rem -- OpenSSL (needed at runtime for some configurations) set "OPENSSLROOT=%DEVROOT%\openssl-3.0\x64" rem === END OF CONFIGURATION === set "QMAKE=%QT_BASE%\bin\qmake.exe" set "HAMLIBVERSION=%HAMLIBVERSION_MAJOR%.%HAMLIBVERSION_MINOR%.%HAMLIBVERSION_PATCH%" set "HAMLIBROOT=%DEVROOT%\hamlib-w64-%HAMLIBVERSION%" set "HAMLIBINCLUDEPATH=%HAMLIBROOT%\include" set "HAMLIBLIBPATH=%HAMLIBROOT%\lib\msvc" set "HAMLIBBINPATH=%HAMLIBROOT%\bin" set "QTKEYCHAININCLUDEPATH=%VCPKG_PACKAGES%\%VCPKG_QTKEYCHAIN_PKG%\include" set "QTKEYCHAINLIBPATH=%VCPKG_PACKAGES%\%VCPKG_QTKEYCHAIN_PKG%\lib" set "QTKEYCHAINBINPATH=%VCPKG_PACKAGES%\%VCPKG_QTKEYCHAIN_PKG%\bin" set "PTHREADINCLUDEPATH=%VCPKG_PACKAGES%\%VCPKG_PTHREAD_PKG%\include" set "PTHREADLIBPATH=%VCPKG_PACKAGES%\%VCPKG_PTHREAD_PKG%\lib" set "ZLIBINCLUDEPATH=%VCPKG_PACKAGES%\%VCPKG_ZLIB_PKG%\include" set "ZLIBLIBPATH=%VCPKG_PACKAGES%\%VCPKG_ZLIB_PKG%\lib" set "ZLIBBINPATH=%VCPKG_PACKAGES%\%VCPKG_ZLIB_PKG%\bin" set "ACTION=%~1" if /I "%ACTION%"=="" set "ACTION=all" if not exist "%PRO%" ( echo ERROR: tests project not found: "%PRO%" goto :fail ) if not exist "%BUILDROOT%" mkdir "%BUILDROOT%" pushd "%BUILDROOT%" >nul echo === Initializing MSVC environment (%VS_ARCH%) === call "%VS_VCVARS%" %VS_ARCH% if errorlevel 1 goto :fail if exist "%JOM%" ( set "MAKE=%JOM%" ) else ( set "MAKE=nmake" ) if /I "%ACTION%"=="clean" goto :action_clean if /I "%ACTION%"=="build" goto :action_build if /I "%ACTION%"=="run" goto :action_run if /I "%ACTION%"=="rebuild" goto :action_rebuild if /I "%ACTION%"=="all" goto :action_all echo Unknown action: %ACTION% echo Usage: %~nx0 [all^|build^|run^|clean^|rebuild] goto :fail :qmake echo === Running qmake (tests, release) === "%QMAKE%" "%PRO%" -spec win32-msvc ^ "CONFIG+=release" ^ "CONFIG-=debug_and_release" ^ "HAMLIBINCLUDEPATH=%HAMLIBINCLUDEPATH%" ^ "HAMLIBLIBPATH=%HAMLIBLIBPATH%" ^ "HAMLIBVERSION_MAJOR=%HAMLIBVERSION_MAJOR%" ^ "HAMLIBVERSION_MINOR=%HAMLIBVERSION_MINOR%" ^ "HAMLIBVERSION_PATCH=%HAMLIBVERSION_PATCH%" ^ "QTKEYCHAININCLUDEPATH=%QTKEYCHAININCLUDEPATH%" ^ "QTKEYCHAINLIBPATH=%QTKEYCHAINLIBPATH%" ^ "PTHREADINCLUDEPATH=%PTHREADINCLUDEPATH%" ^ "PTHREADLIBPATH=%PTHREADLIBPATH%" ^ "ZLIBINCLUDEPATH=%ZLIBINCLUDEPATH%" ^ "ZLIBLIBPATH=%ZLIBLIBPATH%" ^ "OPENSSLINCLUDEPATH=%OPENSSLROOT%/include" ^ "OPENSSLLIBPATH=%OPENSSLROOT%/lib" if errorlevel 1 exit /b 10 exit /b 0 :doBuild call :qmake if errorlevel 1 exit /b 11 echo === Building tests === "%MAKE%" if errorlevel 1 exit /b 12 exit /b 0 :doRun echo === Running tests === set "PATH=%QT_BASE%\bin;%QTKEYCHAINBINPATH%;%HAMLIBBINPATH%;%ZLIBBINPATH%;%OPENSSLROOT%\bin;%PATH%" set "FAILED=0" set "COUNT=0" for /r "%BUILDROOT%" %%F in (tst_*.exe) do ( set /a COUNT+=1 echo --- %%~nxF --- "%%F" if errorlevel 1 ( echo FAILED: %%~nxF set "FAILED=1" goto :run_done ) ) :run_done if "%COUNT%"=="0" ( echo ERROR: No test executables found under "%BUILDROOT%". exit /b 21 ) if "%FAILED%"=="1" exit /b 20 exit /b 0 :action_clean echo === Cleaning build directory === if exist "%BUILDROOT%\Makefile" ( "%MAKE%" clean ) popd >nul rmdir /S /Q "%BUILDROOT%" >nul 2>&1 endlocal exit /b 0 :action_build call :doBuild if errorlevel 1 goto :fail goto :ok :action_run call :doRun if errorlevel 1 goto :fail goto :ok :action_rebuild echo === Rebuild === if exist "%BUILDROOT%\Makefile" ( "%MAKE%" clean ) call :doBuild if errorlevel 1 goto :fail call :doRun if errorlevel 1 goto :fail goto :ok :action_all call :doBuild if errorlevel 1 goto :fail call :doRun if errorlevel 1 goto :fail goto :ok :ok popd >nul endlocal exit /b 0 :fail set "EC=%errorlevel%" if "%EC%"=="0" set "EC=1" echo. echo FAILED with errorlevel %EC% popd >nul endlocal exit /b %EC% foldynl-QLog-3252ff9/doc/000077500000000000000000000000001517334601000151305ustar00rootroot00000000000000foldynl-QLog-3252ff9/doc/UDP_Notifications.txt000066400000000000000000000000771517334601000212160ustar00rootroot00000000000000see details https://github.com/foldynl/QLog/wiki/Notifications foldynl-QLog-3252ff9/entitlements.xml000066400000000000000000000007061517334601000176230ustar00rootroot00000000000000 com.apple.security.cs.allow-unsigned-executable-memory com.apple.security.cs.disable-library-validation com.apple.security.cs.allow-jit com.apple.security.cs.disable-executable-page-protection foldynl-QLog-3252ff9/i18n/000077500000000000000000000000001517334601000151425ustar00rootroot00000000000000foldynl-QLog-3252ff9/i18n/datastrings.tri000066400000000000000000000016221517334601000202060ustar00rootroot00000000000000QT_TRANSLATE_NOOP("Data", "Aircraft Scatter"); QT_TRANSLATE_NOOP("Data", "Aurora-E"); QT_TRANSLATE_NOOP("Data", "Aurora"); QT_TRANSLATE_NOOP("Data", "Back scatter"); QT_TRANSLATE_NOOP("Data", "EchoLink"); QT_TRANSLATE_NOOP("Data", "Earth-Moon-Earth"); QT_TRANSLATE_NOOP("Data", "Sporadic E"); QT_TRANSLATE_NOOP("Data", "F2 Reflection"); QT_TRANSLATE_NOOP("Data", "Field Aligned Irregularities"); QT_TRANSLATE_NOOP("Data", "Ground Wave"); QT_TRANSLATE_NOOP("Data", "Internet-assisted"); QT_TRANSLATE_NOOP("Data", "Ionoscatter"); QT_TRANSLATE_NOOP("Data", "IRLP"); QT_TRANSLATE_NOOP("Data", "Line of Sight"); QT_TRANSLATE_NOOP("Data", "Meteor scatter"); QT_TRANSLATE_NOOP("Data", "Terrestrial or atmospheric repeater or transponder"); QT_TRANSLATE_NOOP("Data", "Rain scatter"); QT_TRANSLATE_NOOP("Data", "Satellite"); QT_TRANSLATE_NOOP("Data", "Trans-equatorial"); QT_TRANSLATE_NOOP("Data", "Tropospheric ducting"); foldynl-QLog-3252ff9/i18n/dbstrings.tri000066400000000000000000000374131517334601000176710ustar00rootroot00000000000000QT_TRANSLATE_NOOP("DBStrings", "PHONE"); QT_TRANSLATE_NOOP("DBStrings", "CW"); QT_TRANSLATE_NOOP("DBStrings", "DIGITAL"); QT_TRANSLATE_NOOP("DBStrings", "Afghanistan"); QT_TRANSLATE_NOOP("DBStrings", "Agalega & St. Brandon"); QT_TRANSLATE_NOOP("DBStrings", "Aland Islands"); QT_TRANSLATE_NOOP("DBStrings", "Alaska"); QT_TRANSLATE_NOOP("DBStrings", "Albania"); QT_TRANSLATE_NOOP("DBStrings", "Algeria"); QT_TRANSLATE_NOOP("DBStrings", "American Samoa"); QT_TRANSLATE_NOOP("DBStrings", "Amsterdam & St. Paul Is."); QT_TRANSLATE_NOOP("DBStrings", "Andaman & Nicobar Is."); QT_TRANSLATE_NOOP("DBStrings", "Andorra"); QT_TRANSLATE_NOOP("DBStrings", "Angola"); QT_TRANSLATE_NOOP("DBStrings", "Anguilla"); QT_TRANSLATE_NOOP("DBStrings", "Annobon Island"); QT_TRANSLATE_NOOP("DBStrings", "Antarctica"); QT_TRANSLATE_NOOP("DBStrings", "Antigua & Barbuda"); QT_TRANSLATE_NOOP("DBStrings", "Argentina"); QT_TRANSLATE_NOOP("DBStrings", "Armenia"); QT_TRANSLATE_NOOP("DBStrings", "Aruba"); QT_TRANSLATE_NOOP("DBStrings", "Ascension Island"); QT_TRANSLATE_NOOP("DBStrings", "Asiatic Russia"); QT_TRANSLATE_NOOP("DBStrings", "Asiatic Turkey"); QT_TRANSLATE_NOOP("DBStrings", "Austral Islands"); QT_TRANSLATE_NOOP("DBStrings", "Australia"); QT_TRANSLATE_NOOP("DBStrings", "Austria"); QT_TRANSLATE_NOOP("DBStrings", "Aves Island"); QT_TRANSLATE_NOOP("DBStrings", "Azerbaijan"); QT_TRANSLATE_NOOP("DBStrings", "Azores"); QT_TRANSLATE_NOOP("DBStrings", "Bahamas"); QT_TRANSLATE_NOOP("DBStrings", "Bahrain"); QT_TRANSLATE_NOOP("DBStrings", "Baker & Howland Islands"); QT_TRANSLATE_NOOP("DBStrings", "Balearic Islands"); QT_TRANSLATE_NOOP("DBStrings", "Banaba Island"); QT_TRANSLATE_NOOP("DBStrings", "Bangladesh"); QT_TRANSLATE_NOOP("DBStrings", "Barbados"); QT_TRANSLATE_NOOP("DBStrings", "Belarus"); QT_TRANSLATE_NOOP("DBStrings", "Belgium"); QT_TRANSLATE_NOOP("DBStrings", "Belize"); QT_TRANSLATE_NOOP("DBStrings", "Benin"); QT_TRANSLATE_NOOP("DBStrings", "Bermuda"); QT_TRANSLATE_NOOP("DBStrings", "Bhutan"); QT_TRANSLATE_NOOP("DBStrings", "Bolivia"); QT_TRANSLATE_NOOP("DBStrings", "Bonaire"); QT_TRANSLATE_NOOP("DBStrings", "Bosnia-Herzegovina"); QT_TRANSLATE_NOOP("DBStrings", "Botswana"); QT_TRANSLATE_NOOP("DBStrings", "Bouvet"); QT_TRANSLATE_NOOP("DBStrings", "Brazil"); QT_TRANSLATE_NOOP("DBStrings", "British Virgin Islands"); QT_TRANSLATE_NOOP("DBStrings", "Brunei Darussalam"); QT_TRANSLATE_NOOP("DBStrings", "Bulgaria"); QT_TRANSLATE_NOOP("DBStrings", "Burkina Faso"); QT_TRANSLATE_NOOP("DBStrings", "Burundi"); QT_TRANSLATE_NOOP("DBStrings", "Cambodia"); QT_TRANSLATE_NOOP("DBStrings", "Cameroon"); QT_TRANSLATE_NOOP("DBStrings", "Canada"); QT_TRANSLATE_NOOP("DBStrings", "Canary Islands"); QT_TRANSLATE_NOOP("DBStrings", "Cape Verde"); QT_TRANSLATE_NOOP("DBStrings", "Cayman Islands"); QT_TRANSLATE_NOOP("DBStrings", "Central African Republic"); QT_TRANSLATE_NOOP("DBStrings", "Central Kiribati"); QT_TRANSLATE_NOOP("DBStrings", "Ceuta & Melilla"); QT_TRANSLATE_NOOP("DBStrings", "Chad"); QT_TRANSLATE_NOOP("DBStrings", "Chagos Islands"); QT_TRANSLATE_NOOP("DBStrings", "Chatham Islands"); QT_TRANSLATE_NOOP("DBStrings", "Chesterfield Islands"); QT_TRANSLATE_NOOP("DBStrings", "Chile"); QT_TRANSLATE_NOOP("DBStrings", "China"); QT_TRANSLATE_NOOP("DBStrings", "Christmas Island"); QT_TRANSLATE_NOOP("DBStrings", "Clipperton Island"); QT_TRANSLATE_NOOP("DBStrings", "Cocos (Keeling) Islands"); QT_TRANSLATE_NOOP("DBStrings", "Cocos Island"); QT_TRANSLATE_NOOP("DBStrings", "Colombia"); QT_TRANSLATE_NOOP("DBStrings", "Comoros"); QT_TRANSLATE_NOOP("DBStrings", "Conway Reef"); QT_TRANSLATE_NOOP("DBStrings", "Corsica"); QT_TRANSLATE_NOOP("DBStrings", "Costa Rica"); QT_TRANSLATE_NOOP("DBStrings", "Cote d'Ivoire"); QT_TRANSLATE_NOOP("DBStrings", "Crete"); QT_TRANSLATE_NOOP("DBStrings", "Croatia"); QT_TRANSLATE_NOOP("DBStrings", "Crozet Island"); QT_TRANSLATE_NOOP("DBStrings", "Cuba"); QT_TRANSLATE_NOOP("DBStrings", "Curacao"); QT_TRANSLATE_NOOP("DBStrings", "Cyprus"); QT_TRANSLATE_NOOP("DBStrings", "Czech Republic"); QT_TRANSLATE_NOOP("DBStrings", "DPR of Korea"); QT_TRANSLATE_NOOP("DBStrings", "Dem. Rep. of the Congo"); QT_TRANSLATE_NOOP("DBStrings", "Denmark"); QT_TRANSLATE_NOOP("DBStrings", "Desecheo Island"); QT_TRANSLATE_NOOP("DBStrings", "Djibouti"); QT_TRANSLATE_NOOP("DBStrings", "Dodecanese"); QT_TRANSLATE_NOOP("DBStrings", "Dominica"); QT_TRANSLATE_NOOP("DBStrings", "Dominican Republic"); QT_TRANSLATE_NOOP("DBStrings", "Ducie Island"); QT_TRANSLATE_NOOP("DBStrings", "East Malaysia"); QT_TRANSLATE_NOOP("DBStrings", "Easter Island"); QT_TRANSLATE_NOOP("DBStrings", "Eastern Kiribati"); QT_TRANSLATE_NOOP("DBStrings", "Ecuador"); QT_TRANSLATE_NOOP("DBStrings", "Egypt"); QT_TRANSLATE_NOOP("DBStrings", "El Salvador"); QT_TRANSLATE_NOOP("DBStrings", "England"); QT_TRANSLATE_NOOP("DBStrings", "Equatorial Guinea"); QT_TRANSLATE_NOOP("DBStrings", "Eritrea"); QT_TRANSLATE_NOOP("DBStrings", "Estonia"); QT_TRANSLATE_NOOP("DBStrings", "Ethiopia"); QT_TRANSLATE_NOOP("DBStrings", "European Russia"); QT_TRANSLATE_NOOP("DBStrings", "Falkland Islands"); QT_TRANSLATE_NOOP("DBStrings", "Faroe Islands"); QT_TRANSLATE_NOOP("DBStrings", "Fed. Rep. of Germany"); QT_TRANSLATE_NOOP("DBStrings", "Fernando de Noronha"); QT_TRANSLATE_NOOP("DBStrings", "Fiji"); QT_TRANSLATE_NOOP("DBStrings", "Finland"); QT_TRANSLATE_NOOP("DBStrings", "France"); QT_TRANSLATE_NOOP("DBStrings", "Franz Josef Land"); QT_TRANSLATE_NOOP("DBStrings", "French Guiana"); QT_TRANSLATE_NOOP("DBStrings", "French Polynesia"); QT_TRANSLATE_NOOP("DBStrings", "Gabon"); QT_TRANSLATE_NOOP("DBStrings", "Galapagos Islands"); QT_TRANSLATE_NOOP("DBStrings", "Georgia"); QT_TRANSLATE_NOOP("DBStrings", "Ghana"); QT_TRANSLATE_NOOP("DBStrings", "Gibraltar"); QT_TRANSLATE_NOOP("DBStrings", "Glorioso Islands"); QT_TRANSLATE_NOOP("DBStrings", "Greece"); QT_TRANSLATE_NOOP("DBStrings", "Greenland"); QT_TRANSLATE_NOOP("DBStrings", "Grenada"); QT_TRANSLATE_NOOP("DBStrings", "Guadeloupe"); QT_TRANSLATE_NOOP("DBStrings", "Guam"); QT_TRANSLATE_NOOP("DBStrings", "Guantanamo Bay"); QT_TRANSLATE_NOOP("DBStrings", "Guatemala"); QT_TRANSLATE_NOOP("DBStrings", "Guernsey"); QT_TRANSLATE_NOOP("DBStrings", "Guinea"); QT_TRANSLATE_NOOP("DBStrings", "Guinea-Bissau"); QT_TRANSLATE_NOOP("DBStrings", "Guyana"); QT_TRANSLATE_NOOP("DBStrings", "Haiti"); QT_TRANSLATE_NOOP("DBStrings", "Hawaii"); QT_TRANSLATE_NOOP("DBStrings", "Heard Island"); QT_TRANSLATE_NOOP("DBStrings", "Honduras"); QT_TRANSLATE_NOOP("DBStrings", "Hong Kong"); QT_TRANSLATE_NOOP("DBStrings", "Hungary"); QT_TRANSLATE_NOOP("DBStrings", "ITU HQ"); QT_TRANSLATE_NOOP("DBStrings", "Iceland"); QT_TRANSLATE_NOOP("DBStrings", "India"); QT_TRANSLATE_NOOP("DBStrings", "Indonesia"); QT_TRANSLATE_NOOP("DBStrings", "Iran"); QT_TRANSLATE_NOOP("DBStrings", "Iraq"); QT_TRANSLATE_NOOP("DBStrings", "Ireland"); QT_TRANSLATE_NOOP("DBStrings", "Isle of Man"); QT_TRANSLATE_NOOP("DBStrings", "Israel"); QT_TRANSLATE_NOOP("DBStrings", "Italy"); QT_TRANSLATE_NOOP("DBStrings", "Jamaica"); QT_TRANSLATE_NOOP("DBStrings", "Jan Mayen"); QT_TRANSLATE_NOOP("DBStrings", "Japan"); QT_TRANSLATE_NOOP("DBStrings", "Jersey"); QT_TRANSLATE_NOOP("DBStrings", "Johnston Island"); QT_TRANSLATE_NOOP("DBStrings", "Jordan"); QT_TRANSLATE_NOOP("DBStrings", "Juan Fernandez Islands"); QT_TRANSLATE_NOOP("DBStrings", "Juan de Nova & Europa"); QT_TRANSLATE_NOOP("DBStrings", "Kaliningrad"); QT_TRANSLATE_NOOP("DBStrings", "Kazakhstan"); QT_TRANSLATE_NOOP("DBStrings", "Kenya"); QT_TRANSLATE_NOOP("DBStrings", "Kerguelen Islands"); QT_TRANSLATE_NOOP("DBStrings", "Kermadec Islands"); QT_TRANSLATE_NOOP("DBStrings", "Kingdom of Eswatini"); QT_TRANSLATE_NOOP("DBStrings", "Kure Island"); QT_TRANSLATE_NOOP("DBStrings", "Kuwait"); QT_TRANSLATE_NOOP("DBStrings", "Kyrgyzstan"); QT_TRANSLATE_NOOP("DBStrings", "Lakshadweep Islands"); QT_TRANSLATE_NOOP("DBStrings", "Laos"); QT_TRANSLATE_NOOP("DBStrings", "Latvia"); QT_TRANSLATE_NOOP("DBStrings", "Lebanon"); QT_TRANSLATE_NOOP("DBStrings", "Lesotho"); QT_TRANSLATE_NOOP("DBStrings", "Liberia"); QT_TRANSLATE_NOOP("DBStrings", "Libya"); QT_TRANSLATE_NOOP("DBStrings", "Liechtenstein"); QT_TRANSLATE_NOOP("DBStrings", "Lithuania"); QT_TRANSLATE_NOOP("DBStrings", "Lord Howe Island"); QT_TRANSLATE_NOOP("DBStrings", "Luxembourg"); QT_TRANSLATE_NOOP("DBStrings", "Macao"); QT_TRANSLATE_NOOP("DBStrings", "Macquarie Island"); QT_TRANSLATE_NOOP("DBStrings", "Madagascar"); QT_TRANSLATE_NOOP("DBStrings", "Madeira Islands"); QT_TRANSLATE_NOOP("DBStrings", "Malawi"); QT_TRANSLATE_NOOP("DBStrings", "Maldives"); QT_TRANSLATE_NOOP("DBStrings", "Mali"); QT_TRANSLATE_NOOP("DBStrings", "Malpelo Island"); QT_TRANSLATE_NOOP("DBStrings", "Malta"); QT_TRANSLATE_NOOP("DBStrings", "Mariana Islands"); QT_TRANSLATE_NOOP("DBStrings", "Market Reef"); QT_TRANSLATE_NOOP("DBStrings", "Marquesas Islands"); QT_TRANSLATE_NOOP("DBStrings", "Marshall Islands"); QT_TRANSLATE_NOOP("DBStrings", "Martinique"); QT_TRANSLATE_NOOP("DBStrings", "Mauritania"); QT_TRANSLATE_NOOP("DBStrings", "Mauritius"); QT_TRANSLATE_NOOP("DBStrings", "Mayotte"); QT_TRANSLATE_NOOP("DBStrings", "Mellish Reef"); QT_TRANSLATE_NOOP("DBStrings", "Mexico"); QT_TRANSLATE_NOOP("DBStrings", "Micronesia"); QT_TRANSLATE_NOOP("DBStrings", "Midway Island"); QT_TRANSLATE_NOOP("DBStrings", "Minami Torishima"); QT_TRANSLATE_NOOP("DBStrings", "Moldova"); QT_TRANSLATE_NOOP("DBStrings", "Monaco"); QT_TRANSLATE_NOOP("DBStrings", "Mongolia"); QT_TRANSLATE_NOOP("DBStrings", "Montenegro"); QT_TRANSLATE_NOOP("DBStrings", "Montserrat"); QT_TRANSLATE_NOOP("DBStrings", "Morocco"); QT_TRANSLATE_NOOP("DBStrings", "Mount Athos"); QT_TRANSLATE_NOOP("DBStrings", "Mozambique"); QT_TRANSLATE_NOOP("DBStrings", "Myanmar"); QT_TRANSLATE_NOOP("DBStrings", "N.Z. Subantarctic Is."); QT_TRANSLATE_NOOP("DBStrings", "Namibia"); QT_TRANSLATE_NOOP("DBStrings", "Nauru"); QT_TRANSLATE_NOOP("DBStrings", "Navassa Island"); QT_TRANSLATE_NOOP("DBStrings", "Nepal"); QT_TRANSLATE_NOOP("DBStrings", "Netherlands"); QT_TRANSLATE_NOOP("DBStrings", "New Caledonia"); QT_TRANSLATE_NOOP("DBStrings", "New Zealand"); QT_TRANSLATE_NOOP("DBStrings", "Nicaragua"); QT_TRANSLATE_NOOP("DBStrings", "Niger"); QT_TRANSLATE_NOOP("DBStrings", "Nigeria"); QT_TRANSLATE_NOOP("DBStrings", "Niue"); QT_TRANSLATE_NOOP("DBStrings", "Norfolk Island"); QT_TRANSLATE_NOOP("DBStrings", "North Cook Islands"); QT_TRANSLATE_NOOP("DBStrings", "North Macedonia"); QT_TRANSLATE_NOOP("DBStrings", "Northern Ireland"); QT_TRANSLATE_NOOP("DBStrings", "Norway"); QT_TRANSLATE_NOOP("DBStrings", "Ogasawara"); QT_TRANSLATE_NOOP("DBStrings", "Oman"); QT_TRANSLATE_NOOP("DBStrings", "Pakistan"); QT_TRANSLATE_NOOP("DBStrings", "Palau"); QT_TRANSLATE_NOOP("DBStrings", "Palestine"); QT_TRANSLATE_NOOP("DBStrings", "Palmyra & Jarvis Islands"); QT_TRANSLATE_NOOP("DBStrings", "Panama"); QT_TRANSLATE_NOOP("DBStrings", "Papua New Guinea"); QT_TRANSLATE_NOOP("DBStrings", "Paraguay"); QT_TRANSLATE_NOOP("DBStrings", "Peru"); QT_TRANSLATE_NOOP("DBStrings", "Peter 1 Island"); QT_TRANSLATE_NOOP("DBStrings", "Philippines"); QT_TRANSLATE_NOOP("DBStrings", "Pitcairn Island"); QT_TRANSLATE_NOOP("DBStrings", "Poland"); QT_TRANSLATE_NOOP("DBStrings", "Portugal"); QT_TRANSLATE_NOOP("DBStrings", "Pr. Edward & Marion Is."); QT_TRANSLATE_NOOP("DBStrings", "Pratas Island"); QT_TRANSLATE_NOOP("DBStrings", "Puerto Rico"); QT_TRANSLATE_NOOP("DBStrings", "Qatar"); QT_TRANSLATE_NOOP("DBStrings", "Republic of Korea"); QT_TRANSLATE_NOOP("DBStrings", "Republic of Kosovo"); QT_TRANSLATE_NOOP("DBStrings", "Republic of South Sudan"); QT_TRANSLATE_NOOP("DBStrings", "Republic of the Congo"); QT_TRANSLATE_NOOP("DBStrings", "Reunion Island"); QT_TRANSLATE_NOOP("DBStrings", "Revillagigedo"); QT_TRANSLATE_NOOP("DBStrings", "Rodriguez Island"); QT_TRANSLATE_NOOP("DBStrings", "Romania"); QT_TRANSLATE_NOOP("DBStrings", "Rotuma Island"); QT_TRANSLATE_NOOP("DBStrings", "Rwanda"); QT_TRANSLATE_NOOP("DBStrings", "Saba & St. Eustatius"); QT_TRANSLATE_NOOP("DBStrings", "Sable Island"); QT_TRANSLATE_NOOP("DBStrings", "Samoa"); QT_TRANSLATE_NOOP("DBStrings", "San Andres & Providencia"); QT_TRANSLATE_NOOP("DBStrings", "San Felix & San Ambrosio"); QT_TRANSLATE_NOOP("DBStrings", "San Marino"); QT_TRANSLATE_NOOP("DBStrings", "Sao Tome & Principe"); QT_TRANSLATE_NOOP("DBStrings", "Sardinia"); QT_TRANSLATE_NOOP("DBStrings", "Saudi Arabia"); QT_TRANSLATE_NOOP("DBStrings", "Scarborough Reef"); QT_TRANSLATE_NOOP("DBStrings", "Scotland"); QT_TRANSLATE_NOOP("DBStrings", "Senegal"); QT_TRANSLATE_NOOP("DBStrings", "Serbia"); QT_TRANSLATE_NOOP("DBStrings", "Seychelles"); QT_TRANSLATE_NOOP("DBStrings", "Sierra Leone"); QT_TRANSLATE_NOOP("DBStrings", "Singapore"); QT_TRANSLATE_NOOP("DBStrings", "Sint Maarten"); QT_TRANSLATE_NOOP("DBStrings", "Slovak Republic"); QT_TRANSLATE_NOOP("DBStrings", "Slovenia"); QT_TRANSLATE_NOOP("DBStrings", "Solomon Islands"); QT_TRANSLATE_NOOP("DBStrings", "Somalia"); QT_TRANSLATE_NOOP("DBStrings", "South Africa"); QT_TRANSLATE_NOOP("DBStrings", "South Cook Islands"); QT_TRANSLATE_NOOP("DBStrings", "South Georgia Island"); QT_TRANSLATE_NOOP("DBStrings", "South Orkney Islands"); QT_TRANSLATE_NOOP("DBStrings", "South Sandwich Islands"); QT_TRANSLATE_NOOP("DBStrings", "South Shetland Islands"); QT_TRANSLATE_NOOP("DBStrings", "Sov Mil Order of Malta"); QT_TRANSLATE_NOOP("DBStrings", "Spain"); QT_TRANSLATE_NOOP("DBStrings", "Spratly Islands"); QT_TRANSLATE_NOOP("DBStrings", "Sri Lanka"); QT_TRANSLATE_NOOP("DBStrings", "St. Barthelemy"); QT_TRANSLATE_NOOP("DBStrings", "St. Helena"); QT_TRANSLATE_NOOP("DBStrings", "St. Kitts & Nevis"); QT_TRANSLATE_NOOP("DBStrings", "St. Lucia"); QT_TRANSLATE_NOOP("DBStrings", "St. Martin"); QT_TRANSLATE_NOOP("DBStrings", "St. Paul Island"); QT_TRANSLATE_NOOP("DBStrings", "St. Peter & St. Paul"); QT_TRANSLATE_NOOP("DBStrings", "St. Pierre & Miquelon"); QT_TRANSLATE_NOOP("DBStrings", "St. Vincent"); QT_TRANSLATE_NOOP("DBStrings", "Sudan"); QT_TRANSLATE_NOOP("DBStrings", "Suriname"); QT_TRANSLATE_NOOP("DBStrings", "Svalbard"); QT_TRANSLATE_NOOP("DBStrings", "Swains Island"); QT_TRANSLATE_NOOP("DBStrings", "Sweden"); QT_TRANSLATE_NOOP("DBStrings", "Switzerland"); QT_TRANSLATE_NOOP("DBStrings", "Syria"); QT_TRANSLATE_NOOP("DBStrings", "Taiwan"); QT_TRANSLATE_NOOP("DBStrings", "Tajikistan"); QT_TRANSLATE_NOOP("DBStrings", "Tanzania"); QT_TRANSLATE_NOOP("DBStrings", "Temotu Province"); QT_TRANSLATE_NOOP("DBStrings", "Thailand"); QT_TRANSLATE_NOOP("DBStrings", "The Gambia"); QT_TRANSLATE_NOOP("DBStrings", "Timor - Leste"); QT_TRANSLATE_NOOP("DBStrings", "Togo"); QT_TRANSLATE_NOOP("DBStrings", "Tokelau Islands"); QT_TRANSLATE_NOOP("DBStrings", "Tonga"); QT_TRANSLATE_NOOP("DBStrings", "Trindade & Martim Vaz"); QT_TRANSLATE_NOOP("DBStrings", "Trinidad & Tobago"); QT_TRANSLATE_NOOP("DBStrings", "Tristan da Cunha & Gough Islands"); QT_TRANSLATE_NOOP("DBStrings", "Tromelin Island"); QT_TRANSLATE_NOOP("DBStrings", "Tunisia"); QT_TRANSLATE_NOOP("DBStrings", "Turkmenistan"); QT_TRANSLATE_NOOP("DBStrings", "Turks & Caicos Islands"); QT_TRANSLATE_NOOP("DBStrings", "Tuvalu"); QT_TRANSLATE_NOOP("DBStrings", "UK Base Areas on Cyprus"); QT_TRANSLATE_NOOP("DBStrings", "US Virgin Islands"); QT_TRANSLATE_NOOP("DBStrings", "Uganda"); QT_TRANSLATE_NOOP("DBStrings", "Ukraine"); QT_TRANSLATE_NOOP("DBStrings", "United Arab Emirates"); QT_TRANSLATE_NOOP("DBStrings", "United Nations HQ"); QT_TRANSLATE_NOOP("DBStrings", "United States"); QT_TRANSLATE_NOOP("DBStrings", "Uruguay"); QT_TRANSLATE_NOOP("DBStrings", "Uzbekistan"); QT_TRANSLATE_NOOP("DBStrings", "Vanuatu"); QT_TRANSLATE_NOOP("DBStrings", "Vatican City"); QT_TRANSLATE_NOOP("DBStrings", "Venezuela"); QT_TRANSLATE_NOOP("DBStrings", "Vietnam"); QT_TRANSLATE_NOOP("DBStrings", "Wake Island"); QT_TRANSLATE_NOOP("DBStrings", "Wales"); QT_TRANSLATE_NOOP("DBStrings", "Wallis & Futuna Islands"); QT_TRANSLATE_NOOP("DBStrings", "West Malaysia"); QT_TRANSLATE_NOOP("DBStrings", "Western Kiribati"); QT_TRANSLATE_NOOP("DBStrings", "Western Sahara"); QT_TRANSLATE_NOOP("DBStrings", "Willis Island"); QT_TRANSLATE_NOOP("DBStrings", "Yemen"); QT_TRANSLATE_NOOP("DBStrings", "Zambia"); QT_TRANSLATE_NOOP("DBStrings", "Zimbabwe"); foldynl-QLog-3252ff9/i18n/i18n.qrc000066400000000000000000000005011517334601000164240ustar00rootroot00000000000000 qlog_de.qm qlog_cs.qm qlog_zh_CN.qm datastrings.tri qlog_es.qm qlog_fr.qm qlog_it.qm foldynl-QLog-3252ff9/i18n/qlog_cs.qm000066400000000000000000007417771517334601000171570ustar00rootroot00000000000000HZx6!3(OOOOOT<qqd?xDI < ;P"E&e'C%*0;mEE%EIGd>xGKGbG#Gd GGGyGnH, H,%H,JH,_EH,>*HYLHjHj{'HjH)H&nH0I;I;=I;mI@IK]LcLMpMMANN"'N NNAQ14Q1uQ1?Q1Q RSg[<Sg -SSE:T^BTmTrUVE]Vp]V VVWBWWdgWedWWWWX2mPXC,X_OXX OXX܌X3XBXYGcY.%YZlZl3 ZTZ6LZH$ZHR[S(|[c([j([[H[a \X(\]l]]I7_T__`e^ovQ/Qb)QQb\M0\Mou%-|cmE0W0×{002/3DDDzDnhD>Xxf`}V}tr,{s &s/sRtTyfve SEx/Ez$&(dK\)̾ %/%L֍,֍3֍uo֍;֍[֍n}!43}ZB7>1Ve~"L(c4"444a44a464 4Bl4P8)8 YEE"E=ELE (EE+EE ;EBESH5H5dH5H5H5DPTT2TTpTTCVEBVE׹VEVETc~hf fK h2h33h3hcFhluv;xx2xcxxcx{{#{}sf&_ IDaR.>q>TRg&g`/ 55LC5]5d5esss6x˦˦)$˦?˦$˦˦8@8!IeyTs|)Q|D|||||:W|I|b1Kdc p. 8>u r#' r܂hբD٢A I) %nȣ'(|)5B?)5)57*b*%I*0{+.B+. +c+..L/Z 05?405,<607Pv7pvh8һ80M:d:dnH:$:$I<~y@̇6B6qFMFF-GđHw9HzFHH{HHiHHH؄#I(KI(KI(KI(K~I(KI(KKI%IAItJ(|J+aJ+,J+1J+mJ+eJ+hJ5ȚJ;ZI=J;NJJJY JYJYbJYJY KI|KtL7LGSL|LbvwLbNMLkMnMYMy^uMANQ?NOPAPJP~P9QRTCRxmRRZSISIPS[ SySS>tS#T[hTTZNTZ zTZTTZ TZ TeC TNZTT|TQT,T%T8Uj^UGVV%VVVVRVVYVEVVE%VE&#VE(VE WTfWi`jWmWmWUWT]:XRwXRX۩XX0J6X1(X1X1JcX2YX2X2JX3X3JX4+Yf1YiA YiB Yl^Ynj_YQY YqYetZ[Zg$ZgÁZk5Zs'~ZvZZeZzZZ)NZ~[S[@[dʒ\qN\\u\\}]Ш]%7]q^^9^A_þ^eѕai(K,iuVjh2jh3hl[jmc>WtE z>}w53$Va$nS$%aAT$+slsms Q(vY5}>ȄtC6kdH>JIJVYJZ%\%AG%c%l%>EjJV$aZ^$n7;˹.Ns 2sg""Lls# 7W n$43ZW`Oyn1ZW1QJhW?S!`7WUtTpt-;M8ShK q . JB&ArN<3Ug&2y#*½23354G.7+8-~28#;{GQIzJ#*ZLoRD VC WZ[M/w\Tu:_ )Z`Ap qƹqU<uup vr-~w &W6Msiy\&# h<#5 'L4"`ߨyy4'f7oԙE1ۋs#uP6zPU$q`r`CC2X06b6@cWRv8NW tl CN>J;z^3AcAo Ul[U v%&H7' *_+y:kr<G]K!^1K~T7RA AV>XG.X"E]Y"AYu-\H\hSK]_s_̆٥g6msnQsnzsn)XsnUtN@t4u^[uVuEuc5wô[]҉`}9R6JT'43"i^OŃQ JR5>s\?cPWNcS0n  3j xΖv}3J$N/=1R,+5Dـ^4<_nnH>Wȡ [Va6 0l{s DZD0~^~"*M" $=)d`*bG?,C-h6S9Hp:1\:2 7:sʗbZʗKO)tt ti`OӾJa;0+݀Na5S3UyZSM hJ^YSI9[|0n_%,2~{~~"|USoD1@ ' Jxx$./*̌/.Uv3$A@8';?#h@B+eB[הFyGw OoVQ\#GT@VV^YG {\]P^ C_bydS'fTAriYil|m]p-qRvu uvv}}}8}e} }}}FPl77PDW]ɳɳi!(*.Ч0y]1|X3U~h(.9/aH2;k'6GII&I?I2IMfnFn&5nJ:njnUno  ~DxŹ~ŹŹ  >Nq0,g,Y, ,5]RM]61%WU2ylR##>=>xHe!ktL#?@`\˱> fI*).)) M)hIŰȟ^u̖e̖e ̖e̖egtviGv v³U:UXQm2)~289fm.s\ѽ4j"Ӗɘ֓Wi֓WO?`Lw؄D3(``&>C&F軕Ct[qX4VCAAĊr?S6ȡeVP3tvkvM   Zp <~[~6[b!nѱ&{((R\F)*%,-3$A45 w68( 8GM<8"<8<8 <8<8h<8m< <z=O==`?0\sAW)BE%[E FGI!J*_KHjKHj=rKNAKN?.KWb/KXPKXKX?KXDM9̷U4iVVx>Y\\\4`ŠbKs|Uc>AczPMeB)eYg45(hhhhH1hjy&jjUsl6mϒnsYtv(DivZQUx^x{T|Lm}`6{#&Q#MrRK]<bPM˴˴˴'^F6FpF$FbFe0F @FFv]#jcH~"#DL) a^N\_{U/<$ jv=IRJc|!2N%N%£O9} ~mit$ *PYuSsSS VSh5/4q4v4u4~ 4@B4f}Dj,>H,s?s#@HZEAC5Swͨ~\9ƨ+5tD5t=; N͜N>5%#18Mu#摴摴*<摴#摴x摴摴摴D摴k Mi8ҋ G 3sc9NF0xё+ђfq*?y3T{  b!g4#$+q)RF*x$-S.0 F0D1/1Q1>F3^.!61 3;\5kc#nc's 0T5k 2GN`pk #7*bF-/ev<3$B38493a'> R?@y@y*yABL?IK)DKLLTMW΁NN.dQ9R"TVXPY39[b\u(o\uJ\uS~\u@]@8]wZ\awNbZbըWi(sJiE.BiE8iECi"s/>&u+)zFQ{ι|?s|=$#.88uPJIX4dyZ(0Io3yC>C6Rf)T_4PsT? ЂG)x<ݮ"FuW=1DE1,y切-切C"44^~9ywL A v25\Z2V^dM jg~i>2h~YjiHHB %@ǟ&9S(((B)%ö+ P,$-ȱ/=j/E0Eʿ0s0i2)3N3N3N3N 3N3N~3Nd3NL3Nb3Nk4Y5Y9^a :l<V>O@BcA)Au;AMF\qKiK KgLRNk*IOlWWPtgX  ZZhZn1[a}#`F`C@`QesFeue$eݽreݽ`fSSfSZpgC rhPw4hPzTkQm6)6mZcpdpw#z;N ztc%zә{~Dud Mpe8z*ř+N(+N2B+N[+NC+NS?Xc| кp2ae)e{*16*1*1*1m*1fO,ı9UQ/33|#TTBj<,AKEݣl< .JO<z{WR~?kYqTTxXZ grM%t.ttib‰SŶr}s]fǒ)KBʸdП|ɰzZY4mUh՛j[IۗV;8:yQ3=#4;S>#SR,ot)UBd0$?f x  222 \1 Lba  d d^A dR dn p ", (9E ([ )W* ))] *JO[ +>F -4IX /)Y /J 1h\ 6O% 8k :$o =&Q @ A: H0 IEh I! I2Q I2oP I26 I22 I2 I2 I2( I2C JhT Jb Mg Mg< QB8 SI T U Z \ ]  ] _f- _, `` aQ c D cNɕ c dw esr e e5 e g i i>X6 j2 { j2ݡ j2C5 rS =p A IO *A h. wr? } JMA ^LO  :< x S>  \ 4 i i S b 3q 3ږ  F G EH щ:^ ; =D 0E  ^ J 'Y ' X V :R Ľ, CN C5 ˰ 7 ̡^ ' 1' u W Jrʐ  8 E 嗓 v  3  O~ ˿ ! qR 9K@ @ Fr  D PI qa e L $8 % s '* (X (2 , ;w ,6 .a 0- 1)13 43 6) 80N 80O :R# ;s ;N =R0 = =!& > >p >m} ?? > AQiу B5is G: J.u J.h J, P U Tn U% U XE. Zr# Z Z ]5D % a-e a4 b c c¤ d<= d<Js d<| d< d<N d<b di# dU d) e U eKN eKr eK eSU/ ee eIu e eb g,5b g7 iu" i k#f l[ l[ l[~I l[ l[ l o; o= pG r=TK v vy vL .4 ?$m ٴ? } S #{ h h3  Z`7 b 4X" 4 #w  U  )~ ϴN  >pq ya  }A J1+ F3 E C C" C C G T *  ' 8N 8 Őu M9O LJ\ y? ȗ. v' ~ ~b ʀsK' ʀsMB „} „W vE v%f v 7iW n 䓳2 Ul u uK 5` C F  f  瘟e b1J N; 9B\# 7] < <Y? <ح < 0%X u{ u$ w Ɣ= ƔD ! vH v Rh D 8c 8 n #G ]v nqu X5" c I<  TAP !L$: !Ok " )RC )AB ,32\ , . .6R 6bc0 8l ; B3 GC] I!X J N:D P.e` R? RR  Te2 TO} UoP Z ^ǥkK _u#ޫ d f( fF * h7+ l$ mpD q 5 r  uD>) ~`$U` C"  +$ +  $"r 5 TK .Q T 4/ Xa @d! @d y  Yo d {" PuM Pua Pu Put Pu` Pu. PuOa PucC Pule Z ] Δ^ * KNE a>Y X Õ3 Õ` B j 5TLq J b ]); e. ۿ @ <~  } KG ߙ l8 u c >E g+ k y E9a $ . 'K  x 5# 5#= ew ?   > " KuN #7 $uU %zV 'Kf ( )2 ) w *9t +3 -aO 1je 13 6t 7@ 9$ ;{KD ; >Pg ? @_SQ3 B9U D: D$ D'c G Gu5 GaU H IH^ש J% K{I$ N(b Pzy P*z4 RV RV` S# S,d S TC" W X YrCf Y [, [ţ@ \-7e ^| d!J gL6 iX j wv wxa w{ { |; h |B %q $X ϒ ]  :O F ÒB q ) ) ) ) )! C$ C J  `   h @n @ @ @i7 $ $Q $ $i i*M 8 # r u? [' [' [(, d C E - Vd4 sb s! dM d d d ƴ 3  ajWE -P p P <#F9 = /e S>  ~ ~d) .? s2 U1~ q{Q -6 5u{ 05 D!7  0 _ O*  ( %  >  tP g &fCٹ ) *5 / f /ki 0i 0j> 0Elk 0El 21) ;3MQ @d Bv KNܴ U U< WgY W+! W& \"[ \p _ _*G5 ar= cXp iFCJ m4YN mY s~ w0>5 w0>]0 5o P Pd Ps[ PwQ  X 8o a `4g tRz   *  + +b +? l oh = zA PS*Y Ps ) ^ K S4S  Œ4 <xk ȳ0: ) c ƍ  N %W H ri {[ } y> Y2 4fCq\^_yq3  @ ~ nSxP%kQ5RQRRSTW`yc zc$d 3wh,hOj hKiش/ iش9iش?,iشE/j=p.:t#dD]onH~IZېG)_d`}=mţj,r#7}^!6*4SD GK9{i=ߌ|(:+&E# DJ[%S4PqG L   [W. [W9 [WC n/ n~!] ;#jP%2P% P%>P%C0s0!a34!aj!>#s$r%&$",*}=w,w1a2  2 33A3R36$%6 ?m(@oE5zE`EYlHYxH}QIdLs=P>PYR]-1^VcIcI#iYV i^iT<ji?.EU} ΢D6-#ɒ%lHD_s8N0e5 (WN,d U3?snih~UeGrPU0&OOQϘ#Dǎuqֻ4\p־]Q"Chshj$p) x]A]@D!"Dit(Editor AktivitActivity EditorActivityEditorJmno aktivity Activity NameActivityEditor AntnaAntennaActivityEditorDostupn poleAvailable FieldsActivityEditorTZmnit poYad. PYesunout vybran pole dolu*Change the order. Move selected field downActivityEditorXZmnit poYad. PYesunout vybran pole nahoru(Change the order. Move selected field upActivityEditorVymazatClearActivityEditorSloupec AColumn AActivityEditorSloupec BColumn BActivityEditorSloupec CColumn CActivityEditorPYipojitConnectActivityEditor(Automaticky pYipojitConnect automaticallyActivityEditorPoleFieldsActivityEditorNPokud nen aktivovn, profil se nezmn)If unchecked, the profile does not changeActivityEditorRozlo~enLayoutActivityEditorPSeznam pol v prvnm sloupci detailu QSO-List of fields in the first QSO Detail ColumnActivityEditor4Seznam pol na prvn Ydce(List of fields in the first variable rowActivityEditorRSeznam pol ve druhm sloupci detailu QSO.List of fields in the second QSO Detail ColumnActivityEditor4Seznam pol na druh Ydce)List of fields in the second variable rowActivityEditorRSeznam pol ve tYetm sloupci detailu QSO-List of fields in the third QSO Detail ColumnActivityEditorHSeznam pol, kter mohou bt pou~itaList of fields that can be usedActivityEditorxPYesunout vybran pole ze seznamu dostupnch pol na Ydek A@Move selected fields from the Available Fields List to the Row AActivityEditorxPYesunout vybran pole ze seznamu dostupnch pol na Ydek B@Move selected fields from the Available Fields List to the Row BActivityEditor"Nesm bt przdnMust not be emptyActivityEditor&Sloupce QSO DetailuNew QSO Detail ColumnsActivityEditorXdky QSO New QSO RowsActivityEditorProfilyProfilesActivityEditor@Odstranit vybran pole z Ydku A$Remove selected field from the Row AActivityEditor@Odstranit vybran pole z Ydku B$Remove selected field from the Row BActivityEditorRigRigActivityEditorRottorRotatorActivityEditorXdka ARow AActivityEditorXdka BRow BActivityEditorUlo~enoSavedActivityEditorStaniceStationActivityEditorNeulo~enoUnsavedActivityEditorHodnotyValuesActivityEditor UspoYdn oken:Window Arrangement:ActivityEditor.*.*AlertRuleDetail AfrikaAfricaAlertRuleDetailDetail PravidlaAlert Rule DetailAlertRuleDetailVaeAllAlertRuleDetailAntarktida AntarcticaAlertRuleDetailAsieAsiaAlertRuleDetail PsmaBandsAlertRuleDetailCQZCQZAlertRuleDetailCWCWAlertRuleDetailPotvrzeno ConfirmedAlertRuleDetailKontinent ContinentAlertRuleDetailZemCountryAlertRuleDetailDXDXAlertRuleDetailDX Zna ka DX CallsignAlertRuleDetailDX Cluster DX ClusterAlertRuleDetailDigiDigitalAlertRuleDetailAktivnEnabledAlertRuleDetail EvropaEuropeAlertRuleDetailFTx (FT8/FT4) FTx (FT8/FT4)AlertRuleDetailIOTAIOTAAlertRuleDetailITUITUAlertRuleDetailStatus v logu Log StatusAlertRuleDetail lenMemberAlertRuleDetailDruhy provozuModesAlertRuleDetail"Nesm bt przdnMust not be emptyAlertRuleDetailNov psmoNew BandAlertRuleDetailNov zem New EntityAlertRuleDetail"Nov druh provozuNew ModeAlertRuleDetailNov slotNew SlotAlertRuleDetail8Nen aktvn ~dn Club ListNo Club List is enabledAlertRuleDetailSevern Amerika North AmericaAlertRuleDetailOcenieOceaniaAlertRuleDetailPOTAPOTAAlertRuleDetailFnePhoneAlertRuleDetailJmno pravidla Rule NameAlertRuleDetailSOTASOTAAlertRuleDetail ZdrojeSourcesAlertRuleDetailJi~n Amerika South AmericaAlertRuleDetailActivitySpecial ProgramsAlertRuleDetailSpot komentY Spot CommentAlertRuleDetailSpotterSpotterAlertRuleDetailPPou~ijte regulrn vraz ve formatu Perl Use Perl-like regular expressionAlertRuleDetail WSJTXWSJTXAlertRuleDetailWWFFWWFFAlertRuleDetailPracovnoWorkedAlertRuleDetail PYidatAddAlertSettingDialogUpozornn Alerts RulesAlertSettingDialogUpravitEditAlertSettingDialog JmnoNameAlertSettingDialogVymazatRemoveAlertSettingDialogPravidlaRulesAlertSettingDialogStavStateAlertSettingDialog Zna kaCallsignAlertTableModelFrekvence FrequencyAlertTableModel Zprva Last CommentAlertTableModelPosledn Last UpdateAlertTableModel lenMemberAlertTableModelDruh provozuModeAlertTableModelPravidlo Rule NameAlertTableModelAktualizacUpdatedAlertTableModel min min(s) AlertWidgetUpozornnAlerts AlertWidgetVymazatClear AlertWidgetVymazat staraClear older than AlertWidget(Zobrazen sloupco...Column Visibility... AlertWidget Upravit pravidla Edit Rules AlertWidgetNemazatNever AlertWidget AfrikaAfrica AwardsDialogAntarktida Antarctica AwardsDialogAsieAsia AwardsDialog DiplomAward AwardsDialogDiplomyAwards AwardsDialogCWCW AwardsDialogPotvrzeno Confirmed by AwardsDialogSmaznoDELETED AwardsDialogDXCCDXCC AwardsDialogDigiDigi AwardsDialog EvropaEurope AwardsDialog Loktor %1 znakoGridsquare %1-Chars AwardsDialogLoktor 2 znakyGridsquare 2-Chars AwardsDialogLoktor 4 znakyGridsquare 4-Chars AwardsDialogLoktor 6 znakoGridsquare 6-Chars AwardsDialogIOTAIOTA AwardsDialogITUITU AwardsDialog4Japonsk msta / ku / gunyJapanese Cities/Ku/Guns AwardsDialogLoTWLoTW AwardsDialogDruh provozuMode AwardsDialogM DXCC ZemMy DXCC Entity AwardsDialog*Okresy Novho Zlandu NZ Counties AwardsDialog.}dn u~ivatelsk filtrNo User Filter AwardsDialogSevern Amerika North America AwardsDialogNepotvrzenoNot-Confirmed Only AwardsDialogNepracovnoNot-Worked Only AwardsDialogOcenieOceania AwardsDialogNastavenOptions AwardsDialogPOTA AktivtorPOTA Activator AwardsDialogPOTA Lovec POTA Hunter AwardsDialogQSLPaper AwardsDialogFnePhone AwardsDialogRusk distriktyRussian Districts AwardsDialogSOTASOTA AwardsDialogZobrazitShow AwardsDialogJi~n Amerika South America AwardsDialog`panlsk DME Spanish DMEs AwardsDialogOkresy USA US Counties AwardsDialog(Ukrajinsk distriktyUkrainian Districts AwardsDialog"U~ivatelsk filtr User Filter AwardsDialogWACWAC AwardsDialogWASWAS AwardsDialogWAZWAZ AwardsDialogWPXWPX AwardsDialogWWFFWWFF AwardsDialogeQSLeQSL AwardsDialogPotvrzeno ConfirmedAwardsTableModel Slot: Slots: AwardsTableModelStle  ek Still WaitingAwardsTableModelPracovnoWorkedAwardsTableModel min min(s) BandmapWidgetBandmapBandmap BandmapWidgetCentrovat RX Center RX BandmapWidgetVae vymazat Clear All BandmapWidgetVymazat stara Clear older BandmapWidget,Vymazat aktuln psmoClear the current band BandmapWidget6VytvoYit dala okno Bandmap#Create an additional Bandmap Window BandmapWidgetBandmapForm BandmapWidgetNemazatNever BandmapWidgetSOSSOS BandmapWidgetZobrazit psmo Show Band BandmapWidget4Zobrazit nouzov frekvenceShow Emergency Frequencies BandmapWidget6Nelze odeslat Text do rdiaCannot send Text to RigCWCatKey:Nelze nastavit rychlost kl eCannot set Keyer SpeedCWCatKey<Nelze zastavit odesln textuCannot stop Text SendingCWCatKey$Kl nen pYipojenKeyer is not connectedCWCatKey"Rig nen pYipojenNo Rig is connectedCWCatKey<Rig nepodporuje Morse over CAT#Rig does not support Morse over CATCWCatKey"Rig nen pYipojenRig is not connectedCWCatKey WPM WPMCWConsoleWidget&CW&CWCWConsoleWidget*CW Konzole - ZastavitCW Console - Halt SendingCWConsoleWidgetProfil kl eCW Keyer ProfileCWConsoleWidgetVymazatClearCWConsoleWidget>Vymazat Odeslan a Echo konzoliClear Sent and Echo ConsoleCWConsoleWidgetEcho text Echoed textCWConsoleWidgetF1F1CWConsoleWidgetF2F2CWConsoleWidgetF3F3CWConsoleWidgetF4F4CWConsoleWidgetF5F5CWConsoleWidgetF6F6CWConsoleWidgetF7F7CWConsoleWidgetFormCWConsoleWidgetZastavitHaltCWConsoleWidget:Okam~it zastavit vysln CWImmediately stop CW sendingCWConsoleWidget-N/ACWConsoleWidget*Rig mus bt pYipojenRig must be connectedCWConsoleWidgetOdeslan text Sent textCWConsoleWidgetShortcut profilShortcuts profileCWConsoleWidgetRychlostSpeedCWConsoleWidgetPYepnout mezi odeslm po <b>slovech</n> (oddlen mezerami) <br>a odeslnm jako <b>celku</b> (oddlen koncem rdku).Switch between sending words individually (separated by spaces)
and sending the entire text as a whole (separated by a new line).CWConsoleWidgetText k odesln Text to sendCWConsoleWidget CelekWholeCWConsoleWidget SlovoWordCWConsoleWidget$Nelze odeslat textCannot send Text CWDaemonKey:Nelze nastavit rychlost kl eCannot set Keyer Speed CWDaemonKey<Nelze zastavit odesln textuCannot stop Text Sending CWDaemonKey$Kl nen pYipojenKeyer is not connected CWDaemonKey:Nelze pYijmount data z FLDigiCannot receive data from FLDigi CWFldigiKey8Nelze odeslat text do FLDigiCannot send Text to FLDigi CWFldigiKey<Nelze odeslat pYkaz do FLDigi'Cannot send the Abort command to FLDigi CWFldigiKey<Nelze odeslat pYkaz do FLDigi'Cannot send the Clear command to FLDigi CWFldigiKey<Nelze odeslat pYkaz do FLDigi&Cannot send the Stop command to FLDigi CWFldigiKey<Nelze odeslat pYkaz do FLDigi$Cannot send the TX command to FLDigi CWFldigiKey<Nelze odeslat pYkaz do FLDigi&Cannot send the Text command to FLDigi CWFldigiKey<PYipojen zaYzen nen FLDigiConnected device is not FLDigi CWFldigiKey>Chyba odeslanho FLDigi pYkazuFLDigi command error CWFldigiKey,Chyba FLDigi pYipojeniFLDigi connection error CWFldigiKeyJVyprael  asov limit pYipojen FLDigiFLDigi connection timeout CWFldigiKey$Kl nen pYipojenKeyer is not connected CWFldigiKey(Nelze pYijipoji kl  Cannot open the Keyer connectionCWKeyerChyba pYipojenConnection ErrorCWKeyer$Chyba inicializaceInitialization ErrorCWKeyerIntern ChybaInternal ErrorCWKeyer<Nen vybrn ~dn profil kl eNo CW Keyer Profile selectedCWKeyer1000 Hz1000 HzCWWinKey1333 Hz1333 HzCWWinKey2000 Hz2000 HzCWWinKey 400 Hz400 HzCWWinKey4000 Hz4000 HzCWWinKey 444 Hz444 HzCWWinKey 500 Hz500 HzCWWinKey 571 Hz571 HzCWWinKey 666 Hz666 HzCWWinKey 800 Hz800 HzCWWinKey6Nelze odeslat Text do rdiaCannot send Text to RigCWWinKey:Nelze nastavit rychlost kl eCannot set Keyer SpeedCWWinKey<Nelze zastavit odesln textuCannot stop Text SendingCWWinKeyChyba pYipojenCommunication ErrorCWWinKey<PYipojen zaYzen nen WinKeyConnected device is not WinKeyCWWinKey$Kl nen pYipojenKeyer is not connectedCWWinKey -  - CabrilloExportDialog&Export&ExportCabrilloExportDialog Dala AdditionalCabrilloExportDialogAdresa:Address:CabrilloExportDialogAsistovan: Assisted:CabrilloExportDialog Psmo:Band:CabrilloExportDialogProchzetBrowseCabrilloExportDialogExport CabrilloCabrillo ExportCabrilloExportDialogSoubory Cabrillo (*.log);;CBR soubory (*.cbr);;Vaechny soubory (*)8Cabrillo Files (*.log);;CBR Files (*.cbr);;All Files (*)CabrilloExportDialogZna ka: Callsign:CabrilloExportDialogDNelze otevYt soubor %1 pro zpis. Cannot open file %1 for writing.CabrilloExportDialog Klub:Club:CabrilloExportDialogContestContestCabrilloExportDialogDatum/ as: Date/Time:CabrilloExportDialog Email:Email:CabrilloExportDialogNExportovno %n QSO do souboru Cabrillo.$Exported %n QSO(s) to Cabrillo file.CabrilloExportDialog,Exportuje se Cabrillo &Exporting Cabrillo...CabrilloExportDialogNNepodaYilo se pYipravit exportn dotaz.Failed to prepare export query.CabrilloExportDialogHNepodaYilo se na st QSO pro export. Failed to query QSOs for export.CabrilloExportDialogSoubor:File:CabrilloExportDialog `ablona formtu:Format Template:CabrilloExportDialogLoktor GridsquareCabrilloExportDialogUmstn: Location:CabrilloExportDialogSpravovatManageCabrilloExportDialogMax. 6 Ydko Max 6 linesCabrilloExportDialogDruh provozu:Mode:CabrilloExportDialog Jmno:Name:CabrilloExportDialogt}dn volac zna ka nen k dispozici. Zkontrolujte filtry.*No callsign available. Check your filters.CabrilloExportDialog Off-Time:CabrilloExportDialogOpertor: Operator:CabrilloExportDialogOpertoYi: Operators:CabrilloExportDialogOverlay:CabrilloExportDialog>Vyberte prosm aablonu sout~e.!Please select a contest template.CabrilloExportDialog>Vyberte prosm vstupn soubor.Please select an output file.CabrilloExportDialog Vkon:Power:CabrilloExportDialogChyba QLog QLog ErrorCabrilloExportDialogInformace QLogQLog InformationCabrilloExportDialogUpozornn QLog QLog WarningCabrilloExportDialogQSO: %1 QSO(s): %1CabrilloExportDialogQSOs: ?QSOs: ?CabrilloExportDialogVoln poznmka:Soapbox:CabrilloExportDialog&Stanice a kategorieStation & CategoriesCabrilloExportDialogStanice:Station:CabrilloExportDialog as:Time:CabrilloExportDialogTransmitter ID:CabrilloExportDialogVysla : Transmitter:CabrilloExportDialogUTCUTCCabrilloExportDialog$U~ivatelsk filtr: User Filter:CabrilloExportDialogyyyy-MM-dd HH:mmCabrilloExportDialogyyyy-mm-dd hhmm yyyy-mm-dd hhmmCabrilloExportDialog1.25m (222 MHz)1.25m (222 MHz)CabrilloFormat12 hodin12 HoursCabrilloFormat23cm (1.2 GHz)23cm (1.2 GHz)CabrilloFormat24 hodin24 HoursCabrilloFormat2m (144 MHz) 2m (144 MHz)CabrilloFormat33cm (902 MHz)33cm (902 MHz)CabrilloFormat6 hodin6 HoursCabrilloFormat70cm (432 MHz)70cm (432 MHz)CabrilloFormatVaechna psma All BandsCabrilloFormatAsistovanAssistedCabrilloFormat Zkontrolovat log Check LogCabrilloFormatKlasickClassicCabrilloFormat$Datum (RRRR-MM-DD)Date (YYYY-MM-DD)CabrilloFormatDigiDigitalCabrilloFormatDistribuovan DistributedCabrilloFormatExpedice ExpeditionCabrilloFormat PevnFixedCabrilloFormatFrekvence (kHz)Frequency (kHz)CabrilloFormatHQHQCabrilloFormatHighHighCabrilloFormat SvtloLightCabrilloFormatOmezenLimitedCabrilloFormatLowLowCabrilloFormatSmaenMixedCabrilloFormatMobilnMobileCabrilloFormatMd (Cabrillo)Mode (Cabrillo)CabrilloFormatVce opertoroMulti OperatorCabrilloFormatNeasistovan Non-AssistedCabrilloFormatNov ek/Technik Novice/TechCabrilloFormat JedenOneCabrilloFormat Nad 50Over 50CabrilloFormatPortablePortableCabrilloFormatQRPCabrilloFormatFRST zkrcen (bez posledn  slice)RST Short (drop last digit)CabrilloFormat RookieRookieCabrilloFormat RoverRoverCabrilloFormatRover Limited Rover LimitedCabrilloFormatRover UnlimitedRover UnlimitedCabrilloFormatSWLSWLCabrilloFormat `kolaSchoolCabrilloFormatJeden opertorSingle OperatorCabrilloFormatTB WiresTB WiresCabrilloFormat*Text (zarovnn vlevo)Text (left-aligned)CabrilloFormat as (HHMM) Time (HHMM)CabrilloFormatTransmitter IDCabrilloFormatDvaTwoCabrilloFormatNeomezen UnlimitedCabrilloFormatVelk psmena UppercaseCabrilloFormatVHF 3 psma VHF 3-BandCabrilloFormatPouze VHF FM VHF FM OnlyCabrilloFormat slo s nulamiZero-Padded Nr.CabrilloFormat PYidatAddCabrilloTemplateDialogPYidat YdekAdd lineCabrilloTemplateDialog.Sprvce Cabrillo aablonCabrillo Template ManagerCabrilloTemplateDialog0Nelze otevYt soubor: %1Cannot open file: %1CabrilloTemplateDialog:Nelze ulo~it aablonu %1 : %2Cannot save template '%1': %2CabrilloTemplateDialogHNelze zahjit databzovou transakci."Cannot start database transaction.CabrilloTemplateDialogNzev zvodu: Contest Name:CabrilloTemplateDialogNzev sout~e podle pravidel. Je mo~n zadat vlastn Yetzec, pokud nen v seznamu.qContest name as required by the rules. It is possible to enter a custom string if it is not included in the list.CabrilloTemplateDialogKoprovatCopyCabrilloTemplateDialogKopie  %1 Copy - %1CabrilloTemplateDialog8Koprovat existujc aablonuCopy existing templateCabrilloTemplateDialogVchoz md: Default Mode:CabrilloTemplateDialogVymazatDeleteCabrilloTemplateDialogSmazat aablonuDelete TemplateCabrilloTemplateDialogSmazat aablonuDelete templateCabrilloTemplateDialog(Smazat aablonu %1 ?Delete template '%1'?CabrilloTemplateDialog ExportExportCabrilloTemplateDialog$Export se nezdaYil Export FailedCabrilloTemplateDialog$Exportovat aablonuExport TemplateCabrilloTemplateDialog$Exportovat aablonuExport templateCabrilloTemplateDialog>NepodaYilo se zapsat soubor: %1Failed to write file: %1CabrilloTemplateDialog0Soubor nebyl nalezen: %1File not found: %1CabrilloTemplateDialogFormtova  FormatterCabrilloTemplateDialog ImportImportCabrilloTemplateDialog$Import se nezdaYil Import FailedCabrilloTemplateDialog$Importovat aablonuImport TemplateCabrilloTemplateDialog$Importovat aablonuImport templateCabrilloTemplateDialogHNeplatn soubor aablony: chyb nzev#Invalid template file: missing nameCabrilloTemplateDialog `ttekLabelCabrilloTemplateDialogNovNewCabrilloTemplateDialogNov aablona New TemplateCabrilloTemplateDialogNov aablona New templateCabrilloTemplateDialog:QLog Cabrillo aablona (*.qct)QLog Cabrillo Template (*.qct)CabrilloTemplateDialogChyba QLog QLog ErrorCabrilloTemplateDialogUpozornn QLog QLog WarningCabrilloTemplateDialogPole QSO QSO FieldCabrilloTemplateDialog$Sloupce Ydku QSO:QSO Line Columns:CabrilloTemplateDialogVymazatRemoveCabrilloTemplateDialog.Odstranit vybran YdekRemove selected lineCabrilloTemplateDialogPoY.Seq.CabrilloTemplateDialogNzev aablony:Template Name:CabrilloTemplateDialog `YkaWidthCabrilloTemplateDialog:<p>Bude pou~it sekundrn</p>*

The secondary callbook will be used

CallbookManagerChat Chat Room ChatWidgetPYipojitConnect ChatWidgetNovNew ChatWidgetON4KST Chat ON4KST Chat ChatWidgetON4KST Chat nen sprvn nastaven.<p> Prosm, pou~ijte dialog <b>Nastaven</b> pro konfiguraci slu~by.</p>bON4KST Chat is not configured properly.

Please, use Settings dialog to configure it.

 ChatWidgetUpozornn QLog QLog Warning ChatWidgetVypnutoDisabledCheckBoxDelegateZapnutoEnabledCheckBoxDelegate HodinyForm ClockWidget-N/A ClockWidget VchodSunrise ClockWidget ZpadSunset ClockWidget"Neplatn kl APIInvalid API KeyCloudlogUploaderdClublog operace pro zna ku %1 se nezdraYila.<br>%2/Clublog Operation for Callsign %1 failed.
%2ClubLogUploader:Nastaven zobrazench sloupcoColumn Visibility SettingColumnSettingDialogPodmnky ConditionalsColumnSettingDialog ZvodyContestsColumnSettingDialogDokon itDoneColumnSettingDialog ObecnGeneralColumnSettingDialog lenstvMembersColumnSettingDialogMoje InfoMy InfoColumnSettingDialogJinOthersColumnSettingDialog QSL && CallbooksQSL && CallbooksColumnSettingDialogVybrat vae Select AllColumnSettingGenericDialogOdzna it vae Unselect AllColumnSettingGenericDialog:Nastaven zobrazench sloupcoColumn Visibility SettingColumnSettingSimpleDialogDokon itDoneColumnSettingSimpleDialog( Aktualizace selhala Update FailedDBSchemaMigrationClublog CTY.XMLClublog CTY.XMLDBSchemaMigrationDXCC Zem DXCC EntitiesDBSchemaMigrationIOTA zznamy IOTA RecordsDBSchemaMigrationSeznam hodnotList of ValuesDBSchemaMigration"Klubov informaceMembership Directory RecordsDBSchemaMigrationPOTA zznamy POTA RecordsDBSchemaMigrationSOTA Summit SOTA SummitsDBSchemaMigrationSat Info Sats InfoDBSchemaMigrationAktualizuji  Updating DBSchemaMigrationWWFF zznamy WWFF RecordsDBSchemaMigrationAfghnistn Afghanistan DBStrings*Agalega a St. BrandonAgalega & St. Brandon DBStrings Alandsk ostrovy Aland Islands DBStringsAljaakaAlaska DBStringsAlbnieAlbania DBStringsAl~rskoAlgeria DBStringsAmerick SamoaAmerican Samoa DBStrings0Amsterdam a St. Paul Is.Amsterdam & St. Paul Is. DBStrings*Andaman & Nicobar Is.Andaman & Nicobar Is. DBStringsAndorraAndorra DBStrings AngolaAngola DBStringsAnguillaAnguilla DBStringsOstrov AnnobonAnnobon Island DBStringsAntarktida Antarctica DBStrings"Antigua a BarbudaAntigua & Barbuda DBStringsArgentina Argentina DBStringsArmnieArmenia DBStrings ArubaAruba DBStrings Ostrov AscensionAscension Island DBStringsAsijsk RuskoAsiatic Russia DBStringsAsijsk TureckoAsiatic Turkey DBStrings$Australsk ostrovyAustral Islands DBStringsAustrlie Australia DBStringsRakouskoAustria DBStringsOstrov Aves Aves Island DBStringszerbajd~n Azerbaijan DBStrings AzoryAzores DBStrings BahamyBahamas DBStringsBahrajnBahrain DBStrings:Bakerovy a Howlandovy ostrovyBaker & Howland Islands DBStrings"Balersk ostrovyBalearic Islands DBStringsOstrov Banaba Banaba Island DBStringsBanglada Bangladesh DBStringsBarbadosBarbados DBStringsBloruskoBelarus DBStrings BelgieBelgium DBStrings BelizeBelize DBStrings BeninBenin DBStringsBermudyBermuda DBStrings BhtnBhutan DBStringsBolvieBolivia DBStringsBonaireBonaire DBStrings&Bosna a HercegovinaBosnia-Herzegovina DBStringsBotswanaBotswana DBStrings BouvetBouvet DBStringsBrazlieBrazil DBStrings0Britsk Panensk ostrovyBritish Virgin Islands DBStrings"Brunej DarussalamBrunei Darussalam DBStringsBulharskoBulgaria DBStringsBurkina Faso Burkina Faso DBStringsBurundiBurundi DBStringsCWCW DBStringsKambod~aCambodia DBStringsKamerunCameroon DBStrings KanadaCanada DBStrings Kanrsk ostrovyCanary Islands DBStringsKapverdy Cape Verde DBStrings"Kajmansk ostrovyCayman Islands DBStrings.StYedoafrick republikaCentral African Republic DBStrings StYedn KiribatiCentral Kiribati DBStringsCeuta a MelillaCeuta & Melilla DBStrings adChad DBStringsostrovy ChagosChagos Islands DBStrings$Chathamsk ostrovyChatham Islands DBStrings.Chesterfieldovy ostrovyChesterfield Islands DBStrings ChileChile DBStrings naChina DBStringsVno n ostrovChristmas Island DBStrings"Ostrov ClippertonClipperton Island DBStrings:Kokosov (Keelingovy) ostrovyCocos (Keeling) Islands DBStringsKokosov ostrov Cocos Island DBStringsKolumbieColombia DBStrings KomoryComoros DBStringsConwaysk tes Conway Reef DBStringsKorsikaCorsica DBStringsKostarika Costa Rica DBStrings"PobYe~ slonoviny Cote d'Ivoire DBStrings KrtaCrete DBStringsChorvatskoCroatia DBStringsOstrov Crozet Crozet Island DBStringsKubaCuba DBStringsCuracaoCuracao DBStringsKyprCyprus DBStrings esk RepublikaCzech Republic DBStringsDigiDIGITAL DBStrings2Korejsk lidov republika DPR of Korea DBStringsDem. Rep. KongaDem. Rep. of the Congo DBStrings DnskoDenmark DBStringsOstrov DesecheoDesecheo Island DBStringsD~ibutskoDjibouti DBStringsDodecanese Dodecanese DBStringsDominikaDominica DBStrings,Dominiknsk republikaDominican Republic DBStringsOstrov Ducie Ducie Island DBStrings"Vchodn Malajsie East Malaysia DBStrings$Velikono n ostrov Easter Island DBStrings"vchodn KiribatiEastern Kiribati DBStringsEkvdorEcuador DBStrings EgyptEgypt DBStringsEl Salvador El Salvador DBStrings AnglieEngland DBStrings Rovnkov GuineaEquatorial Guinea DBStringsEritreaEritrea DBStringsEstonskoEstonia DBStringsEtiopieEthiopia DBStringsevropsk RuskoEuropean Russia DBStringsFalklandyFalkland Islands DBStringsFaersk ostrovy Faroe Islands DBStringsNmeckoFed. Rep. of Germany DBStrings&Fernando de NoronhaFernando de Noronha DBStrings Fid~iFiji DBStrings FinskoFinland DBStringsFrancieFrance DBStrings*Zem Frantiaka JosefaFranz Josef Land DBStrings$Francouzsk Guyana French Guiana DBStrings*Francouzsk PolynsieFrench Polynesia DBStrings GabonGabon DBStringsGalapgyGalapagos Islands DBStrings GruzieGeorgia DBStrings GhanaGhana DBStringsGibraltar Gibraltar DBStrings Ostrovy GloriosoGlorioso Islands DBStrings XeckoGreece DBStringsGrnsko Greenland DBStringsGrenadaGrenada DBStringsGuadeloupe Guadeloupe DBStringsGuamGuam DBStringsGuantnamoGuantanamo Bay DBStringsGuatemala Guatemala DBStringsGuernseyGuernsey DBStrings GuineaGuinea DBStringsGuinea-Bissau Guinea-Bissau DBStrings GuyanaGuyana DBStrings HaitiHaiti DBStrings HavajHawaii DBStringsHeardov ostrov Heard Island DBStringsHondurasHonduras DBStringsHong Kong Hong Kong DBStringsMaarskoHungary DBStrings ITU HQITU HQ DBStrings IslandIceland DBStrings IndieIndia DBStringsIndonsie Indonesia DBStringsrnIran DBStringsIrkIraq DBStrings IrskoIreland DBStringsOstrov Man Isle of Man DBStrings IzraelIsrael DBStrings ItlieItaly DBStringsJamaicaJamaica DBStringsJan Mayen Jan Mayen DBStringsJaponskoJapan DBStrings JerseyJersey DBStringsOstrov JohnstonJohnston Island DBStrings JordnJordan DBStrings0Ostrovy Juana FernandezeJuan Fernandez Islands DBStrings*Juan de Nova a EvropaJuan de Nova & Europa DBStringsKaliningrad Kaliningrad DBStringsKazachstn Kazakhstan DBStringsKeHaKenya DBStrings(Kerguelensk ostrovyKerguelen Islands DBStrings ostrovy KermadecKermadec Islands DBStrings&Krlovstv EswatiniKingdom of Eswatini DBStringsOstrov Kure Kure Island DBStrings KuvajtKuwait DBStringsKyrgyzstn Kyrgyzstan DBStrings&Ostrovy LakshadweepLakshadweep Islands DBStringsLaosLaos DBStringsLotyaskoLatvia DBStringsLibanonLebanon DBStringsLesothoLesotho DBStringsLibrieLiberia DBStrings LibyeLibya DBStringsLichtenatejnsko Liechtenstein DBStrings Litva Lithuania DBStrings$Ostrov lorda HoweaLord Howe Island DBStringsLucembursko Luxembourg DBStrings MacaoMacao DBStrings Ostrov MacquarieMacquarie Island DBStringsMadagaskar Madagascar DBStringsostrovy MadeiraMadeira Islands DBStrings MalawiMalawi DBStringsMaledivyMaldives DBStringsMaliMali DBStringsOstrov MalpeloMalpelo Island DBStrings MaltaMalta DBStrings"Marinsk ostrovyMariana Islands DBStringsMarket Reef Market Reef DBStrings"Markzsk ostrovyMarquesas Islands DBStrings&Marshallovy ostrovyMarshall Islands DBStringsMartinik Martinique DBStringsMauritnie Mauritania DBStringsMauricius Mauritius DBStringsMayotteMayotte DBStringsMellish Reef Mellish Reef DBStrings MexikoMexico DBStringsMikronsie Micronesia DBStringsOstrov Midway Midway Island DBStrings Minami TorishimaMinami Torishima DBStringsMoldavskoMoldova DBStrings MonakoMonaco DBStringsMongolskoMongolia DBStrings ern Hora Montenegro DBStringsMontserrat Montserrat DBStrings MarokoMorocco DBStringsHora Athos Mount Athos DBStringsMosambik Mozambique DBStringsMyanmarMyanmar DBStringsNamibieNamibia DBStrings NauruNauru DBStringsOstrov NavassaNavassa Island DBStrings NeplNepal DBStringsHolandsko Netherlands DBStringsNov Kaledonie New Caledonia DBStringsNov Zland New Zealand DBStringsNikaragua Nicaragua DBStrings NigerNiger DBStringsNigrieNigeria DBStringsNiueNiue DBStringsOstrov NorfolkNorfolk Island DBStrings.Severn Cookovy ostrovyNorth Cook Islands DBStrings"Severn MakedonieNorth Macedonia DBStringsSevern IrskoNorthern Ireland DBStrings NorskoNorway DBStringsOgasawara Ogasawara DBStringsOmnOman DBStringsFnePHONE DBStringsPkistnPakistan DBStrings PalauPalau DBStringsPalestina Palestine DBStrings0Palmra a ostrovy JarvisPalmyra & Jarvis Islands DBStrings PanamaPanama DBStrings"Papua-Nov GuineaPapua New Guinea DBStringsParaguayParaguay DBStringsPeruPeru DBStringsOstrov Petr 1Peter 1 Island DBStringsFilipny Philippines DBStringsOstrov PitcairnPitcairn Island DBStrings PolskoPoland DBStringsPortugalskoPortugal DBStringsOstrov Pratas Pratas Island DBStringsPortoriko Puerto Rico DBStrings KatarQatar DBStrings$Korejsk republikaRepublic of Korea DBStrings$Kosovsk republikaRepublic of Kosovo DBStrings*Republika Ji~n SdnRepublic of South Sudan DBStringsRepublika KongoRepublic of the Congo DBStringsOstrov RunionReunion Island DBStringsRevillagigedo Revillagigedo DBStrings$Rodriguezov ostrovRodriguez Island DBStringsRumunskoRomania DBStringsOstrov Rotuma Rotuma Island DBStrings RwandaRwanda DBStrings(Saba & St. EustatiusSaba & St. Eustatius DBStringsSable Island Sable Island DBStrings SamoaSamoa DBStrings0San Andres & ProvidencieSan Andres & Providencia DBStrings0San Felix a San AmbrosioSan Felix & San Ambrosio DBStringsSan Marino San Marino DBStrings8Svat Toma a Princov ostrovSao Tome & Principe DBStringsSardinieSardinia DBStringsSaudsk arbie Saudi Arabia DBStrings tes ScarboroughScarborough Reef DBStringsSkotskoScotland DBStringsSenegalSenegal DBStrings SrbskoSerbia DBStringsSeychely Seychelles DBStringsSierra Leone Sierra Leone DBStringsSingapur Singapore DBStringsSvat Martin Sint Maarten DBStrings&Slovensk republikaSlovak Republic DBStringsSlovinskoSlovenia DBStrings$Solomonovy ostrovySolomon Islands DBStringsSomlskoSomalia DBStringsJi~n Afrika South Africa DBStrings*Ji~n Cookovy ostrovySouth Cook Islands DBStrings(Ostrov Ji~n GeorgieSouth Georgia Island DBStrings.Ji~n Orknejsk ostrovySouth Orkney Islands DBStrings2Ji~n Sandwichovy ostrovySouth Sandwich Islands DBStrings2Ji~n Shetlandsk ostrovySouth Shetland Islands DBStrings*Maltzsk Yd Sov MilSov Mil Order of Malta DBStrings`panlskoSpain DBStrings"Spratlyho ostrovySpratly Islands DBStringsSr Lanka Sri Lanka DBStrings Svat BartolomjSt. Barthelemy DBStringsSvat Helena St. Helena DBStrings*Svat Kryatof a NevisSt. Kitts & Nevis DBStringsSvat Lucie St. Lucia DBStringsSvat Martin St. Martin DBStrings(Ostrov svatho PavlaSt. Paul Island DBStrings0Svat Petr a Svat PavelSt. Peter & St. Paul DBStrings*St. Pierre a MiquelonSt. Pierre & Miquelon DBStringsSvat Vincent St. Vincent DBStrings SdnSudan DBStringsSurinamSuriname DBStringsSvalbardSvalbard DBStringsOstrov Swains Swains Island DBStrings`vdskoSweden DBStrings`vcarsko Switzerland DBStrings SrieSyria DBStringsTchaj-wanTaiwan DBStringsTd~ikistn Tajikistan DBStringsTanzanieTanzania DBStrings Provincie TemotuTemotu Province DBStringsThajskoThailand DBStrings Gambie The Gambia DBStrings Timor  Vchodn Timor - Leste DBStringsTogoTogo DBStrings$Tokelausk ostrovyTokelau Islands DBStrings TongaTonga DBStrings0Trindade a Martim VazoviTrindade & Martim Vaz DBStrings"Trinidad a TobagoTrinidad & Tobago DBStringsFTristan da Cunha a Goughovy ostrovy Tristan da Cunha & Gough Islands DBStringsOstrov TromelinTromelin Island DBStringsTuniskoTunisia DBStringsTurkmenistn Turkmenistan DBStrings,Ostrovy Turks a CaicosTurks & Caicos Islands DBStrings TuvaluTuvalu DBStrings2Americk Panensk ostrovyUS Virgin Islands DBStrings UgandaUganda DBStringsUkrajinaUkraine DBStrings.Spojen arabsk emirtyUnited Arab Emirates DBStringsBSdlo Organizace spojench nrodoUnited Nations HQ DBStringsSpojen stty United States DBStringsUruguayUruguay DBStringsUzbekistn Uzbekistan DBStringsVanuatuVanuatu DBStringsVatikn Vatican City DBStringsVenezuela Venezuela DBStringsVietnamVietnam DBStringsOstrov Wake Wake Island DBStrings WalesWales DBStrings.Ostrovy Wallis a FutunaWallis & Futuna Islands DBStrings Zpadn Malajsie West Malaysia DBStrings Zpadn KiribatiWestern Kiribati DBStringsZpadn SaharaWestern Sahara DBStringsOstrov Willis Willis Island DBStrings JemenYemen DBStrings ZambieZambia DBStringsZimbabweZimbabwe DBStrings.%1 %2 %3  DXCC %4 / %5%1 %2 %3 — DXCC %4 / %5DXCCSubmissionDialog$%1 vybranch psem%1 selected band(s)DXCCSubmissionDialog5psmov DXCC 5-Band DXCCDXCCSubmissionDialog@5psmov DXCC (80/40/20/15/10 m)5-Band DXCC (80/40/20/15/10m)DXCCSubmissionDialog5psmov5-bandDXCCSubmissionDialog$Vaechna DXCC psmaAll DXCC BandsDXCCSubmissionDialogJi~ uznnoAlready GrantedDXCCSubmissionDialog>Libovoln psmo (roveH entity)Any Band (Entity Level)DXCCSubmissionDialog PsmoBandDXCCSubmissionDialogRozsah psem Band ScopeDXCCSubmissionDialog PsmaBandsDXCCSubmissionDialogCWCWDXCCSubmissionDialog Zna kaCallsignDXCCSubmissionDialogKategorieCategoryDXCCSubmissionDialogPotvrzeno Confirmed byDXCCSubmissionDialog&Vlastn vbr psemCustom Band SelectionDXCCSubmissionDialog,Seznam pro DXCC podnDXCC Submission ListDXCCSubmissionDialog DatumDateDXCCSubmissionDialogDigiDigitalDXCCSubmissionDialog EntitaEntityDXCCSubmissionDialog ExportExportDXCCSubmissionDialogExport ADIF Export ADIFDXCCSubmissionDialogNExportovat seznam DXCC podn jako ADIF#Export DXCC Submission List as ADIFDXCCSubmissionDialog`Exportovat kontakty uveden vae do souboru ADIF0Export the contacts listed above to an ADIF fileDXCCSubmissionDialogLNepodaYilo se na st zznamy kontakto.#Failed to retrieve contact records.DXCCSubmissionDialog UznnoGrantedDXCCSubmissionDialogLoTWLoTWDXCCSubmissionDialogSmaenMixedDXCCSubmissionDialogDruh provozuModeDXCCSubmissionDialogM DXCC ZemMy DXCC EntityDXCCSubmissionDialog.}dn u~ivatelsk filtrNo User FilterDXCCSubmissionDialog\}dn kontakty neodpovdaj zadanm kritrim.(No contacts match the selected criteria.DXCCSubmissionDialog2}dn kontakty k exportu.No contacts to export.DXCCSubmissionDialog$Dosud nepYedlo~enoNot Yet SubmittedDXCCSubmissionDialogNastavenOptionsDXCCSubmissionDialogQSLPaperDXCCSubmissionDialogFnePhoneDXCCSubmissionDialog PrefixPrefixDXCCSubmissionDialogrVybrat pYednastaven DXCC psma 5-Band (80/40/20/15/10 m)1Select 5-Band DXCC preset bands (80/40/20/15/10m)DXCCSubmissionDialogFVybrat vaechna DXCC zposobil psmaSelect all DXCC-eligible bandsDXCCSubmissionDialogtVyberte mo~nosti vae a seznam se automaticky aktualizuje.Feldbedingte UnregelmigkeitenField Aligned IrregularitiesDataGHzGHzDataGraylineGraylineDataBodenwelle Ground WaveDataHzHzDataIRLPIRLPData"Internet-assistedInternet-assistedDataUngltigInvalidDataIonoscatter IonoscatterDataSichtlinie Line of SightData Long PathDataMHzMHzDataNMechanical fully-automatic keyer or Bug'Mechanical fully-automatic keyer or BugDataLMechanical semi-automatic keyer or Bug&Mechanical semi-automatic keyer or BugDataGendertModifiedDataNeues BandNew BandDataNeues Band&Mode New Band&ModeDataNeuer Eintrag New EntityDataNeuer ModeNew ModeDataNeuer SlotNew SlotDataNeinNoDataNicht gehrt Not HeardData AndereOtherDataWartendQueuedDataAngefordert RequestedData Short PathDataSideswiper SideswiperDataSingle Paddle Single PaddleDataSporadic E Sporadic EDataStraight Key Straight KeyDataUnsicher UncertainDataUnbekanntUnknownDataGearbeitetWorkedDataJaYesDatakHzkHzDataLeerBlankDateFormatDelegateD%1 Zeile(n) in %2 ms zurckgegeben%1 row(s) returned in %2 msDevToolsDialog^%1 Zeile(n) angezeigt (gekrzt auf %2) in %3 ms*%1 row(s) shown (truncated at %2) in %3 msDevToolsDialog ADIF exportieren ADIF ExportDevToolsDialogAnwendenApplyDevToolsDialogJCSV-Dateien (*.csv);;Alle Dateien (*) CSV Files (*.csv);;All Files (*)DevToolsDialogdDatei kann nicht zum Schreiben geffnet werden: %1 Cannot open file for writing: %1DevToolsDialogHDatei kann nicht geffnet werden: %1Cannot open file: %1DevToolsDialogNDatei kann nicht gespeichert werden: %1Cannot save file: %1DevToolsDialogDebug-Log Debug LogDevToolsDialog6Debug-Log in %1 gespeichertDebug log saved to %1DevToolsDialog Entwickler-ToolsDeveloper ToolsDevToolsDialogjSQL-Abfrage hier eingeben... Strg+Eingabe = ausfhren)Enter SQL query here... Ctrl+Return = runDevToolsDialogFehler: %1 Error: %1DevToolsDialogExportierenExportDevToolsDialogExportieren als Export AsDevToolsDialogExportfehler Export ErrorDevToolsDialog"Datei exportieren Export FileDevToolsDialog<%1 Zeile(n) nach %2 exportiertExported %1 row(s) to %2DevToolsDialog^Die Debug-Logdatei konnte nicht kopiert werden."Failed to copy the debug log file.DevToolsDialogpKontaktaufzeichnungen konnten nicht abgerufen werden: %1&Failed to retrieve contact records: %1DevToolsDialogHDateiprotokollierung ist deaktiviertFile logging is disabledDevToolsDialog(Debug-Datei erzeugenGenerate Debug FileDevToolsDialogHLogdateien (*.log);;Alle Dateien (*) Log Files (*.log);;All Files (*)DevToolsDialogLogdatei: %1 Log file: %1DevToolsDialog.Protokollierungsregeln:Logging Rules:DevToolsDialogBProtokollierungsregeln angewendetLogging rules appliedDevToolsDialog^Protokollierungsregeln zurckgesetzt (Standard) Logging rules cleared (defaults)DevToolsDialogZDerzeit wird keine Debug-Logdatei geschrieben,No debug log file is currently being writtenDevToolsDialogfKeine passenden Kontakte in der Datenbank gefunden.+No matching contacts found in the database.DevToolsDialogBKeine Ergebnisse zum Exportieren.No results to export.DevToolsDialoghKeine gltigen Kontakt-IDs im Ergebnissatz gefunden.-No valid contact IDs found in the result set.DevToolsDialog$Fehler beim ffnen Open ErrorDevToolsDialogSQL ffnenOpen SQLDevToolsDialog$SQL-Abfrage ffnenOpen SQL QueryDevToolsDialog2Abfrage in %1 gespeichertQuery saved to %1DevToolsDialogSQL ausfhrenRun SQLDevToolsDialogSQL-Konsole SQL ConsoleDevToolsDialogJSQL-Dateien (*.sql);;Alle Dateien (*) SQL Files (*.sql);;All Files (*)DevToolsDialog&Debug-Log speichernSave Debug LogDevToolsDialog*Fehler beim Speichern Save ErrorDevToolsDialogSQL speichernSave SQLDevToolsDialog*SQL-Abfrage speichernSave SQL QueryDevToolsDialogJTextdateien (*.txt);;Alle Dateien (*)!Text Files (*.txt);;All Files (*)DevToolsDialog8z. B. qlog.ui.*.runtime=truee.g. qlog.ui.*.runtime=trueDevToolsDialogLAktualisierung von %1 fehlgeschlagen: %1 update failed: DownloadQSLDialog&Herunterladen &DownloadDownloadQSLDialogAbbrechenCancelDownloadQSLDialog$QSLs herunterladen Download QSLsDownloadQSLDialog(Herunterladen von %1Downloading from %1DownloadQSLDialogLoTWLoTWDownloadQSLDialogLoTW ist nicht richtig eingerichtet.<p> Bitte verwende den <b>Einstellungen</b> Dialog, um es einzurichten.</p>[LoTW is not configured properly.

Please, use Settings dialog to configure it.

DownloadQSLDialog$Eigenes Rufzeichen My CallsignDownloadQSLDialog,Kein Dienst ausgewhltNo service selectedDownloadQSLDialog$Verarbeite %1 QSLsProcessing %1 QSLsDownloadQSLDialogQLog Fehler QLog ErrorDownloadQSLDialog QLog InformationQLog InformationDownloadQSLDialogQSLs seit QSLs SinceDownloadQSLDialogQSO seit QSOs SinceDownloadQSLDialogeQSLeQSLDownloadQSLDialogeQSL QTH ProfileQSL QTH ProfileDownloadQSLDialogeQSL ist nicht richtig eingerichtet.<p> Bitte verwende den <b>Einstellungen</b> Dialog, um es einzurichten.</p>[eQSL is not configured properly.

Please, use Settings dialog to configure it.

DownloadQSLDialog kHz kHzDxFilterDialog AfrikaAfricaDxFilterDialogAntarktis AntarcticaDxFilterDialog AsienAsiaDxFilterDialog BnderBandsDxFilterDialogCWCWDxFilterDialogBesttigt ConfirmedDxFilterDialogKontinent ContinentDxFilterDialog"DX Cluster FilterDX Cluster FiltersDxFilterDialogDigitalDigitalDxFilterDialog,Folgende Spots nicht anzeigen, wenn sie dasselbe Rufzeichen haben und der Unterschied in Frequenz und Zeit kleiner als die eingestellten Parameter istDo not show the following spots when they have the same Callsign and their time difference is lower than Time Diff and their frequency difference is lower than Freq DiffDxFilterDialog EuropaEuropeDxFilterDialog"Erweiterte FilterExtended FiltersDxFilterDialogFTx (FT8/FT4) FTx (FT8/FT4)DxFilterDialog&FrequenzunterschiedFrequency differenceDxFilterDialog"Allgemeine FilterGeneral FiltersDxFilterDialogLog Status Log StatusDxFilterDialogMitgliedMemberDxFilterDialogBetriebsartenModesDxFilterDialogNeues BandNew BandDxFilterDialogNeuer Eintrag New EntityDxFilterDialogNeuer ModeNew ModeDxFilterDialogNeuer SlotNew SlotDxFilterDialog2Keine Clubliste aktiviertNo Club List is enabledDxFilterDialogNordamerika North AmericaDxFilterDialogOzeanienOceaniaDxFilterDialog PhoniePhoneDxFilterDialogSdamerika South AmericaDxFilterDialog0Spot-Dubletten entfernen Spots DedupDxFilterDialog"Spotter KontinentSpotter ContinentDxFilterDialogZeitunterschiedTime differenceDxFilterDialogGearbeitetWorkedDxFilterDialogssDxFilterDialogBandBand DxTableModelRufzeichenCallsign DxTableModelKommentarComment DxTableModelKontinent Continent DxTableModelLandCountry DxTableModelFrequenz Frequency DxTableModelMitgliedMember DxTableModelBetriebsartMode DxTableModelSpotter DxTableModel"Spotter KontinentSpotter Continent DxTableModelZeitTime DxTableModel 15-min TrendDxWidget*Ungltiges RufzeichenAn invalid callsignDxWidgetAutomatischAutoDxWidgetLAutomatische Verbindung nach dem Start Automatic connection after startDxWidgetLschenClearDxWidget Passwort lschenClear PasswordDxWidgetAlle LschenClear all dataDxWidgetSuche schlieen Close SearchDxWidget,Spaltensichtbarkeit...Column Visibility...DxWidgetVerbindenConnectDxWidget(Beim Start verbindenConnect on startupDxWidgetVerbinden... Connecting...DxWidgetKonsoleConsoleDxWidget&DX-Cluster KommandoDX Cluster CommandDxWidget&DX Cluster PasswortDX Cluster PasswordDxWidgetRDX-Cluster vorbergehend nicht erreichbar%DX Cluster is temporarily unavailableDxWidget(DXC - Lschen ServerDXC - Delete ServerDxWidgetDXC- Suchen DXC - SearchDxWidget DXC-ServerfehlerDXC Server ErrorDxWidgetLschen Server Delete ServerDxWidgetTrennen DisconnectDxWidgetFilter DXC Filter DXCDxWidgetFilter... Filter...DxWidgetGefiltertFilteredDxWidgetVolltextsucheFull-text searchDxWidget`Fge <b>hostname:port</b> eines DXC Servers ein.,Insert a hostname:port of DXC Server.DxWidgetSpots merken Keep SpotsDxWidgetMein Kontinent My ContinentDxWidget SuchenSearchDxWidgetSuchen... Search...DxWidget$SicherheitshinweisSecurity NoticeDxWidget2Sende DX-Cluster KommandoSend DX Cluster CommandDxWidget.Letzten QSO-Spot sendenSend last QSO spotDxWidget ServerServerDxWidget*HF Statistik anzeigen Show HF StatsDxWidget,VHF Statistik anzeigenShow VHF StatsDxWidgetWCY anzeigenShow WCYDxWidgetWWV anzeigenShow WWVDxWidget Spot letztes QSO Spot Last QSODxWidgetSpotsDxWidgetSpots werden nicht gelscht, wenn eine Verbindung zu einem neuen DX-Cluster hergestellt wird.:Spots are not cleared when connecting to a new DX Cluster.DxWidgetDas Passwort kann ber einen ungesicherten Kanal gesendet werden1The password can be sent via an unsecured channelDxWidgetAn alleTo AllDxWidgetBenutzernameUsernameDxWidgetWCYWCYDxWidgetWWVWWVDxWidgetLWelche Spalten sollen angezeigt werden!Which columns should be displayedDxWidgetLoTWDxccTableModel PapierPaperDxccTableModelGearbeitetWorkedDxccTableModeleQSLDxccTableModelBetriebsartModeDxccTableWidgetZKeine ADIF-Datei in der eQSL-Antwort gefunden$ADIF file not found in eQSL responseEQSLQSLDownloaderBKann temporre Datei nicht ffnenCannot opet temporary fileEQSLQSLDownloaderTKann das Bild nicht in die Datei speichernCannot save the image to fileEQSLQSLDownloaderFFalsches Passwort oder QTHProfil-Id#Incorrect Password or QTHProfile IdEQSLQSLDownloaderFFalscher Benutzername oder PasswortIncorrect Username or passwordEQSLQSLDownloader$Unbekannter Fehler Unknown ErrorEQSLQSLDownloader6Unbekannte Antwort von eQSLUnknown Reply from eQSL EQSLUploaderAktivitten ActivitiesEditActivitiesDialogHinzufgenAddEditActivitiesDialogBearbeitenEditEditActivitiesDialog AktivittseditorEdit ActivitiesEditActivitiesDialogEntfernenRemoveEditActivitiesDialog"Ignorieren""Ignore" ExportDialog "Nein""No" ExportDialog&Exportieren&Export ExportDialogADXADX ExportDialogAlleAll ExportDialog Bereits gesendet Already Sent ExportDialogDurchsuchenBrowse ExportDialogCSV ExportDialogAbbrechenCancel ExportDialogtExportierte QSOs knnen nicht als gesendet markiert werden!Cannot mark exported QSOs as Sent ExportDialogExport-Felder Column set ExportDialog&Benutzerdefiniert 1Custom 1 ExportDialog&Benutzerdefiniert 2Custom 2 ExportDialog&Benutzerdefiniert 3Custom 3 ExportDialogDatumsbereich Date Range ExportDialogBearbeitenEdit ExportDialoghBearbeiten Sie die aktuelle Auswahl von ADIF-FeldernEdit current set of columns ExportDialog QSOs exportieren Export QSOs ExportDialogQSOs exportieren, die dem ausgewhlten Benutzer-QSO-Filter entsprechen3Export QSOs that match the selected user QSO Filter ExportDialog8Ausgewhlte QSOs exportierenExport Selected QSOs ExportDialogExport-Typ Export Type ExportDialogvNur QSOs exportieren, die tomuto Stationsprofil entsprechen.Export only QSOs matching this station profile ExportDialogNur QSOs exportieren, die mit den aktiven Filtern bereinstimmen.Export only QSOs that match the active filters ExportDialogNur QSOs exportieren, die mit dem ausgewhlten eigenen Rufzeichen bereinstimmen4Export only QSOs that match the selected My Callsign ExportDialogNur QSOs exportieren, die mit dem ausgewhlten eigenen Gitterfeld bereinstimmen6Export only QSOs that match the selected My Gridsquare ExportDialogExportieren Sie nur QSOs, die der ausgewhlten QSL-Ausgang-Via entsprechen;Export only QSOs that match the selected QSL Send Via value ExportDialogNur QSOs exportieren, die dem ausgewhlten Datumsbereich entsprechen3Export only QSOs that match the selected date range ExportDialog.Export wird ausgefhrt & Exporting... ExportDialog DateiFile ExportDialog FilterFilters ExportDialogAllgemeinGeneric ExportDialog6Send-Status mit einbeziehenInclude Sent Status ExportDialogLUnblichen QSO Sent-Status einbeziehen!Include unusual QSO Sent statuses ExportDialogJSONJSON ExportDialogVMarkieren Sie exportierte QSOs als gesendetMark exported QSOs As Sent ExportDialogMinimal ExportDialog$Eigenes Rufzeichen My Callsign ExportDialog$Eigenes Gitterfeld My Gridsquare ExportDialogPOTAPOTA ExportDialogQLog Fehler QLog Error ExportDialogQSL Ausgang via QSL Send via ExportDialogQSL-spezifisch QSL-specific ExportDialogQSLQSLs ExportDialogHBereits gesendete QSOs erneut sendenResend already sent QSOs ExportDialogWhlen Sie eine der vordefinierten Auswahl von ADIF-Feldern aus oder definieren Sie Ihre eigene AuswahlOSelect one of the pre-defined sets of columns or define your own set of columns ExportDialogStationsprofilStation Profile ExportDialogbUnter normalen Umstnden bedeutet dieser Status <b>"ignorieren/fehlerhaft"</b>.<br/>Manchmal kann es jedoch sinnvoll sein, diese Einstellung beim Senden einer QSL zu ignorieren.Under normal circumstances this status means "Ignore/Invalid".
However, it may sometimes be wanted to ignore this setting when sending a QSL. ExportDialogPUnter normalen Umstnden bedeutet dieser Status <b>"nicht senden"</b>.<br/>Manchmal kann es jedoch sinnvoll sein, diese Einstellung beim Senden einer QSL zu ignorieren.Under normal circumstances this status means "do not send".
However, it may sometimes be wanted to ignore this setting when sending a QSL. ExportDialogBenutzer-Filter User Filter ExportDialog&Passwort besttigenConfirm PasswordExportPasswordDialogvPasswrter nach dem Export aus dem Credential Store lschen3Delete passwords from Credential Store after exportExportPasswordDialog Geben Sie ein Passwort ein, um die gespeicherten Zugangsdaten zu verschlsseln. Dieses Passwort wird spter bentigt, um sie wiederherzustellen.bEnter a password to encrypt stored credentials. The password will be needed to restore them later.ExportPasswordDialog<Daten und Einstellungen packenPack Data & SettingsExportPasswordDialogPasswortPasswordExportPasswordDialogZuflligRandomExportPasswordDialog>FLRig-AntwortzeitberschreitungFLRig response timeout FlrigRigDrvNetzwerkfehler Network Error FlrigRigDrv$ZeitberschreitungTimeout FlrigRigDrv6Antwortnachricht fehlerhaftResponse message malformedHRDLogUploader HamQTHHamQTHHamQTHCallbookCATCAT HamlibRigDrvLCI-V-Adresse kann nicht gesetzt werdenCannot set CIV Addr HamlibRigDrvNPTT-Share kann nicht eingestellt werdenCannot set PTT Share HamlibRigDrvJPTT-Typ kann nicht eingestellt werdenCannot set PTT Type HamlibRigDrvNauto_power_on kann nicht gesetzt werdenCannot set auto_power_on HamlibRigDrvNno_xchg kann nicht auf 1 gesetzt werdenCannot set no_xchg to 1 HamlibRigDrvDTRDTR HamlibRigDrv<Fehler bei der FrequenzabfrageGet Frequency Error HamlibRigDrv6Fehler bei der Mode-AbfrageGet Mode Error HamlibRigDrv6Fehler beim Abrufen des VFO Get VFO Error HamlibRigDrv,InitialisierungsfehlerInitialization Error HamlibRigDrv KeineNone HamlibRigDrvRTSRTS HamlibRigDrv2Verbindung fehlgeschlagenRig Open Error HamlibRigDrvDFehler bei der FrequenzeinstellungSet Frequency Error HamlibRigDrv>Fehler bei der ModuseinstellungSet Mode Error HamlibRigDrv8Fehler beim Auslsen der PTT Set PTT Error HamlibRigDrv8Fehler beim Setzen von SplitSet Split Error HamlibRigDrvDFehler beim Setzen des Split-ModusSet Split Mode Error HamlibRigDrvDFehler beim Setzen der TX-FrequenzSet TX Frequency Error HamlibRigDrv>Nicht untersttzter Rig-TreiberUnsupported Rig Driver HamlibRigDrv@Fehler beim Abrufen der PositionGet Possition Error HamlibRotDrv,InitialisierungsfehlerInitialization Error HamlibRotDrv2Verbindung fehlgeschlagenRot Open Error HamlibRotDrvFFehler beim Einstellen der PositionSet Possition Error HamlibRotDrvBNicht untersttzter Rotor-TreiberUnsupported Rotator Driver HamlibRotDrv&Importieren&Import ImportDialog:<p><b>Importieren:</b></p><p>

Importing:

 ImportDialog:<p><b>Logbuch QSO:</b></p><p>

In-Log QSO:

 ImportDialogL<p>Doppelte QSOs importieren?</p>%1 %20

Do you want to import duplicate QSO?

%1 %2 ImportDialogADXADX ImportDialogAlleAll ImportDialogDurchsuchenBrowse ImportDialogKommentarComment ImportDialogZeitraum Date Range ImportDialogVoreinstellungDefaults ImportDialogDetailsDetails ImportDialogDoppeltes QSO Duplicate QSO ImportDialogFehler: %n Error(s): %n ImportDialog DateiFile ImportDialogXFehlende DXCC-Entittsinformationen ergnzen$Fill missing DXCC Entity Information ImportDialogWenn DXCC im importierten Datensatz fehlt, wird es aus dem Rufzeichen ermittelt.QIf DXCC is missing in the imported record, it will be resolved from the callsign. ImportDialogImportierenImport ImportDialog(Ergebnis des Imports Import Result ImportDialogvAlle oder nur QSOs aus dem angegebenen Zeitraum importieren-Import all or only QSOs from the given period ImportDialog"Datum importieren Import date ImportDialog"Datei importieren Imported file ImportDialog2Importiert: %n Kontakt(e)Imported: %n contact(s) ImportDialogEigenes Profil My Profile ImportDialogEigener RigMy Rig ImportDialogOptionenOptions ImportDialog6Zusammenfassung QLog ImportQLog Import Summary ImportDialog(Details speichern...Save Details... ImportDialog$In Datei speichern Save to File ImportDialogDatei auswhlen Select File ImportDialogDer Wert wird verwendet, wenn ein importierter Datensatz den ADIF-Wert nicht enthltFThe value is used when an input record does not contain the ADIF value ImportDialogDie folgenden Werte werden verwendet, wenn ein importierter Datensatz die ADIF-Werte nicht enthltSThe values below will be used when an input record does not contain the ADIF values ImportDialogWarnungen: %nWarning(s): %n ImportDialogDialogInputPasswordDialogPasswort merkenRemember PasswordInputPasswordDialogdDas Passwort wird im Credential Store gespeichert.4The password will be stored in the Credential Store.InputPasswordDialog"Falsches PasswortInvalid passwordKSTChat(Unbekannter Benutzer Unknown UserKSTChatBeam KSTChatWidget Chat-Nachrichten Chat messages KSTChatWidget&Nachrichten lschenClear Messages KSTChatWidgetFAlle Nachrichten im Fenster lschen Clear all messages in the window KSTChatWidgetzAusgewhlten Rufzeichen- und Chat-Nachrichteneintrag lschen./Clear selected Callsign and Chat message entry. KSTChatWidget&SpaltensichtbarkeitColumn Visibility KSTChatWidgetHervorheben Highlight KSTChatWidget$Regeln hervorhebenHighlight Rules KSTChatWidget\Hervorhebung von Meldungen je nach Einstellung'Highlight messages based on the setting KSTChatWidgetQSO vorbereiten Prepare QSO KSTChatWidget*Chat-Nachricht sendenSend chat message KSTChatWidgetHNur Informationen ber mich anzeigenShow About Me Only KSTChatWidgetvNur Nachrichten anzeigen, in denen mein Rufzeichen vorkommt/Show only messages where my callsign is present KSTChatWidgetLUnterdrckung von Benutzer zu BenutzerSuppress User To User KSTChatWidgetrPrivate Nachrichten zwischen zwei Rufzeichen unterdrcken/Suppress private messages between two callsigns KSTChatWidgetbertragen Sie Rufzeichen und Gitterfeldinformationen in den Neues QSO DialogBTransfer Callsign and Gridsquare Information to the New QSO dialog KSTChatWidget*Wertvolle NachrichtenValuable messages KSTChatWidgetLWelche Spalten sollen angezeigt werden!Which columns should be displayed KSTChatWidgetDuYou KSTChatWidget(Bedingung hinzufgen Add ConditionKSTHighlightRuleDetailAlleAllKSTHighlightRuleDetail4Alle folgenden BedingungenAll the following conditionsKSTHighlightRuleDetail<Eine der folgenden BedingungenAny of the following conditionsKSTHighlightRuleDetailNachrichtenraum Chat RoomKSTHighlightRuleDetailenthltContainsKSTHighlightRuleDetail Regel bearbeiten Edit RuleKSTHighlightRuleDetail AktivEnabledKSTHighlightRuleDetailGitterfeld GridsquareKSTHighlightRuleDetail`Hervorhebung von Nachrichten, die bereinstimmenHighlight message which matchKSTHighlightRuleDetailNachrichtMessageKSTHighlightRuleDetail(Darf nicht leer seinMust not be emptyKSTHighlightRuleDetailEntfernenRemoveKSTHighlightRuleDetailRegelname Rule NameKSTHighlightRuleDetailSenderKSTHighlightRuleDetailbeginnt mit Starts withKSTHighlightRuleDetailHinzufgenAddKSTHighlighterSettingDialogBearbeitenEditKSTHighlighterSettingDialog$Regeln hervorhebenHighlight RulesKSTHighlighterSettingDialogNameNameKSTHighlighterSettingDialogEntfernenRemoveKSTHighlighterSettingDialog RegelnRulesKSTHighlighterSettingDialog StaatStateKSTHighlighterSettingDialogLschenClearKeySequenceEdit<html><head/><body><p>& <span style=" font-weight:700;">Die aktuelle Datenbank wird GELSCHT!</span><br/>& <span style=" font-weight:700;">Alle gespeicherten Passwrter werden GELSCHT!</span><br/>& <span style=" font-weight:700;">Die Anwendung wird nach dem Laden neu gestartet</span>.</p><p>Um Daten zu sichern, verwenden Sie zuerst Pack Data &amp; Settings oder Export QSOs.</p></body></html>o

Current database will be DELETED!
All stored passwords will be DELETED!
The application will restart after loading.

To preserve data, use Pack Data & Settings or Export QSOs first.

LoadDatabaseDialogDurchsuchenBrowseLoadDatabaseDialogTTemporre Datei kann nicht erstellt werdenCannot create temporary fileLoadDatabaseDialog\Datenbankdatei kann nicht dekomprimiert werdenCannot decompress database fileLoadDatabaseDialogHDatenbank kann nicht geffnet werdenCannot open databaseLoadDatabaseDialog:Datenbank wird dekomprimiert &Decompressing database...LoadDatabaseDialog4Zugangsdaten entschlsselnDecrypt CredentialsLoadDatabaseDialog Andere PlattformDifferent platformLoadDatabaseDialognPasswort eingeben, um die Zugangsdaten zu entschlsseln%Enter password to decrypt credentialsLoadDatabaseDialog Datei:File:LoadDatabaseDialog"Falsches PasswortInvalid passwordLoadDatabaseDialog*Laden und neu startenLoad && RestartLoadDatabaseDialogfKeine verschlsselten Zugangsdaten in der Datenbank$No encrypted credentials in databaseLoadDatabaseDialoglPasswort zum Importieren der Zugangsdaten erforderlich'Password required to import credentialsLoadDatabaseDialogPasswort: Password:LoadDatabaseDialog\QLog-Datenbankexport (*.dbe);;Alle Dateien (*)+QLog Database Export (*.dbe);;All Files (*)LoadDatabaseDialog&Datenbank auswhlenSelect DatabaseLoadDatabaseDialog0Datenbankdatei auswhlenSelect Database FileLoadDatabaseDialog<Status: Keine Datei ausgewhltStatus: No file selectedLoadDatabaseDialogBDaten und Einstellungen entpackenUnpack Data & SettingsLoadDatabaseDialog"Gltige DatenbankValid databaseLoadDatabaseDialogWarnungWarningLoadDatabaseDialogEin minimaler Satz von Datenfeldern, die nicht vorhanden sind (start_time, call, band, mode, station_callsign)TA minimal set of fields not present (start_time, call, band, mode, station_callsign) LogFormat>Meine DXCC-Informationen fehlenCannot find My DXCC Entity Info LogFormatNEinfgen in die Datenbank nicht mglichCannot insert to database LogFormat2DXCC-Informationen fehlenDXCC Info is missing LogFormatDXCC Status: DXCC State: LogFormatDuplikate Duplicate LogFormat FehlerError LogFormatImportiertImported LogFormatLAuerhalb des gewhlten DatumsbereichsOutside the selected Date Range LogFormatWarnungWarning LogFormatBKein Stationsrufzeichen vorhandenno Station Callsign present LogFormat #MS Bursts LogbookModel #MS Pings LogbookModelA-IndexA-Index LogbookModelARRL Sektion ARRL Section LogbookModelZusatzfelderAdditional Fields LogbookModelAdresseAddress LogbookModelAdresse (ASCII)Address (ASCII) LogbookModel AlterAge LogbookModelHheAltitude LogbookModelAntenne Az Antenna Az LogbookModelAntenne El Antenna El LogbookModelAward erteilt Award Granted LogbookModel"Award eingereichtAward Submitted LogbookModelBandBand LogbookModelBand RXBand RX LogbookModelCQZCQZ LogbookModel$CW Key Information CW Key Info LogbookModelCW Key Typ CW Key Type LogbookModelRufzeichenCall LogbookModel KlasseClass LogbookModel&Clublog UploaddatumClubLog Upload Date LogbookModel(Clublog UploadstatusClubLog Upload State LogbookModelKommentarComment LogbookModel"Kommentar (ASCII)Comment (ASCII) LogbookModel(Operator kontaktiertContacted Operator LogbookModelContest Pfung Contest Check LogbookModelContest ID Contest ID LogbookModelContest VorrangContest Precedence LogbookModelKontinent Continent LogbookModelLandCountry LogbookModelLand (ASCII)Country (ASCII) LogbookModelLandkreisCounty LogbookModelLandkreis Alt County Alt LogbookModel"Beitrag bewilligtCredit Granted LogbookModel&Beitrag eingereichtCredit Submitted LogbookModelDCLeDCLr LogbookModelDCLe Datum DCLr Date LogbookModelDCLaDCLs LogbookModelDCLa Datum DCLs Date LogbookModelDOKDOK LogbookModelDXCCDXCC LogbookModelEntfernungDistance LogbookModel&EME InitialisierungEME Init LogbookModel EmailEmail LogbookModelFISTS CC LogbookModelFISTS Nummer FISTS Number LogbookModelFrequenz Frequency LogbookModelFrequenz RX Frequency RX LogbookModelLocator Gridsquare LogbookModel,Erweitertes GitterfeldGridsquare Extended LogbookModelGastoperatorGuest Operator LogbookModel$HRDLog UploaddatumHRDLog Upload Date LogbookModel&HRDLog UploadstatusHRDLog Upload Status LogbookModel$HamQTH UploaddatumHamQTH Upload Date LogbookModel&HamQTH UploadstatusHamQTH Upload Status LogbookModel(HamlogEU UploaddatumHamlogEU Upload Date LogbookModel*HamlogEU UploadstatusHamlogEU Upload Status LogbookModelIOTAIOTA LogbookModelIOTA Insel-IDIOTA Island ID LogbookModelITUITU LogbookModelK-IndexK-Index LogbookModelBreitengradLatitude LogbookModelLoTWLoTW LogbookModel LoTWeLoTWr LogbookModelLoTWe Datum LoTWr Date LogbookModel LoTWaLoTWs LogbookModelLoTWa Datum LoTWs Date LogbookModel4Logging Station RufzeichenLogging Station Callsign LogbookModelLngengrad Longitude LogbookModelMS Shower Name LogbookModel Max Bursts LogbookModelBetriebsartMode LogbookModel&Eigene ARRL SektionMy ARRL Section LogbookModelEigene Hhe My Altitude LogbookModelEigene Antenne My Antenna LogbookModel,Eigene Antenne (ASCII)My Antenna (ASCII) LogbookModelEigene CQZMy CQZ LogbookModelEiene CW KeyMy CW Key Info LogbookModel$Eigener CW Key TypMy CW Key Type LogbookModelEigene StadtMy City LogbookModel(Eigene Stadt (ASCII)My City (ASCII) LogbookModelEigenes Land My Country LogbookModel(Eigenes Land (ASCII)My Country (ASCII) LogbookModel"Eigener Landkreis My County LogbookModel*Eigener Landkreis Alt My County Alt LogbookModel Eigenes DARC DOK My DARC DOK LogbookModel"Eigenes DXCC LandMy DXCC LogbookModel&Eigene FISTS NummerMy FISTS LogbookModelEigener Locator My Gridsquare LogbookModel6Eigener erweiterter LocatorMy Gridsquare Extended LogbookModel$Eigene IOTA NummerMy IOTA LogbookModel(Eigene IOTA Insel-IDMy IOTA Island ID LogbookModelEigene ITU ZoneMy ITU LogbookModel&Eigener Breitengrad My Latitude LogbookModel$Eigener Lngengrad My Longitude LogbookModelEigener NameMy Name LogbookModel(Eigener Name (ASCII)My Name (ASCII) LogbookModelEigene POTA Ref My POTA Ref LogbookModel&Eigene PostleitzahlMy Postal Code LogbookModel6Eigene Postleitzahl (ASCII)My Postal Code (ASCII) LogbookModelEigener RigMy Rig LogbookModel&Eigener Rig (ASCII)My Rig (ASCII) LogbookModel$Eigene SOTA NummerMy SOTA LogbookModelbEigene spezielle Interessenaktivitt Info (ASCII)&My Spec. Interes Activity Info (ASCII) LogbookModelREigene spezielle Interessenaktivitt InfoMy Spec. Interest Activity Info LogbookModelHEigene spezielle InteressenaktivittMy Special Interest Activity LogbookModelXEigene spezielle Interessenaktivitt (ASCII)$My Special Interest Activity (ASCII) LogbookModelEigener StaatMy State LogbookModelEigene Strasse My Street LogbookModel*Eigene USA-CA BezirkeMy USA-CA Counties LogbookModel.Eigenes VUCC Gitterfeld My VUCC Grids LogbookModelEigener WWFFMy WWFF LogbookModelNameName LogbookModelName (ASCII) Name (ASCII) LogbookModelAnmerkungenNotes LogbookModel&Anmerkungen (ASCII) Notes (ASCII) LogbookModel&Operator RufzeichenOperator Callsign LogbookModel*Eigentmer RufzeichenOwner Callsign LogbookModelPOTAPOTA LogbookModel PapierPaper LogbookModel PrfixPrefix LogbookModel"AusbreitungsmodusPropagation Mode LogbookModel>ffentlicher ChiffrierschlsselPublic Encryption Key LogbookModel.QRZ Herunterladen DatumQRZ Download Date LogbookModel0QRZ Herunterladen StatusQRZ Download Status LogbookModelQRZ UploaddatumQRZ Upload Date LogbookModel QRZ UploadstatusQRZ Upload Status LogbookModelQSL-Nachricht QSL Message LogbookModelQSL Eingang QSL Received LogbookModelQSL AusgangQSL Sent LogbookModelQSL Via LogbookModelQSLeQSLr LogbookModelQSLe Datum QSLr Date LogbookModelQSLe viaQSLr Via LogbookModelQSLaQSLs LogbookModelQSLa Datum QSLs Date LogbookModelQSL-Nachricht QSLs Message LogbookModelQSLa viaQSLs Via LogbookModel"QSO abgeschlossen QSO Completed LogbookModel QSO IDQSO ID LogbookModel QSO Random LogbookModelQTH LogbookModelQTH (ASCII) QTH (ASCII) LogbookModelRST EingangRST Rcvd LogbookModelRST AusgangRST Sent LogbookModelRSTeRSTr LogbookModelRSTaRSTs LogbookModelInfo erhaltenRcvExch LogbookModelNr. erhaltenRcvNr LogbookModel RegionRegion LogbookModelRig LogbookModel Rig (ASCII) LogbookModelSAT BetriebsartSAT Mode LogbookModelSAT NameSAT Name LogbookModelSIG LogbookModel SIG (ASCII) LogbookModelSIG Info LogbookModelSIG Info (ASCII) LogbookModelSKCC Mitglied SKCC Member LogbookModelSOTASOTA LogbookModelSWLSWL LogbookModelInfo gesendetSentExch LogbookModelNr. gesendetSentNr LogbookModelSignalweg Signal Path LogbookModelVerstorben Silent Key LogbookModel Solar Flux LogbookModel StaatState LogbookModelUnterartSubmode LogbookModelTX LeistungTX PWR LogbookModelTen-Ten NummerTen-Ten Number LogbookModelEndzeitTime off LogbookModelStartzeitTime on LogbookModelUKSMG Mitglied UKSMG Member LogbookModelUSA-CA BezirkeUSA-CA Counties LogbookModelVE Prov LogbookModelVUCCVUCC LogbookModelWWFF LogbookModelWebWeb LogbookModeleQSLeQSL LogbookModeleQSL AGeQSL AG LogbookModel eQSLeeQSLr LogbookModeleQSLe Datum eQSLr Date LogbookModel eQSLaeQSLs LogbookModeleQSLa Datum eQSLs Date LogbookModel2fehlende Angaben ergnzenAdd Missing Info LogbookWidgetAlle Bnder All Bands LogbookWidgetAlle Clubs All Clubs LogbookWidgetAlle Lnder All Countries LogbookWidget$Alle Betriebsarten All Modes LogbookWidgetxDurch die Aktualisierung werden alle ausgewhlten Zeilen beeinflusst.<br>Der aktuell bearbeitete Wert in der Spalte wird auf alle ausgewhlten Zeilen angewendet.<br>Mchten Sie fortfahren?By updating, all selected rows will be affected.
The value currently edited in the column will be applied to all selected rows.

Do you want to edit them? LogbookWidget"Callbook-Fehler: Callbook error:  LogbookWidgetBCallbook-Anmeldung fehlgeschlagenCallbook login failed LogbookWidgetRufzeichenCallsign LogbookWidgetAbbrechenCancel LogbookWidgetpClublog <b>Sofort Upload</b> untersttzt nur das Lschen eines Datensatzes nach dem anderen.<br><br>Mchten Sie fortfahren, obwohl<br>der DELETE-Vorgang nicht an Clublog gesendet wird?Clublog's Immediately Send supports only one-by-one deletion

Do you want to continue despite the fact
that the DELETE operation will not be sent to Clublog? LogbookWidgetAnzahl: %nAnzahl: %n Count: %n LogbookWidgetLschenDelete LogbookWidgetDDie ausgewhlten Kontakte lschen?Delete the selected contacts? LogbookWidgetQSOs Lschen Deleting QSOs LogbookWidget.eQSL-Bild herunterladenDownloading eQSL Image LogbookWidgetRJeder Stapel untersttzt bis zu 100 QSOs.#Each batch supports up to 100 QSOs. LogbookWidgetWert Bearbeiten Edit Value LogbookWidget.Ausgewhlte exportierenExport Selected LogbookWidget8Ausgewhlte QSOs exportierenExport selected QSOs LogbookWidget$Rufzeichen filternFilter Callsign LogbookWidgetGitterfeld Gridsquare LogbookWidgetIOTAIOTA LogbookWidget*Logbuch - Lschen QSOLogbook - Delete QSO LogbookWidget2Logbuch - Wert BearbeitenLogbook - Edit Value LogbookWidget2Logbuch - QSO-Spot sendenLogbook - Send DX Spot LogbookWidget&Nachschlagen im Web Lookup on Web LogbookWidget6QSL als empfangen markieren Mark QSL RCVD LogbookWidget:QSL als angefordert markierenMark QSL Requested LogbookWidget&Kein BenutzerfilterNo User Filter LogbookWidgetPOTAPOTA LogbookWidgetQLog Fehler QLog Error LogbookWidgetQLog Warnung QLog Warning LogbookWidget.QSOs Update FortschrittQSOs Update Progress LogbookWidgetSIGSIG LogbookWidgetSOTASOTA LogbookWidgetQSO-Spot senden Send DX Spot LogbookWidgetAktualisierenUpdate LogbookWidget&Update vom CallbookUpdate from Callbook LogbookWidget,Nach Clublog hochladenUpload to Clublog LogbookWidgetWWFFWWFF LogbookWidgetLWelche Spalten sollen angezeigt werden!Which columns should be displayed LogbookWidgetFeQSL-Bild download fehlgeschlagen: eQSL Download Image failed:  LogbookWidgetBKann temporre Datei nicht ffnenCannot open temporary fileLotwQSLDownloaderXFalscher Benutzername oder falsches PasswortIncorrect login or passwordLotwQSLDownloadervAlle QSOs waren Duplikate oder auerhalb des Datumsbereichs-All QSOs were duplicates or out of date range LotwUploader(Befehls-SyntaxfehlerCommand syntax error LotwUploaderLoTW Verbindungsfehler (kein Netzwerk oder LoTW nicht erreichbar)9LoTW Connection error (no network or LoTW is unreachable) LotwUploaderzEinige QSOs waren Duplikate oder auerhalb des Datumsbereichs.Some QSOs were duplicates or out of date range LotwUploaderTQSL abgestrzt TQSL crashed LotwUploader&TQSL nicht gefundenTQSL not found LotwUploader&TQSL-Utility FehlerTQSL utility error LotwUploaderTQSLib Fehler TQSLlib error LotwUploader<Kann Eingabedatei nicht ffnenUnable to open input file LotwUploader<Kann Ausgabedatei nicht ffnenUnable to open output file LotwUploader8Unerwarteter Fehler von TQSLUnexpected Error from TQSL LotwUploaderFUnerwartete Antwort vom TQSL-Server$Unexpected response from TQSL server LotwUploader>Upload vom Benutzer abgebrochenUpload cancelled by user LotwUploader6Upload durch LoTW abgelehntUpload rejected by LoTW LotwUploader &ber&About MainWindow&Awards MainWindow&Gerte &Equipment MainWindow&Exportieren&Export MainWindow &Datei&File MainWindow &Hilfe&Help MainWindow&Importieren&Import MainWindow&Logbuch&Logbook MainWindow$&Manueller Eintrag &Manual Entry MainWindowEinste&llungen &Settings MainWindow &Wiki&Wiki MainWindowFe&nster&Window MainWindow@<h1>QLog %1</h1><p>&copy; 2019 Thomas Gatzweiler DL2IC<br/>&copy; 2021-2026 Ladislav Foldyna OK1MLG<br/>&copy; 2025-2026 Michael Morgan AA5SH<br/>&copy; 2025-2026 Kyle Boyle VE9KZ</p><p>Qt %2<br/>%3<br/>%4<br/>%5</p><p>Icon by <a href='http://www.iconshock.com'>Icon Shock</a><br />Satellite images by <a href='http://www.nasa.gov'>NASA</a><br />ZoneDetect by <a href='https://github.com/BertoldVdb/ZoneDetect'>Bertold Van den Bergh</a><br />TimeZone Database by <a href='https://github.com/evansiroky/timezone-boundary-builder'>Evan Siroky</a>)

QLog %1

© 2019 Thomas Gatzweiler DL2IC
© 2021-2026 Ladislav Foldyna OK1MLG
© 2025-2026 Michael Morgan AA5SH
© 2025-2026 Kyle Boyle VE9KZ

Based on Qt %2
%3
%4
%5

Try to export your log to ADIF manually QMessageBox:Das Land darf nicht leer seinCountry must not be empty QMessageBox&DX Cluster PasswortDX Cluster Password QMessageBox8DXC Server VerbindungsfehlerDXC Server Connection Error QMessageBox.DXC Server NamensfehlerDXC Server Name Error QMessageBoxFormat der DXC-Server-Adresse <p><b>[benutzername@]hostname:Port</b> (z. B. hamqth.com:7300)</p>`DXC Server address must be in format

[username@]hostname:port (ex. hamqth.com:7300)

 QMessageBoxNMigration der Datenbank fehlgeschlagen.Database migration failed. QMessageBox2%n Kontakt(e) exportiert.Exported %n contact(s). QMessageBoxExportiert. Exported. QMessageBoxzAusstehenden Datenbankimport konnte nicht verarbeitet werden.*Failed to process pending database import. QMessageBox$Dateiname ist leerFilename is empty QMessageBoxBFiltername ist bereits vorhanden.Filter name is already exists. QMessageBoxDGitterfeld hat ein falsches Format Gridsquare has an invalid format QMessageBox0ITU darf nicht leer seinITU must not be empty QMessageBox"Falsches PasswortInvalid Password QMessageBoxSchleife erkannt. Raw-UDP-Weiterleitung verwendet denselben Port wie der WSJT-X-Empfangsport.OLoop detected. Raw UDP forward uses the same port as the WSJT-X receiving port. QMessageBox~Netzwerkfehler. Clubliste kann nicht heruntergeladen werden fr,Network error. Cannot download Club List for QMessageBoxbDas Operator-Rufzeichen hat ein ungltiges Format'Operator Callsign has an invalid format QMessageBoxtBitte definieren Sie mindestens ein Stationsstandortprofil5Please, define at least one Station Locations Profile QMessageBox,QLog kritischer Fehler QLog Critical QMessageBoxQLog Fehler QLog Error QMessageBoxQLog Info QLog Info QMessageBox QLog InformationQLog Information QMessageBoxQLog Warnung QLog Warning QMessageBox8QLog wird bereits ausgefhrtQLog is already running QMessageBox&Rig-PTT-Port muss ein gltiger COM-Port sein. Fr Windows verwenden Sie COMxx, fr Unix-hnliche Betriebssysteme verwenden Sie einen Pfad zum GertfRig PTT port must be a valid COM port.
For Windows use COMxx, for unix-like OS use a path to device QMessageBoxRig port muss ein gltiger COM-Port sein.<br>Fr Windows verwende COMxx, fr Unix-hnliche Betriebssysteme verwende einen Pfad zum GertbRig port must be a valid COM port.
For Windows use COMxx, for unix-like OS use a path to device QMessageBox(Rotor-Port muss ein gltiger COM-Port sein.<br>Fr Windows verwenden Sie COMxx, fr Unix-hnliche Betriebssysteme verwenden Sie einen Pfad zum GertfRotator port must be a valid COM port.
For Windows use COMxx, for unix-like OS use a path to device QMessageBoxJName der Regel ist bereits vorhanden.Rule name is already exists. QMessageBox&Die Datenbank wurde erfolgreich importiert, aber die gespeicherten Passwrter konnten nicht wiederhergestellt werden (Entschlsselung fehlgeschlagen oder Daten sind beschdigt). Alle Service-Passwrter wurden gelscht und mssen in den Einstellungen erneut eingegeben werden.The database was imported successfully, but the stored passwords could not be restored (decryption failed or the data is corrupted). All service passwords have been cleared and must be re-entered in Settings. QMessageBoxDie Felder <b>%0</b> werden nicht gespeichert, da <b>%1</b> nicht ausgefllt ist.KThe fields %0 will not be saved because the %1 is not filled. QMessageBoxJUnerwarteter Inhalt der Clubliste fr Unexpected Club List content for QMessageBox|Unerwartete Clubliste herunterladen. Nchste Downloads beenden7Unexpected Club List download. Canceling next downloads QMessageBoxVUCC Gitterfeld hat ein falsches Format (es mssen 2 oder 4 Gitterfelder sein, getrennt durch ',')OVUCC Grids have an invalid format (must be 2 or 4 Gridsquares separated by ',') QMessageBoxWSJTX Multicast ist aktiviert, aber die Adresse ist keine Multicast-Adresse.FWSJTX Multicast is enabled but the Address is not a multicast address. QMessageBoxIhr Rufzeichen ist nicht angegeben. Bitte richten Sie Ihr Stationsprofil ein8Your callsign is empty. Please, set your Station Profile QMessageBox.(Interner Flatpak-Pfad)(Flatpak internal path)QObject"<b>Fehler</b>: %nError(s): %nQObject@<b>Importiert</b>: %n Kontakt(e)Imported: %n contact(s)QObject(<b>Warnungen</b>: %nWarning(s): %nQObject"Datenbank sichernBackuping DatabaseQObject CW KeyCW KeyerQObjectKann keine Verbindung zum DXC Server herstellen <p>Ursache <b>: ,Cannot connect to DXC Server

Reason : QObjectBesttigt ConfirmedQObject(Verbindung abgelehntConnection RefusedQObjectHDatenbank ist keine QLog-Exportdatei Database is not QLog Export fileQObjectnDatenbankversion zu neu (erfordert neuere QLog-Version)6Database version too new (requires newer QLog version)QObjectFDer Host hat die Verbindung beendetHost closed the connectionQObject&Host nicht gefundenHost not foundQObject2Datenbank wird importiertImporting DatabaseQObjectInterner FehlerInternal ErrorQObject4Logging-Station RufzeichenLogging Station CallsignQObject&Datenbank migrierenMigrating DatabaseQObjectEigene CQZMy CQZQObjectEigene StadtMy CityQObjectEigenes Land My CountryQObject"Eigener Landkreis My CountyQObject Eigenes DARC DOK My DARC DOKQObject"Eigenes DXCC LandMy DXCCQObject$Eigenes Gitterfeld My GridsquareQObject$Eigene IOTA NummerMy IOTAQObjectEigene ITU ZoneMy ITUQObjectEigene POTA Ref My POTA RefQObjectEigener RigMy RigQObject$Eigene SOTA NummerMy SOTAQObjectREigene spezielle Interessenaktivitt InfoMy Spec. Interes Activity InfoQObjectHEigene spezielle InteressenaktivittMy Special Interest ActivityQObject.Eigenes VUCC Gitterfeld My VUCC GridsQObjectEigener WWFFMy WWFFQObjectNetzwerkfehler Network ErrorQObject8Keine gltige QLog-DatenbankNot a valid QLog databaseQObject Datenbank ffnenOpening DatabaseQObject&Operator RufzeichenOperator CallsignQObjectOperator Name Operator NameQObjectRigRigQObject RotorRotatorQObject"Anwendung startenStarting ApplicationQObjectSumme BesttigtTOTAL ConfirmedQObject Summe Gearbeitet TOTAL WorkedQObjectTQSL Pfad TQSL PathQObject$ZeitberschreitungTimeoutQObjectGearbeitetWorkedQObjectkmkmQObjectmilmilesQObjectQRZ.comQRZ.com QRZCallbook$Allgemeiner Fehler General Error QRZUploader%n QSL-Karte(n)%n QSL-Karte(n)%n QSL card(s)QSLGalleryDialog.Zu Favoriten hinzufgenAdd to FavoritesQSLGalleryDialogAlle QSL-Karten All QSL CardsQSLGalleryDialogNach BandBy BandQSLGalleryDialogNach Kontinent By ContinentQSLGalleryDialogNach Land By CountryQSLGalleryDialogNach DatumBy DateQSLGalleryDialogNach ModusBy ModeQSLGalleryDialog Rufzeichen (A-Z)Callsign (A-Z)QSLGalleryDialog Rufzeichen (Z-A)Callsign (Z-A)QSLGalleryDialogDatum (neueste) Date (Newest)QSLGalleryDialogDatum (lteste) Date (Oldest)QSLGalleryDialog,Gefilterte exportierenExport FilteredQSLGalleryDialog,QSL-Karten exportierenExport QSL CardsQSLGalleryDialog6%1 von %2 Karten exportiertExported %1 of %2 cardsQSLGalleryDialogFavoriten FavoritesQSLGalleryDialog ffnenOpenQSLGalleryDialog$QSL-Karten-GalerieQSL Card GalleryQSLGalleryDialog.Aus Favoriten entfernenRemove from FavoritesQSLGalleryDialog&QSL-Karte speichern Save QSL CardQSLGalleryDialogSpeichern &Save...QSLGalleryDialog.Nach Rufzeichen suchen &Search by callsign...QSLGalleryDialogSortieren nach:Sort by:QSLGalleryDialogDetailsDetailsQSLImportStatDialog Heruntergeladen: Downloaded:QSLImportStatDialogFehler:Errors:QSLImportStatDialogNeue QSLs:  New QSLs: QSLImportStatDialog4Zusammenfassung QSL-ImportQSL Import SummaryQSLImportStatDialogZusammenfassungSummaryQSLImportStatDialog,Nicht gefundene QSLs: Unmatched QSLs: QSLImportStatDialogNicht gefunden: Unmatched:QSLImportStatDialog(Aktualisierte QSOs: Updated QSOs: QSLImportStatDialogAktualisiert:Updated:QSLImportStatDialog"Gre To Radio :"To Radio" Size:QSLPrintLabelDialog Text To Radio :"To Radio" Text:QSLPrintLabelDialog.(Datenbank-Spaltenname)(DB column name)QSLPrintLabelDialog"Band-Header-Text:Band Header Text:QSLPrintLabelDialog,Gre des Rufzeichens:Callsign Size:QSLPrintLabelDialogSpalte:Columns:QSLPrintLabelDialog"BenutzerdefiniertCustomQSLPrintLabelDialogDatengre: Data Size:QSLPrintLabelDialogDatumsformat: Date Format:QSLPrintLabelDialog$Datum-Header-Text:Date Header Text:QSLPrintLabelDialogLeerEmptyQSLPrintLabelDialogPDF exportieren Export PDFQSLPrintLabelDialog&Als PDF exportieren Export as PDFQSLPrintLabelDialog8Text der zustzlichen SpalteExtra Column TextQSLPrintLabelDialog&Zustzliche Spalte: Extra Column:QSLPrintLabelDialog FilterFilterQSLPrintLabelDialog*Linker Fuzeilentext:Footer Left Text:QSLPrintLabelDialog,Rechter Fuzeilentext:Footer Right Text:QSLPrintLabelDialog*Horizontaler Abstand: H Spacing:QSLPrintLabelDialog"Kopfzeilen-Gre: Header Size:QSLPrintLabelDialog:Erscheinungsbild des EtikettsLabel AppearanceQSLPrintLabelDialogEtikettenhhe: Label Height:QSLPrintLabelDialog EtikettenvorlageLabel TemplateQSLPrintLabelDialog Etikettenbreite: Label Width:QSLPrintLabelDialog2Etiketten: %1 (%2 Seiten)Labels: %1 (%2 pages)QSLPrintLabelDialog.Etiketten: 0 (0 Seiten)Labels: 0 (0 pages)QSLPrintLabelDialogLinker Rand: Left Margin:QSLPrintLabelDialog,Als gesendet markieren Mark as SentQSLPrintLabelDialogdGedruckte/exportierte QSOs als gesendet markieren?#Mark printed/exported QSOs as sent?QSLPrintLabelDialog$Modus-Header-Text:Mode Header Text:QSLPrintLabelDialog$Monospace-Schrift: Mono Font:QSLPrintLabelDialog$Eigenes Rufzeichen My CallsignQSLPrintLabelDialog:Keine passenden QSOs gefundenNo matching QSOs foundQSLPrintLabelDialog&PDF-Dateien (*.pdf)PDF Files (*.pdf)QSLPrintLabelDialogSeite %1 von %2 Page %1 of %2QSLPrintLabelDialogSeite 0 von 0 Page 0 of 0QSLPrintLabelDialogSeitengre: Page Size:QSLPrintLabelDialogDruckenPrintQSLPrintLabelDialog.Etikettenrnder druckenPrint Label BordersQSLPrintLabelDialog*QSL-Etiketten druckenPrint QSL LabelsQSLPrintLabelDialog QSL-Header-Text:QSL Header Text:QSLPrintLabelDialogQSL AusgangQSL SentQSLPrintLabelDialogVQSOs, die diesem Stationsprofil entsprechen"QSOs matching this station profileQSLPrintLabelDialog"QSOs pro Etikett:QSOs per Label:QSLPrintLabelDialog Zeile:Rows:QSLPrintLabelDialog(Serifenlose Schrift: Sans Font:QSLPrintLabelDialog*Etikett berspringen: Skip Label:QSLPrintLabelDialogStationsprofilStation ProfileQSLPrintLabelDialog"Zeit-Header-Text:Time Header Text:QSLPrintLabelDialogOberer Rand: Top Margin:QSLPrintLabelDialogBenutzer-Filter User FilterQSLPrintLabelDialog&Vertikaler Abstand: V Spacing:QSLPrintLabelDialog MHzQSODetailDialog WQSODetailDialog&ContestQSODetailDialog&Details&DetailsQSODetailDialogB&earbeiten&EditQSODetailDialog&Suchen&LookupQSODetailDialog&QSL&QSLQSODetailDialog&Zurcksetzen&ResetQSODetailDialog&Speichern&SaveQSODetailDialog-QSODetailDialog*<b>DXCC-Statistik</b>DXCC StatisticsQSODetailDialog0<b>Stationsstatistik</b>Station StatisticsQSODetailDialog <b>Warnung: </b>Warning: QSODetailDialog<b>Ja</b> - eine eingehende QSL-Karte wurde angenommen; das QSO wurde vom Online-Dienst besttigt.<br/><b>Nein</b> - eine eingehende QSL-Karte wurde nicht angenommen; das QSO wurde vom Online-Dienst nicht besttigt.<br/><b>Angefordert</b> - die loggende Station hat eine QSL-Karte angefordert; die loggende Station hat verlangt, dass das QSO in den Online-Dienst hochgeladen wird.<br/>lYes - an incoming QSL card has been received; the QSO has been confirmed by the online service
No - an incoming QSL card has not been received; the QSO has not been confirmed by the online service
Requested - the logging station has requested a QSL card; the logging station has requested the QSO be uploaded to the online service
QSODetailDialog@<b>Ja</b> - eine ausgehende QSL-Karte wurde gesendet; das QSO wurde in den Online-Dienst hochgeladen und von diesem akzeptiert.<br/><b>Nein</b> - keine ausgehende QSL-Karte senden; das QSO nicht in den Online-Dienst hochladen.<br/><b>Angefordert</b> - die kontaktierte Station hat eine QSL-Karte angefordert; die kontaktierte Station hat angefordert, dass das QSO in den Online-Dienst hochgeladen wird.<br/><b>Wartend</b> - eine ausgehende QSL-Karte wurde zum Senden ausgewhlt; ein QSO wurde zum Hochladen in den Online-Dienst ausgewhlt.<br/>Yes - an outgoing QSL card has been sent; the QSO has been uploaded to, and accepted by, the online service
No - do not send an outgoing QSL card; do not upload the QSO to the online service
Requested - the contacted station has requested a QSL card; the contacted station has requested the QSO be uploaded to the online service
Queued - an outgoing QSL card has been selected to be sent; a QSO has been selected to be uploaded to the online service
QSODetailDialogAFQSODetailDialogANQSODetailDialogASQSODetailDialog AlterAgeQSODetailDialogAntenneAntennaQSODetailDialogBandQSODetailDialogAuf Grundlage der SOTA-Daten stimmt das QTH nicht mit dem SOTA Gipfelname berein - erwartend FBased on SOTA Summit, QTH does not match SOTA Summit Name - expecting QSODetailDialogLeerBlankQSODetailDialogBroBureauQSODetailDialogCQQSODetailDialog"Callbook-Fehler: Callbook error: QSODetailDialogRufzeichenCallsignQSODetailDialogAbbrechenCancelQSODetailDialogEs knnen nicht alle nderungen gespeichert werden - interner Fehler(Cannot save all changes - internal errorQSODetailDialogEs knnen nicht alle nderungen gespeichert werden - versuchen Sie, alle nderungen zurckzusetzen2Cannot save all changes - try to reset all changesQSODetailDialogKommentarCommentQSODetailDialogKontinentContQSODetailDialogContest ID Contest IDQSODetailDialogLandCountryQSODetailDialogLandkreisCountyQSODetailDialogD&X Stats D&X StatsQSODetailDialogDOKQSODetailDialogDDX-Rufzeichen darf nicht leer seinDX Callsign must not be emptyQSODetailDialogRDX Gitterfeld hat ein fehlerhaftes FormatDX Grid has an incorrect formatQSODetailDialogJDX-Rufzeichen hat ein falsches Format#DX callsign has an incorrect formatQSODetailDialogEin Datum sollte fr LoTW Sent Status <b>Ja</b> angegeben werden6Date should be present for LoTW Sent Status YesQSODetailDialogEin Datum sollte fr Papier Sent Status <b>Ja</b> angegeben werden7Date should be present for Paper Sent Status YesQSODetailDialogEin Datum sollte fr eQSL Sent Status <b>Ja</b> angegeben werden6Date should be present for eQSL Sent Status YesQSODetailDialog DirektDirectQSODetailDialog.eQSL-Bild herunterladenDownloading eQSL ImageQSODetailDialogE-MailQSODetailDialogEUQSODetailDialogQSO BearbeitenEdit QSOQSODetailDialogElektronisch ElectronicQSODetailDialog FISTSFISTSQSODetailDialogFrequenz FrequencyQSODetailDialogGitterfeld GridsquareQSODetailDialogIOTAQSODetailDialogITUQSODetailDialogIgnoriertIgnoredQSODetailDialogLoTWLoTWQSODetailDialog0LoTW Sent Status <b>Nein</b> macht keinen Sinn, wenn ein QSL Sent Datum gesetzt ist. Setzen Sie das Datum auf 1.1.1900, um das Datumsfeld leer zu lassenLoTW Sent Status to No does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blankQSODetailDialog&Eigene Station M&y StationQSODetailDialog&QSL-Karte verwaltenManage QSL CardQSODetailDialogMitglied:Member:QSODetailDialogBetriebsartModeQSODetailDialog$Eigene AnmerkungenMy NotesQSODetailDialogNAQSODetailDialogNameNameQSODetailDialogNeinNoQSODetailDialogOCQSODetailDialog&Operator RufzeichenOperator CallsignQSODetailDialogOperator Name Operator NameQSODetailDialogNEigenes Rufzeichen darf nicht leer seinOwn Callsign must not be emptyQSODetailDialogfEigenes VUCC Gitterfeld hat ein fehlerhaftes Format'Own VUCC Grids have an incorrect formatQSODetailDialog\Eigenes Rufzeichen hat ein fehlerhaftes Format$Own callsign has an incorrect formatQSODetailDialogPOTAQSODetailDialog PapierPaperQSODetailDialog4Papier Sent Status <b>Nein</b> macht keinen Sinn, wenn ein QSL Sent Datum gesetzt ist. Setzen Sie das Datum auf 1.1.1900, um das Datumsfeld leer zu lassenPaper Sent Status to No does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blankQSODetailDialogLeistungPowerQSODetailDialog"AusbreitungsmodusPropagation ModeQSODetailDialogQLog Fehler QLog ErrorQSODetailDialogQSL Ausgang via QSL Sent viaQSODetailDialogQSL viaQSODetailDialogQSL-Nachricht QSLs MessageQSODetailDialogQSO Detail QSO DetailQSODetailDialogQTHQSODetailDialogWartendQueuedQSODetailDialogRSTeRSTrQSODetailDialogRSTaRSTsQSODetailDialog(RX-Band sollte sein RX Band should be QSODetailDialogRX: QSODetailDialogInfo erhaltenRcvExchQSODetailDialogNr. erhaltenRcvNrQSODetailDialogJWirklich alle nderungen bermitteln?Really submit all changes?QSODetailDialogEingangReceivedQSODetailDialogAngefordert RequestedQSODetailDialogRigQSODetailDialogSAQSODetailDialogSIGQSODetailDialogSIG InfoQSODetailDialogSKCCSKCCQSODetailDialogSOTAQSODetailDialogNDer Satellitenname darf nicht leer seinSat name must not be emptyQSODetailDialog(Satellit-BetriebsartSatellite ModeQSODetailDialogSatellit-NameSatellite NameQSODetailDialogInfo gesendetSendExchQSODetailDialogNr. gesendetSendNrQSODetailDialogAusgangSentQSODetailDialog"QSL-Karte ansehen Show QSL CardQSODetailDialogSig InfoQSODetailDialog StaatStateQSODetailDialog,nderungen bermittelnSubmit changesQSODetailDialog(TX-Band sollte sein TX Band should be QSODetailDialogVTX-Frequenz oder -Band muss ausgefllt sein#TX Frequency or Band must be filledQSODetailDialogTX: QSODetailDialogTen-TenTen-TenQSODetailDialogEndzeitTime OffQSODetailDialogStartzeitTime OnQSODetailDialog UKSMGUKSMGQSODetailDialogURLQSODetailDialogVUCCQSODetailDialog@VUCC hat ein fehlerhaftes FormatVUCC has an incorrect formatQSODetailDialogberprfung ValidationQSODetailDialogWWFFQSODetailDialogGelb markierte Felder sind ungltig.<p>Dennoch die nderungen speichern?</p>GYellow marked fields are invalid.

Nevertheless, save the changes?

QSODetailDialogJaYesQSODetailDialog about:blankQSODetailDialogLeerblankQSODetailDialogdd/MM/yyyy HH:mm:ssQSODetailDialogeQSLeQSLQSODetailDialogFeQSL-Bild download fehlgeschlagen: eQSL Download Image failed: QSODetailDialog0eQSL Sent Status <b>Nein</b> macht keinen Sinn, wenn ein QSL Sent Datum eingestellt ist. Setzen Sie Datum auf 1.1.1900, um das Datumsfeld leer zu lasseneQSL Sent Status to No does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blankQSODetailDialogDARC-DOK (Ortsverbandkenner) der kontaktierten Station (z.B. A01)Cthe contacted station's DARC DOK (District Location Code) (ex. A01)QSODetailDialogzwei oder vier nebeneinander liegende, jeweils vier Zeichen lange Gitterfelder (z. B. EN98,FM08,EM97,FM07)Vtwo or four adjacent Gridsquares, each four characters long, (ex. EN98,FM08,EM97,FM07)QSODetailDialog(Bedingung hinzufgen Add ConditionQSOFilterDetail4Alle folgenden BedingungenAll the following conditionsQSOFilterDetail<Eine der folgenden BedingungenAny of the following conditionsQSOFilterDetailenthltContainsQSOFilterDetail gleichEqualQSOFilterDetailFilter Name: Filter Name:QSOFilterDetail2QSO mit Suchfilter findenFind QSO which matchQSOFilterDetailgrer als Greater ThanQSOFilterDetailkleiner als Less ThanQSOFilterDetail(Darf nicht leer seinMust not be emptyQSOFilterDetailenthlt nicht Not ContainsQSOFilterDetailnicht gleich Not EqualQSOFilterDetail$QSO Filter DetailsQSO Filter DetailQSOFilterDetailEntfernenRemoveQSOFilterDetailbeginnt mit Starts withQSOFilterDetailHinzufgenAddQSOFilterDialogBearbeitenEditQSOFilterDialog FilterFiltersQSOFilterDialogQSO-Filter QSO FiltersQSOFilterDialogEntfernenRemoveQSOFilterDialog*Kann Rig nicht ffnenCannot open RigRig,InitialisierungsfehlerInitialization ErrorRigInterner FehlerInternal ErrorRig4Kein Rig-Profil ausgewhltNo Rig Profile selectedRigRigctld-Fehler Rigctld ErrorRig MHz MHz RigWidget$Split deaktivieren Disable Split RigWidgetNicht verbunden Disconnected RigWidgetForm RigWidgetPWR: %1W RigWidgetRIT: 0.00000 MHz RigWidgetRX RigWidgetXIT: 0.00000 MHz RigWidget,Zustzliche Argumente:Additional Arguments:RigctldAdvancedDialog Alle Dateien (*) All files (*)RigctldAdvancedDialog,Automatische Erkennung Auto DetectRigctldAdvancedDialog,Automatische Erkennung Auto-DetectRigctldAdvancedDialogBRigctld-Pfad automatisch erkennenAuto-detect Rigctld pathRigctldAdvancedDialogDurchsuchenBrowseRigctldAdvancedDialog4Kann nicht gendert werdenCannot be changedRigctldAdvancedDialogZAusfhrbare Datei (*.exe);;Alle Dateien (*.*)#Executable (*.exe);;All files (*.*)RigctldAdvancedDialogLLeer lassen fr automatische ErkennungLeave empty for auto-detectionRigctldAdvancedDialogNicht gefunden Not foundRigctldAdvancedDialog@Erweiterte Rigctld-EinstellungenRigctld Advanced SettingsRigctldAdvancedDialogRigctld-Pfad: Rigctld Path:RigctldAdvancedDialog Rigctld-Version:Rigctld Version:RigctldAdvancedDialogFRigctld ausfhrbare Datei auswhlenSelect rigctld executableRigctldAdvancedDialogXz. /B. -v -v fr ausfhrliche Protokollierunge.g. -v -v for verbose loggingRigctldAdvancedDialogrigctld wurde auf diesem System nicht gefunden. Bitte installieren Sie Hamlib oder geben Sie den Pfad manuell an.Yrigctld was not found on this system. Please install Hamlib or specify the path manually.RigctldAdvancedDialogXRigctld konnte nicht gestartet werden: %1 %2Failed to start rigctld: %1 %2RigctldManagerLHamlib-Hauptversionskonflikt: QLog wurde mit Hamlib %1 kompiliert, aber rigctld meldet Version %2.%3.%4. Rig-Modell-IDs sind zwischen Hauptversionen nicht kompatibel.Hamlib major version mismatch: QLog was compiled with Hamlib %1 but rigctld reports version %2.%3.%4. Rig model IDs are incompatible between major versions.RigctldManagerPort %1 wird bereits verwendet. Ein anderer rigctld oder eine Anwendung luft mglicherweise auf diesem Port.VPort %1 is already in use. Another rigctld or application may be running on this port.RigctldManager0Lese Fehler bei rigctld.Read error with rigctld.RigctldManager6Unbekannter rigctld-Fehler.Unknown rigctld error.RigctldManager4Schreibfehler bei rigctld.Write error with rigctld.RigctldManager.rigctld ist abgestrzt.rigctld crashed.RigctldManagerRigctld-Ausfhrbare Datei wurde in /app/bin/ nicht gefunden. Dies sollte im Flatpak-Build nicht passieren.Srigctld executable not found in /app/bin/. This should not happen in Flatpak build.RigctldManagerRigctld-Ausfhrbare Datei wurde nicht gefunden. Bitte installieren Sie Hamlib oder geben Sie den Pfad in den erweiterten Einstellungen an.]rigctld executable not found. Please install Hamlib or specify the path in Advanced settings.RigctldManagerrRigctld wurde gestartet, reagiert aber nicht auf Port %1..rigctld started but not responding on port %1.RigctldManagerXrigctld hat die Zeitberschreitung erreicht.rigctld timed out.RigctldManager.Kann Rotor nicht ffnenCannot open RotatorRotator,InitialisierungsfehlerInitialization ErrorRotatorInterner FehlerInternal ErrorRotator8Kein Rotor-Profil ausgewhltNo Rotator Profile selectedRotatorAz: RotatorWidgetForm RotatorWidgetGoto RotatorWidget*Nchstes TastenprofilNext Button Profile RotatorWidget.Vorheriges TastenprofilPrevious Button Profile RotatorWidgetQSO LP RotatorWidget QSO Long Path RotatorWidgetQSO SP RotatorWidgetQSO Short Path RotatorWidget° RotatorWidget MHzSettingsDialog Profile ProfilesSettingsDialog WSettingsDialog WPMSettingsDialog msSettingsDialog--SettingsDialog1SettingsDialog 115200115200SettingsDialog12001200SettingsDialog 1920019200SettingsDialog22SettingsDialog24-Stunden24-hourSettingsDialog24002400SettingsDialog 3840038400SettingsDialog48004800SettingsDialog5SettingsDialog 5760057600SettingsDialog66SettingsDialog77SettingsDialog88SettingsDialog96009600SettingsDialog*<DXCALL> = DX Rufzeichen <NAME> = DX Operator Name <RST> = Report 599 <RSTN> = Report 5NN <GREETING> = Grussformel GM/GA/GE <QTH> = QTH <MYCALL> = Eigenes Rufzeichen <MYNAME> = Eigener Name <MYQTH> = Eigenes QTH <MYLOCATOR> = Eigenes Gitterfeld <MYSIG> = Eigenes SIG <MYSIGINFO> = Eigene SIG Information <MYIOTA> = Eigenes IOTA <MYSOTA> = Eigenes SOTA <MYWWFT> = Eigenes WWFT <MYVUCC> = Eigenes VUCC <MYPWR> = Eigene Leistung in W <EXCHSTR> = Contest Exchange <EXCHNR> = Contest Exchange Serial Number <EXCHNRN> = Contest Exchange Serial Number (9!N, 0!T) <+> = Geschwindigkeit +5 WPM (<++> = +10 WPM, usw.) <-> = Geschwindigkeit -5 WPM (<--> = -10 WPM, usw.) g = DX Callsign = DX Operator Name = Report 599 = Report 5NN = Greenting GM/GA/GE = QTH = My Callsign = My Name = My QTH = My Gridsquare = My Gridsquare = My SIG = My SIG Information = My IOTA = MY SOTA = My WWFT = MY VUCC = My Power in W = Contest Exchange Message = Contest Exchange Serial Number = Contest Exchange Serial Number (9→N, 0→T) <+> = Speed +5 WPM (<++> = +10 WPM, etc.) <-> = Speed -5 WPM (<--> = -10 WPM, etc.) SettingsDialog<a href="https://doc.qt.io/qt-6/qdate.html#fromString-1">Dokumentation des Zeitformats</a>VTime Format DocumentationSettingsDialog<b>Notiz:</b> Es wird empfohlen, mindestens ein QRZ-XML-Abonnement abzuschlieen, um detaillierte Informationen zu erhalten. Ohne ein Abonnement erhalten Sie nur begrenzte Daten von QRZ, z. B. Gitterfeld und andere Felder.Notice: At least a QRZ XML Subscription is recommended to access detailed information. Without a subscription, you will obtain limited data from QRZ, such as missing grid and other fields.SettingsDialog<b>Sicherheitshinweis:</b> QLog speichert alle Passwrter im Secure Storage. Leider verwendet ON4KST ein Protokoll, bei dem dieses Passwort ber einen ungesicherten Kanal im Klartext gesendet wird.</p><p>Bitte seien Sie vorsichtig, wenn Sie Ihr Passwort fr diesen Dienst whlen, da Ihr Passwort ber einen ungesicherten Kanal im Klartext gesendet wird.</p>HSecurity Notice: QLog stores all passwords in the Secure Storage. Unfortunately, ON4KST uses a protocol where this password is sent over an unsecured channel as plaintext.

Please exercise caution when choosing your password for this service, as your password is sent over an unsecured channel in plaintext form.

SettingsDialogp<b>& Dies ist eine Gefahrenzone. Gehen Sie vorsichtig vor, da die ausgefhrten Aktionen nicht rckgngig gemacht werden knnen und erhebliche Auswirkungen auf Ihr Log haben knnen.</b>⚠ This is a danger zone. Proceed with caution, as actions performed here cannot be undone and may have a significant impact on your log.SettingsDialog<p>Liste der IP-Adressen, an die QLog UDP-Benachrichtigungspakete ber ein neues/aktualisiertes/gelschtes QSO im Log sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT

List of IP addresses to which QLog sends UDP notification packets about a new/updated/deleted QSO in the log.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialogf<p>Liste der IP-Adressen, an die QLog UDP-Benachrichtigungspakete ber User Spot Alerts sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT

List of IP addresses to which QLog sends UDP notification packets about user Spot Alerts.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialog\<p>Liste der IP-Adressen, an die QLog UDP-Notification-Pakete mit DX Cluster Spots sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT

List of IP addresses to which QLog sends UDP notification packets with DX Cluster Spots.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialog`<p>Liste der IP-Adressen, an die QLog UDP-Benachrichtigungspakete mit WSJTX CQ Spots sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT

List of IP addresses to which QLog sends UDP notification packets with WSJTX CQ Spots.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialogX<p>Liste der IP-Adressen, an die QLog UDP-Benachrichtigungspakete mit Rig-Status sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT

List of IP addresses to which QLog sends UDP notification packets when Rig State changes.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialog<p>Zugeordnete LogID fr das aktuelle Protokoll.</p>Die LogID wird in den Netzwerk-Notifizierungsmeldungen als eindeutige Instanzkennung gesendet.<p>Die ID wird automatisch generiert und kann nicht gendert werden</>

Assigned LogID to the current log.

The LogID is sent in the Network Nofitication messages as a unique instance identified.

The ID is generated automatically and cannot be changedSettingsDialogN<p>Liste der IP-Adressen, an die QLog unbearbeitete UDP WSJT-X-Pakete weiterleitet.</p>Die IP-Adressen werden durch ein Leerzeichen getrennt und haben die Form IP:PORT

List of IP addresses to which QLog forwards raw UDP WSJT-X packets.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialog AM/PMAM/PMSettingsDialogAPI-SchlsselAPI KeySettingsDialogAktive Listen Active ListsSettingsDialogHinzufgenAddSettingsDialogErweitert & Advanced...SettingsDialog>Alle Passwrter wurden gelschtAll passwords have been deletedSettingsDialogAntennenAntennasSettingsDialog*Zugeordneter CW-KeyerAssigned CW KeyerSettingsDialogAutomatischAutoSettingsDialog,Automatische Erkennung Auto DetectSettingsDialog,Automatische Erkennung Auto-DetectSettingsDialog<TQSL-Pfad automatisch erkennenAuto-detect TQSL pathSettingsDialogAzimuth Beamwidth SettingsDialogAzimuth OffsetSettingsDialog BnderBandsSettingsDialogBaudrateBaudrateSettingsDialogLeerBlankSettingsDialogDurchsuchenBrowseSettingsDialogTaste 1Button 1SettingsDialogTaste 2Button 2SettingsDialogTaste 3Button 3SettingsDialogTaste 4Button 4SettingsDialogCIV AddrCIV AddrSettingsDialogCQZCQZSettingsDialogCW-Keyer WPMCW Keyer SpeedSettingsDialogCW-Keyer CW KeyersSettingsDialog4CW Funktionstasten ProfileCW Shortcut ProfilesSettingsDialogWPM-Sync CW Speed SyncSettingsDialogCWDaemonSettingsDialogCallbookSettingsDialogRufzeichenCallsignSettingsDialog2Rufzeichen (erforderlich)Callsign (Mandatory parameter)SettingsDialogRufzeichen des Operators (Optionale Angabe, falls es vom Stationsrufzeichen abweicht)MCallsign of operator (Optional parameter, if different from station callsign)SettingsDialogpAPI-Schlssel, die auf das Rufzeichen zugeschnitten sindCallsign-specific API KeysSettingsDialog4Kann nicht gendert werdenCannot be changedSettingsDialogChatSettingsDialogClubLogSettingsDialogClubsSettingsDialog$CQ-Spots einfrbenColor CQ SpotsSettingsDialogLandCountrySettingsDialogLandkreisCountySettingsDialog"BenutzerdefiniertCustomSettingsDialogDOKDOKSettingsDialogDTRDTRSettingsDialogDX SpotsSettingsDialog DX-Spots zum RigDX Spots to RigSettingsDialogDXCCSettingsDialogGefahrenzone Danger ZoneSettingsDialogDaten Bit Data BitsSettingsDialogDatumsformat Date FormatSettingsDialog,Standard-API-SchlsselDefault API KeySettingsDialog2Standard-Ausgangsleistung Default PWRSettingsDialogStandard WPM Default SpeedSettingsDialogLschenDeleteSettingsDialogbAlle Passwrter aus dem sicheren Speicher lschen*Delete All Passwords from the Secure StoreSettingsDialog"Alle QSOs lschenDelete All QSOsSettingsDialog$Passwrter lschenDelete PasswordsSettingsDialog8Alle QSOs werden gelscht...Deleting all QSOs...SettingsDialogBeschreibung DescriptionSettingsDialogInaktivDisabledSettingsDialogDummySettingsDialog E-MailE-MailSettingsDialoglAktivieren/Deaktivieren der Multicast-Option fr WSJTX)Enable/Disable Multicast option for WSJTXSettingsDialogSenden farbcodierter Statusindikatoren fr jede CQ-rufende Station zurck an WSJT-X aktivieren/deaktivieren`Enable/Disable sending color-coded status indicators back to WSJT-X for each callsign calling CQSettingsDialogEnde (MHz) End (MHz)SettingsDialogEndpunktEndpointSettingsDialogStandard-Ausgangsleistung eingeben (z.B. wenn der Rig nicht verbunden ist)0Enter default PWR (ex. when Rig is disconnected)SettingsDialogFEingabe RIT oder Transverter Offset(Enter manually RIT or Transverter OffsetSettingsDialogFEingabe XIT oder Transverter Offset(Enter manually XIT or Transverter offsetSettingsDialog Gerte EquipmentSettingsDialog FehlerErrorSettingsDialogEvenSettingsDialogF1F1SettingsDialogF2F2SettingsDialogF3F3SettingsDialogF4F4SettingsDialogF5F5SettingsDialogF6F6SettingsDialogF7F7SettingsDialogFLDigiSettingsDialogPAlle QSOs konnten nicht gelscht werden.Failed to delete all QSOs.SettingsDialog Flow ControlSettingsDialogFrequenzFreqSettingsDialogGUIGUISettingsDialogGitterfeld GridsquareSettingsDialog HRDLogHRDLogSettingsDialogdHamLib untersttzt keine nderung eines Zielports.5HamLib does not support to change a destination port.SettingsDialogHamQTHSettingsDialogHardwareSettingsDialogHighHighSettingsDialog Host NameSettingsDialogIAMBIC ASettingsDialogIAMBIC BSettingsDialogIOTASettingsDialogIOTA (optional)IOTA (Optional parameter)SettingsDialogITUITUSettingsDialogWenn es aktiviert ist und Rig angeschlossen ist, sendet QLog regelmig On-Air-Nachrichten an HRDLog\If it is enabled and Rig is connected then QLog periodically sends On-Air messages to HRDLogSettingsDialogSofort-UploadImmediately UploadSettingsDialogImperialImperialSettingsDialogInterface InterfaceSettingsDialogDas ist kein Passwort. Es handelt sich um den Upload-Code, den sie nach der Registrierung bei HRDLOG.net per E-Mail erhalten habendIt is not a password. It is the upload code received via email after the registration to HRDLOG..netSettingsDialog&Multicast verbindenJoin MulticastSettingsDialogKeyer Modus Keyer ModeSettingsDialogKeyer ProfileKeyer ProfilesSettingsDialogLLeer lassen fr automatische ErkennungLeave empty for auto-detectionSettingsDialog<Liste der verfgbaren AntennenList of all available AntennasSettingsDialog<Liste der verfgbaren CW KeyerList of all available CW KeyersSettingsDialog^Liste der verfgbaren CW Funktionstastenprofile+List of all available CW Shortcuts ProfilesSettingsDialog4Liste der verfgbaren RigsList of all available RigsSettingsDialogLListe der verfgbaren Stations-Profile&List of all available Station ProfilesSettingsDialogLoTWLoTWSettingsDialogLogIDSettingsDialogLowLowSettingsDialogMarkSettingsDialogMetrischMetricSettingsDialogNiedrigste und hchste Sendefrequenzen. Die spezifischen Bereiche ergeben sich aus dem zulssigen Band in der Einstellung.aMinimum and maximum TX frequencies. Specific ranges are derived from allowed Band in the Setting.SettingsDialogBetriebsartModeSettingsDialog ModellModelSettingsDialogBetriebsartenModesSettingsDialog ndernModifySettingsDialogCW-ber-CATMorse Over CATSettingsDialog"Multicast AdresseMulticast AddressSettingsDialog(Darf nicht leer seinMust not be emptySettingsDialogN/ASettingsDialogNameNameSettingsDialogNetzwerkNetworkSettingsDialogNoSettingsDialogNoneSettingsDialogNicht gefunden Not foundSettingsDialog$Benachrichtigungen NotificationsSettingsDialogOddSettingsDialog OffsetOffsetsSettingsDialog&Operator RufzeichenOperator CallsignSettingsDialogOperator Name Operator NameSettingsDialog0Operator-Name (optional)"Operator name (Optional parameter)SettingsDialog AndereOthersSettingsDialogPOTASettingsDialogPTT PortPTT PortSettingsDialogPTT Status PTT StateSettingsDialogPTT TypPTT TypeSettingsDialog PapierPaperSettingsDialogParitySettingsDialogPasswortPasswordSettingsDialog Poll IntervalSettingsDialogPortSettingsDialogPort SettingsDialogPort Typ Port TypeSettingsDialogPort, an dem QLog auf eingehenden Datenverkehr von WSJT-X wartet7Port where QLog listens an incoming traffic from WSJT-XSettingsDialogLeistungPowerSettingsDialogDrcken Sie <b>ndern</b>, um die Profilnderungen zu besttigen oder <b>Abbrechen</b>.DPress Modify to confirm the profile changes or Cancel.SettingsDialog PrimrPrimarySettingsDialogProfilname Profile NameSettingsDialogProfilname, der als Alias fr Rufzeichen, QTH-Locator, Operator-Name und QTH verwendet wird (erforderlich) qProfile name that is used as the alias for the Callsign, Gridsquare, Operator name, and QTH (required parameter) SettingsDialogProfileProfilesSettingsDialogQRZ.comSettingsDialogQSO nderungen  QSO Changes SettingsDialog<QSOs werden sofort hochgeladenQSOs are uploaded immediatelySettingsDialog QSY WipingSettingsDialogQTHSettingsDialog&QTH Name (optional)QTH Name (Optional parameter)SettingsDialog.Reihenfolge der Abfrage Query OrderSettingsDialogRTSRTSSettingsDialogRX Offset (RIT)SettingsDialog4UDP Rohdaten-WeiterleitungRaw UDP ForwardSettingsDialogBerichtReportSettingsDialogjErfordert Internetverbindung beim Start der Anwendung5Required internet connection during application startSettingsDialogRig Merkmale Rig FeaturesSettingsDialogRig-PortRig PortSettingsDialogRig-Status Rig StatusSettingsDialogrRig-Freigabe ist fr Netzwerkverbindungen nicht verfgbar3Rig sharing is not available for network connectionSettingsDialogjRig-Freigabe ist nur fr den Hamlib-Treiber verfgbar/Rig sharing is only available for Hamlib driverSettingsDialogRigsSettingsDialogRotorenRotatorsSettingsDialogSAT BetriebsartSAT ModeSettingsDialogSIGSettingsDialogSIG (optional).SIG (Optional parameter).SettingsDialogSIG InfoSettingsDialog4SIG Information (optional)$SIG Information (Optional parameter)SettingsDialogSOTASettingsDialogSOTA (optional)SOTA (Optional parameter)SettingsDialogSekundr SecondarySettingsDialogDatei auswhlen Select FileSettingsDialogOn-Air senden Send On-AirSettingsDialog SerialSerialSettingsDialogEinstellungenSettingsSettingsDialog.Rig ber Port freigebenShare Rig via portSettingsDialoghKurzbeschreibung der Schaltflche (bis zu 7 Zeichen).Short Desciption of the Button (up to 7 chars)SettingsDialog$Sidetone-Frequenz:Sidetone Freq:SettingsDialog Single PaddleSettingsDialogSoftwareSettingsDialogSpaceSettingsDialog"Special - OmnirigSpecial - OmnirigSettingsDialog:Geben Sie die Multicast-Adresse an. <br>Auf einigen Linux-Systemen kann es erforderlich sein, Multicast auf der Loopback-Netzwerkschnittstelle zu aktivieren.Specify Multicast Address.
On some Linux systems it may be necessary to enable multicast on the loop-back network interface.SettingsDialogGeben Sie die URL an, die fr die Schnellsuche verwendet werden soll. Das Makro <DXCALL> wird durch das aktuelle Rufzeichen ersetztdSpecify the URL to use for quick search. The macro will be replaced by the current callsignSettingsDialog Spot AlertsSettingsDialogBeginn (MHz) Start (MHz)SettingsDialogRigctld-Daemon starten, um das Rig mit anderen Anwendungen zu teilen (z. /B. WSJT-X)GStart rigctld daemon to share rig with other applications (e.g. WSJT-X)SettingsDialog StaatStateSettingsDialogStationStationSettingsDialog4Logging Station RufzeichenStation CallsignSettingsDialogDStations-Gitterfeld (erforderlich)(Station Gridsquare (Mandatory parameter)SettingsDialogBesttigt durchStatus Confirmed BySettingsDialog Stop BitsSettingsDialog&Paddles vertauschen Swap PaddlesSettingsDialog Sync && QSLSettingsDialog SystemSystemSettingsDialogTQSL Pfad TQSL PathSettingsDialogTQSL-Version TQSL VersionSettingsDialogTQSL wurde auf diesem System nicht gefunden. Bitte installieren Sie TQSL oder geben Sie den Pfad manuell an.TTQSL was not found on this system. Please install TQSL or specify the path manually.SettingsDialogTTLSettingsDialogTX Offset (XIT)SettingsDialog$TX FrequenzbereichTX RangeSettingsDialogTestSettingsDialogNPrfen Sie die URL mit Ihrem RufzeichenTest URL with your CallsignSettingsDialogDas Zeichen >  wird als Markierung fr die anfngliche Cursorposition in der Spalte Report  interpretiert.<br/>Beispiel: 5>9  bedeutet, dass sich der Cursor auf dem zweiten Zeichen befindetThe '>' character is interpreted as a marker for the initial cursor position in the Report column.
Ex.: '5>9' means the cursor will be positioned on the second characterSettingsDialogZeitformat Time FormatSettingsDialogTime-To-Live bestimmt den Bereich<br>, ber den ein Multicast-Paket in Ihrem Intranet verbreitet wird. dTime-To-Live determines the range
over which a multicast packet is propagated in your intranet. SettingsDialogURLSettingsDialogUltimateSettingsDialogEinheitensystem Unit SystemSettingsDialogUnbestimmt UnspecifiedSettingsDialogUpload Code Upload CodeSettingsDialogVerwende COMxx fr Windows oder den Pfad zum COM-Anschluss unter Unix-hnlichen Betriebssystemen;Use COMxx for Window or path to COM port under Unix-like OSSettingsDialog.Funktionstasten ProfileUser Buttons ProfilesSettingsDialogBenutzernameUsernameSettingsDialog<Verwendung einer internen TQSLUsing an internal TQSL instanceSettingsDialogVFOSettingsDialogVUCCSettingsDialogpVUCC Gitterfelder (optional). Beisp. EN98,FM08,EM97,FM079VUCC Grids (Optional parameter). Ex. EN98,FM08,EM97,FM07SettingsDialog`Gltiger Wertebereich: 0 - 100 (0 unbestimmt)2Valid range value is 0° - 100° (0° Unspecified)SettingsDialogWWFFSettingsDialogWavelogWavelogSettingsDialog,Schaltflche Web SucheWeb Lookup ButtonSettingsDialog WinKeyWinKeySettingsDialogFWorld Wide Flora & Fauna (optional)-World Wide Flora & Fauna (Optional parameter)SettingsDialog WsjtxWsjtxSettingsDialogWsjtx CQ SpotsSettingsDialogeQSLSettingsDialog%ex. 192.168.1.1:1234 192.168.2.1:1234SettingsDialogMitgliedermembersSettingsDialog°SettingsDialog`Konflikt mit einer eingebauten Tastenkombination!Conflict with a built-in shortcutShortcutEditorModelpKonflikt mit einer benutzerdefinierten Tastenkombination%Conflict with a user-defined shortcutShortcutEditorModelBeschreibung DescriptionShortcutEditorModel"TastenkombinationShortcutShortcutEditorModel$QSOs zum HochladenQSOs to UploadShowUploadDialog Ausgewhlte QSOs Selected QSOShowUploadDialogHochladenUploadShowUploadDialog SuchenSearchSmartSearchBoxAlleAllStatisticsWidgetBandBandStatisticsWidgetGrossfelderBig GridsquaresStatisticsWidget6Besttigt / nicht BesttigtConfirmed / Not ConfirmedStatisticsWidgetBesttigt durch Confirmed byStatisticsWidgetJBesttigte / gearbeitete GitterfelderConfirmed/Worked GridsStatisticsWidgetKontinent ContinentStatisticsWidget Lnder CountriesStatisticsWidgetDatumsbereich Date RangeStatisticsWidgetWochentag Day in WeekStatisticsWidgetEntfernungDistanceStatisticsWidgetFreFriStatisticsWidgetDiagramm-Typ Graph TypeStatisticsWidgetHistogramm HistogramStatisticsWidget StundeHourStatisticsWidgetLoTWLoTWStatisticsWidgetBetriebsartModeStatisticsWidgetMonMonStatisticsWidget MonatMonthStatisticsWidgetEigene Antenne My AntennaStatisticsWidget$Eigenes Rufzeichen My CallsignStatisticsWidget$Eigenes Gitterfeld My GridsquareStatisticsWidgetEigener RigMy RigStatisticsWidget&Kein BenutzerfilterNo User FilterStatisticsWidgetNicht angegeben Not specifiedStatisticsWidgetODXODXStatisticsWidget4ber 50000 QSOs. Anzeigen?Over 50000 QSOs. Display them?StatisticsWidget PapierPaperStatisticsWidgetProzentPercentsStatisticsWidget"AusbreitungsmodusPropagation ModeStatisticsWidgetQSOsStatisticsWidgetQSOs proQSOs perStatisticsWidget"Rendern der QSOs &Rendering QSOs...StatisticsWidgetSaSatStatisticsWidget"Auf Karte ansehen Show on MapStatisticsWidgetStatistik StatisticsStatisticsWidgetSonSunStatisticsWidgetDonThuStatisticsWidgetTop 10StatisticsWidgetDieTueStatisticsWidgetBenutzer-Filter User FilterStatisticsWidgetMitWedStatisticsWidgetJahrYearStatisticsWidgeteQSLeQSLStatisticsWidgetbistoStatisticsWidget$Fehler aufgetretenError Occurred TCIRigDrv Rig 0Rig 0 TCIRigDrv Rig 1Rig 1 TCIRigDrv Rig 2Rig 2 TCIRigDrv Rig 3Rig 3 TCIRigDrv&Rig nicht verbundenRig is not connected TCIRigDrv&Rig-Status gendertRig status changed TCIRigDrvLeerBlankTimestampFormatDelegateNachrichtMessageToAllTableModelSpotterToAllTableModelZeitTimeToAllTableModel&Hochladen&UploadUploadQSODialogIrgendeinAnyUploadQSODialogRufzeichenCallsignUploadQSODialogAbbrechenCancelUploadQSODialogRQSO-Status kann nicht aktualisiert werdenCannot update QSO StatusUploadQSODialog:Kann QSO(s) nicht hochladen: Cannot upload the QSO(s): UploadQSODialogRClublog lschen und QSOs erneut hochladenClear Clublog and reupload QSOsUploadQSODialogClublogClublogUploadQSODialogKommentarCommentUploadQSODialog FilterFiltersUploadQSODialogGitterfeld GridsquareUploadQSODialog HRDLogHRDLogUploadQSODialog$QSOs ausblenden... Hide QSOs...UploadQSODialogIgnorierenIgnoreUploadQSODialog(QSOs mit SendestatusInclude QSOs StatusUploadQSODialogLoTWLoTWUploadQSODialogLoTW / TQSL LoTW / TQSLUploadQSODialogStandortrufzeichen (%1) und Grid (%2) stimmen nicht mit den ausgewhlten Filtern bereinBLocation callsign (%1) and grid (%2) do not match selected filtersUploadQSODialogStandortrufzeichen (%1) stimmt nicht mit dem ausgewhlten Rufzeichen (%2) berein Bitte verwende den <b>Einstellungen</b> Dialog, um es einzurichten.</p>^Service is not configured properly.

Please, use Settings dialog to configure it.

UploadQSODialog QSOs anzeigen... Show QSOs...UploadQSODialogStationsprofilStation ProfileUploadQSODialogStationsprofilStation Profile IDUploadQSODialog(TQSL-StationstandortTQSL Station LocationUploadQSODialogDie folgenden Werte werden verwendet, wenn ein importierter Datensatz die ADIF-Werte nicht enthltSThe values below will be used when an input record does not contain the ADIF valuesUploadQSODialogDiese Option lscht alle QSOs im Clublog<br>und ldt basierend auf dem Filter alle QSOs hoch, unabhngig von ihrem Status.sThis option deletes all QSOs in the Clublog
and based on filter, it uploads all QSOs regardless of their status.UploadQSODialogZeitTimeUploadQSODialogbUnter normalen Umstnden bedeutet dieser Status <b>"ignorieren/fehlerhaft"</b>.<br/>Manchmal kann es jedoch sinnvoll sein, diese Einstellung beim Senden einer QSL zu ignorieren.Under normal circumstances this status means "Ignore/Invalid".
However, it may sometimes be wanted to ignore this setting when sending a QSL.UploadQSODialogPUnter normalen Umstnden bedeutet dieser Status <b>"nicht senden"</b>.<br/>Manchmal kann es jedoch sinnvoll sein, diese Einstellung beim Senden einer QSL zu ignorieren.Under normal circumstances this status means "do not send".
However, it may sometimes be wanted to ignore this setting when sending a QSL.UploadQSODialogUnbekanntUnknownUploadQSODialogUnbestimmt UnspecifiedUploadQSODialogQSOs hochladen Upload QSOsUploadQSODialogHochladen zu Upload toUploadQSODialogLade hoch zu %1Uploading to %1UploadQSODialogWavelogWavelogUploadQSODialogeQSLeQSLUploadQSODialogAzimuth UserListModelRufzeichenCallsign UserListModelKommentarComment UserListModelEntfernungDistance UserListModelGitterfeld Gridsquare UserListModelA WCYTableModelAu WCYTableModelGMF WCYTableModelK WCYTableModelR WCYTableModelSA WCYTableModelSFI WCYTableModelZeitTime WCYTableModelexpK WCYTableModelA WWVTableModelInfo WWVTableModelK WWVTableModelSFI WWVTableModelZeitTime WWVTableModel dB dBWsjtxFilterDialog AfrikaAfricaWsjtxFilterDialogAntarktis AntarcticaWsjtxFilterDialog AsienAsiaWsjtxFilterDialogBesttigt ConfirmedWsjtxFilterDialogKontinent ContinentWsjtxFilterDialog*Entfernung grer alsDistance more thanWsjtxFilterDialog EuropaEuropeWsjtxFilterDialog"Erweiterte FilterExtended FiltersWsjtxFilterDialog"Allgemeine FilterGeneral FiltersWsjtxFilterDialogLog Status Log StatusWsjtxFilterDialogMitgliedMemberWsjtxFilterDialogNeues BandNew BandWsjtxFilterDialogNeuer Eintrag New EntityWsjtxFilterDialogNeuer ModeNew ModeWsjtxFilterDialogNeuer SlotNew SlotWsjtxFilterDialog2Keine Clubliste aktiviertNo Club List is enabledWsjtxFilterDialogNordamerika North AmericaWsjtxFilterDialogOzeanienOceaniaWsjtxFilterDialogSNR besser alsSNR better thanWsjtxFilterDialogSdamerika South AmericaWsjtxFilterDialogWSJTX-Filter WSJTX FiltersWsjtxFilterDialogGearbeitetWorkedWsjtxFilterDialogRufzeichenCallsignWsjtxTableModelEntfernungDistanceWsjtxTableModelGitterfeld GridsquareWsjtxTableModel Letzte Aktivitt Last ActivityWsjtxTableModel Letzte Nachricht Last MessageWsjtxTableModelMitgliedMemberWsjtxTableModelSNRSNRWsjtxTableModel,Spaltensichtbarkeit...Column Visibility... WsjtxWidgetFilter Spots Filter Spots WsjtxWidgetFilter... Filter... WsjtxWidgetGefiltertFiltered WsjtxWidgetForm WsjtxWidgetLWelche Spalten sollen angezeigt werden!Which columns should be displayed WsjtxWidgetxAktualisierung aller Wertelisten erzwingen (DXCC, SATs usw.)2Force update of all value lists (DXCC, SATs, etc.)mainzAusstehenden Datenbankimport verarbeiten (interne Verwendung).Process pending database import (internal use)mainJIm spezifischen Namensraum ausfhren. Run with the specific namespace.mainSprache einstellen. Beispiel <code>: 'en' oder 'en_US'. Ignoriert Betriebssystemeinstellungen.JSet language. example: 'en' or 'en_US'. Ignore environment setting.mainbersetzungsdatei - Absoluter oder relativer Pfad und Name der QM-Datei.>Translation file - absolute or relative path and QM file name.mainRSchreibt Debugmeldungen in die Debugdatei'Writes debug messages to the debug filemaincodecodemainNamensraum namespacemain path/QM-filenamepath/QM-filenamemainfoldynl-QLog-3252ff9/i18n/qlog_de.ts000066400000000000000000020737121517334601000171400ustar00rootroot00000000000000 ActivityEditor Activity Editor Aktivitätseditor Activity Name Aktivitätsname Layout Layout Window Arrangement: Fensteranordnung: Saved Gespeichert Clear Löschen Available Fields Verfügbare Felder List of fields that can be used Liste der Felder, die verwendet werden können Row A Zeile A Move selected fields from the Available Fields List to the Row A Ausgewählte Felder aus der Liste der verfügbaren Felder in die Zeile A verschieben Remove selected field from the Row A Ausgewähltes Feld aus der Zeile A entfernen List of fields in the first variable row Liste der Felder in der ersten Variablenzeile Change the order. Move selected field up Ändern Sie die Reihenfolge. Ausgewähltes Feld nach oben verschieben Change the order. Move selected field down Ändern Sie die Reihenfolge. Ausgewähltes Feld nach unten verschieben Row B Zeile B Move selected fields from the Available Fields List to the Row B Ausgewählte Felder aus der Liste der verfügbaren Felder in die Zeile B verschieben Remove selected field from the Row B Ausgewähltes Feld aus der Zeile B entfernen List of fields in the second variable row Liste der Felder in der zweiten Variablenzeile Column A Spalte A List of fields in the first QSO Detail Column Liste der Felder in der ersten QSO-Detail Spalte Column B Spalte B List of fields in the second QSO Detail Column Liste der Felder in der zweiten QSO-Detail Spalte Column C Spalte C List of fields in the third QSO Detail Column Liste der Felder in der dritten QSO-Detail-Spalte New QSO Rows Neue QSO Zeilen New QSO Detail Columns Neue Spalten in den QSO Details Values Werte Profiles Profile If unchecked, the profile does not change Wenn nicht aktiviert, ändert sich das Profil nicht Station Station Antenna Antenne Rig Rig Connect automatically Automatisch verbinden Connect Verbinden Rotator Rotor Fields Felder Must not be empty Darf nicht leer sein Unsaved Ungespeichert AlertRuleDetail Alert Rule Detail Alarmregel Details Rule Name Regelname Enabled Aktiviert Sources Quellen DX Cluster WSJTX WSJTX DX Worked Gearbeitet New Slot Neuer Slot Confirmed Bestätigt New Entity Neuer Eintrag New Mode Neuer Mode New Band Neues Band DX Callsign DX Rufzeichen Use Perl-like regular expression Verwende Perl-ähnliche reguläre Ausdrücke .* Country Land Log Status Protokollstatus Spot Comment Spot-Kommentar ITU ITU CQZ CQZ IOTA IOTA SOTA SOTA POTA POTA WWFF WWFF Special Programs Sonderprogramme Modes Betriebsarten FTx (FT8/FT4) FTx (FT8/FT4) Phone Phonie CW CW Digital Digital Bands Bänder Continent Kontinent North America Nordamerika Africa Afrika Antarctica Antarktis South America Südamerika Asia Asien Europe Europa Oceania Ozeanien Member Mitglied Spotter All Alle Must not be empty Darf nicht leer sein No Club List is enabled Keine Clubliste aktiviert AlertSettingDialog Alerts Rules Alarmregeln Rules Regeln Add Hinzufügen Edit Bearbeiten Remove Entfernen Name Name State Status AlertTableModel Rule Name Regelname Callsign Rufzeichen Frequency Frequenz Mode Betriebsart Updated Aktualisiert Last Update Letzte Aktualisierung Last Comment Letzter Kommentar Member Mitglied AlertWidget Alerts Benachrichtigungen Clear older than Löschen älter als Never Nie min(s) Edit Rules Regeln bearbeiten Column Visibility... Spaltensichtbarkeit... Clear Löschen AwardsDialog Awards Auszeichnungen Options Optionen Award Auszeichnung My DXCC Entity Eigener DXCC Eintrag User Filter Benutzer-Filter Confirmed by Bestätigt durch LoTW eQSL Paper Papier Mode Betriebsart CW Phone Phonie Digi Not-Worked Only nur nicht gearbeit Not-Confirmed Only Nur unbestätigt Show Anzeigen DXCC ITU WAC WAZ WAS WPX IOTA POTA Hunter POTA Jaeger POTA Activator POTA Aktivierer SOTA SOTA WWFF Gridsquare 2-Chars Locator 2 Zeichen Gridsquare 4-Chars Locator 4 Zeichen Gridsquare 6-Chars Locator 6 Zeichen Gridsquare %1-Chars Locator %1 Zeichen US Counties Countys der USA Russian Districts Russische Distrikte Japanese Cities/Ku/Guns Japanische Städte / Ku / Gun NZ Counties Countys Neuseelands Spanish DMEs Spanische DME Ukrainian Districts Ukrainische Distrikte No User Filter Kein Benutzerfilter North America Nordamerika South America Südamerika Europe Europa Africa Afrika Asia Asien Antarctica Antarktis Oceania Ozeanien DELETED Gelöscht AwardsTableModel Slots: Slot: Confirmed Bestätigt Worked Gearbeitet Still Waiting Wartend BandmapWidget Form Create an additional Bandmap Window Ein zusätzliches Bandplan-Fenster erstellen Clear older Ältere löschen Never Nie Clear All Alle löschen Clear the current band Aktuelles Band löschen min(s) Bandmap Bandplan Show Band Band anzeigen Center RX RX zentrieren Show Emergency Frequencies Notruffrequenzen anzeigen SOS CWCatKey No Rig is connected Rig nicht verbunden Rig does not support Morse over CAT Rig unterstützt kein CW-über-CAT Keyer is not connected Keyer nicht verbunden Cannot send Text to Rig Kann Text nicht an Rig senden Rig is not connected Rig nicht verbunden Cannot set Keyer Speed Kann Keyer Geschwindigkeit nicht einstellen Cannot stop Text Sending Kann Textübertragung nicht beenden CWConsoleWidget Form Speed Geschwindigkeit Immediately stop CW sending CW-Sendung sofort stoppen Halt Halt Clear Sent and Echo Console Sendefenster und Echo-Konsole löschen Clear Löschen &CW Text to send Zu versendender Text F1 F2 F3 Shortcuts profile Funktionstasten Profile CW Keyer Profile CW-Keyer Profil N/A WPM Sent text Gesendeter Text Echoed text Wiederholter Text Switch between sending <b>words</b> individually (separated by spaces)<br> and sending the entire text as a <b>whole</b> (separated by a new line). Wechseln Sie zwischen dem Senden <b>Wort</b> für Wort (getrennt durch Leerzeichen) <br> und dem Senden als <b>Ganzes</b> (getrennt durch eine neue Zeile). F4 F5 F6 F7 CW Console - Halt Sending CW Console - Halt Rig must be connected Rig muss verbunden sein Word Wort Whole Ganze CWDaemonKey Keyer is not connected Keyer nicht verbunden Cannot send Text Kann Text nicht senden Cannot set Keyer Speed Kann Keyer-Geschwindigkeit nicht einstellen Cannot stop Text Sending Kann Textübertragung nicht beenden CWFldigiKey Connected device is not FLDigi Verbundenes Programm ist nicht FLDigi Keyer is not connected Keyer ist nicht verbunden Cannot send Text to FLDigi Kann Text nicht an FLDigi senden Cannot send the Clear command to FLDigi Kann das Kommando Clear nicht an FLDigi senden Cannot send the TX command to FLDigi Kann das Kommando TX nicht an FLDigi senden Cannot send the Text command to FLDigi Kann das Text-Kommando nicht an FLDigi senden Cannot send the Stop command to FLDigi Kann das Kommando Stop nicht an FLDigi senden Cannot send the Abort command to FLDigi Kann das Kommando Abort nicht an FLDigi senden Cannot receive data from FLDigi Kann keine Daten von FLDigi empfangen FLDigi connection timeout Zeitüberschreitung der FLDigi-Verbindung FLDigi connection error FLDigi Verbindungsfehler FLDigi command error FLDigi Kommandofehler CWKeyer No CW Keyer Profile selected Kein CW-Keyer Profil ausgewählt Initialization Error Initialisierungsfehler Internal Error Interner Fehler Connection Error Verbindungsfehler Cannot open the Keyer connection Kann die Keyer-Verbindung nicht herstellen CWWinKey Connected device is not WinKey Angeschlossenes Gerät ist kein WinKey Cannot send Text to Rig Kann Text nicht an Rig senden Keyer is not connected Keyer nicht verbunden Communication Error Kommunikationsfehler Cannot set Keyer Speed Kann Keyer-Geschwindigkeit nicht einstellen Cannot stop Text Sending Kann Textübertragung nicht beenden 4000 Hz 4000 Hz 2000 Hz 2000 Hz 1333 Hz 1333 Hz 1000 Hz 1000 Hz 800 Hz 800 Hz 666 Hz 666 Hz 571 Hz 571 Hz 500 Hz 500 Hz 444 Hz 444 Hz 400 Hz 400 Hz CabrilloExportDialog Cabrillo Export Cabrillo exportieren File: Datei: Browse Durchsuchen Contest Contest Format Template: Formatvorlage: Manage Verwalten User Filter: Benutzerfilter: Date/Time: Datum/Uhrzeit: yyyy-MM-dd HH:mm - - UTC Station & Categories Station & Kategorien Callsign: Rufzeichen: Operators: Operatoren: Band: Band: Mode: Betriebsart: Power: Leistung: Operator: Operator: Assisted: Unterstützt: Station: Station: Transmitter: Sender: Time: Zeit: Overlay: Transmitter ID: Additional Zusätzlich Name: Name: Email: Email: Address: Adresse: Max 6 lines Max. 6 Zeilen Gridsquare Gitterfeld Location: Standort: Club: Club: Soapbox: Freitext: Off-Time: yyyy-mm-dd hhmm yyyy-mm-dd hhmm &Export &Exportieren Cabrillo Files (*.log);;CBR Files (*.cbr);;All Files (*) Cabrillo-Dateien (*.log);;CBR-Dateien (*.cbr);;Alle Dateien (*) QSO(s): %1 QSO(s): %1 QSOs: ? QSOs: ? QLog Warning QLog Warnung Please select a contest template. Bitte wählen Sie eine Contest-Vorlage aus. Please select an output file. Bitte wählen Sie eine Ausgabedatei aus. No callsign available. Check your filters. Kein Rufzeichen verfügbar. Überprüfen Sie Ihre Filter. QLog Error QLog Fehler Failed to prepare export query. Exportabfrage konnte nicht vorbereitet werden. Failed to query QSOs for export. QSOs für den Export konnten nicht abgefragt werden. Cannot open file %1 for writing. Datei %1 kann nicht zum Schreiben geöffnet werden. Exporting Cabrillo... Cabrillo wird exportiert… QLog Information QLog Information Exported %n QSO(s) to Cabrillo file. %n QSOs in die Cabrillo-Datei exportiert. CabrilloFormat All Bands Alle Bänder 2m (144 MHz) 2m (144 MHz) 1.25m (222 MHz) 1.25m (222 MHz) 70cm (432 MHz) 70cm (432 MHz) 33cm (902 MHz) 33cm (902 MHz) 23cm (1.2 GHz) 23cm (1.2 GHz) Light Licht VHF 3-Band VHF 3-Band VHF FM Only Nur VHF FM Digital Digital Mixed Gemischt High High Low Low QRP Single Operator Einmannbetrieb Multi Operator Mehrmannbetrieb Check Log Log prüfen Non-Assisted Nicht assistiert Assisted Assistiert Fixed Fest Mobile Mobil Portable Rover Rover Rover Limited Rover Limited Rover Unlimited Expedition Expedition HQ School Schule Distributed Verteilt One Eins Two Zwei Limited Begrenzt Unlimited Unbegrenzt SWL SWL 6 Hours 6 Stunden 12 Hours 12 Stunden 24 Hours 24 Stunden Classic Klassisch Rookie TB Wires Novice/Tech Novize/Techniker Over 50 Über 50 Text (left-aligned) Text (linksbündig) Frequency (kHz) Frequenz (kHz) Time (HHMM) Zeit (HHMM) Date (YYYY-MM-DD) Datum (JJJJ-MM-TT) RST Short (drop last digit) RST kurz (letzte Ziffer weglassen) Uppercase Großbuchstaben Mode (Cabrillo) Modus (Cabrillo) Zero-Padded Nr. Nummer mit Nullen Transmitter ID CabrilloTemplateDialog Cabrillo Template Manager Cabrillo-Vorlagenverwaltung Import template Vorlage importieren Import Importieren Export template Vorlage exportieren Export Exportieren New template Neue Vorlage New Neu Copy existing template Vorhandene Vorlage kopieren Copy Kopieren Delete template Vorlage löschen Delete Löschen Template Name: Vorlagenname: Contest Name: Contest-Name: Default Mode: Standardmodus: QSO Line Columns: QSO-Zeilen-Spalten: Contest name as required by the rules. It is possible to enter a custom string if it is not included in the list. Contest-Name gemäß den Regeln. Es ist möglich, eine benutzerdefinierte Zeichenkette einzugeben, falls sie nicht in der Liste enthalten ist. Seq. Nr. QSO Field QSO-Feld Formatter Formatierer Width Breite Label Etikett Add line Zeile hinzufügen Add Hinzufügen Remove selected line Ausgewählte Zeile entfernen Remove Entfernen New Template Neue Vorlage Copy - %1 Kopie – %1 Delete Template Vorlage löschen Delete template '%1'? Vorlage „%1“ löschen? Import Template Vorlage importieren QLog Cabrillo Template (*.qct) QLog Cabrillo-Vorlage (*.qct) Import Failed Import fehlgeschlagen Export Template Vorlage exportieren Export Failed Export fehlgeschlagen Failed to write file: %1 Datei konnte nicht geschrieben werden: %1 File not found: %1 Datei nicht gefunden: %1 Cannot open file: %1 Datei kann nicht geöffnet werden: %1 Invalid template file: missing name Ungültige Vorlagendatei: Name fehlt QLog Error QLog Fehler Cannot start database transaction. Datenbanktransaktion kann nicht gestartet werden. QLog Warning QLog Warnung Cannot save template '%1': %2 Vorlage „%1“ kann nicht gespeichert werden: %2 CallbookManager <p>The secondary callbook will be used</p> <p>Das sekundäre Callbook wird verwendet</p> ChatWidget ON4KST Chat Chat Room Chatraum Connect Verbinden New Neu QLog Warning QLog Warnung ON4KST Chat is not configured properly.<p> Please, use <b>Settings</b> dialog to configure it.</p> ON4KST Chat ist nicht richtig konfiguriert.<p>Bitte verwenden Sie den <b>Einstellungen</b> Dialog um ihn zu konfigurieren.</p> CheckBoxDelegate Enabled Aktiv Disabled Inaktiv ClockWidget Form Sunrise SA Sunset SU N/A CloudlogUploader Invalid API Key Ungültiger API-Schlüssel ClubLogUploader Clublog Operation for Callsign %1 failed.<br>%2 Clublog-Anfrage für Rufzeichen %1 fehlgeschlagen.<br>%2 ColumnSettingDialog Column Visibility Setting Einstellung der Spaltensichtbarkeit General Allgemein My Info Eigene Info QSL && Callbooks Members Mitglieder Conditionals Bedingungen Contests Conteste Others Andere Done erledigt ColumnSettingGenericDialog Unselect All Alle abwählen Select All Alle auswählen ColumnSettingSimpleDialog Column Visibility Setting Spaltensichtbarkeit Done erledigt DBSchemaMigration DXCC Entities DXCC Einträge Sats Info SAT Info SOTA Summits SOTA Gipfel WWFF Records WWFF Datensätze IOTA Records IOTA Datensätze POTA Records POTA Datensätze Membership Directory Records Mitgliedschaftsverzeichnis Clublog CTY.XML Clublog CTY.XML List of Values Werteliste Updating Update Failed DBStrings PHONE Phonie CW CW DIGITAL Digital Afghanistan Afghanistan Agalega & St. Brandon Agalega & St. Brandon Aland Islands Aland-Inseln Alaska Alaska Albania Albanien Algeria Algerien American Samoa Amerikanischen Samoa-Inseln Amsterdam & St. Paul Is. Amsterdam & St. Paul Is. Andaman & Nicobar Is. Andamanen und Nikobaren. Andorra Andorra Angola Angola Anguilla Anguilla Annobon Island Annobon-Insel Antarctica Antarktis Antigua & Barbuda Antigua und Barbuda Argentina Argentinien Armenia Armenien Aruba Aruba Ascension Island Ascension-Insel Asiatic Russia Asiatisches Russland Asiatic Turkey Asiatische Türkei Austral Islands Austral-Inseln Australia Australien Austria Österreich Aves Island Aves-Insel Azerbaijan Aserbaidschan Azores Azoren Bahamas Bahamas Bahrain Bahrain Baker & Howland Islands Baker- und Howlandinseln Balearic Islands Balearen Banaba Island Banaba-Insel Bangladesh Bangladesch Barbados Barbados Belarus Weißrussland Belgium Belgien Belize Belize Benin Benin Bermuda Bermuda Bhutan Bhutan Bolivia Bolivien Bonaire Bonaire Bosnia-Herzegovina Bosnien-Herzegowina Botswana Botswana Bouvet Bouvet Brazil Brasilien British Virgin Islands Britische Jungferninseln Brunei Darussalam Brunei Darussalam Bulgaria Bulgarien Burkina Faso Burkina Faso Burundi Burundi Cambodia Kambodscha Cameroon Kamerun Canada Kanada Canary Islands Kanarische Inseln Cape Verde Kap Verde Cayman Islands Cayman Inseln Central African Republic Zentralafrikanische Republik Central Kiribati Zentralkiribati Ceuta & Melilla Ceuta und Melilla Chad Tschad Chagos Islands Chagos-Inseln Chatham Islands Chatham-Inseln Chesterfield Islands Chesterfield-Inseln Chile Chile China China Christmas Island Weihnachtsinsel Clipperton Island Clipperton-Insel Cocos (Keeling) Islands Kokosinseln (Keelinginseln) Cocos Island Kokosinsel Colombia Kolumbien Comoros Komoren Conway Reef Conway-Riff Corsica Korsika Costa Rica Costa Rica Cote d'Ivoire Elfenbeinküste Crete Kreta Croatia Kroatien Crozet Island Crozet-Insel Cuba Kuba Curacao Curacao Cyprus Zypern Czech Republic Tschechien DPR of Korea DVR Korea Dem. Rep. of the Congo Dem. Republik Kongo Denmark Dänemark Desecheo Island Insel Desecheo Djibouti Dschibuti Dodecanese Dodekanes Dominica Dominica Dominican Republic Dominikanische Republik Ducie Island Ducie-Insel East Malaysia Ost-Malaysia Easter Island Osterinsel Eastern Kiribati Ostkiribati Ecuador Ecuador Egypt Ägypten El Salvador El Salvador England England Equatorial Guinea Äquatorialguinea Eritrea Eritrea Estonia Estland Ethiopia Äthiopien European Russia Europäisches Russland Falkland Islands Falkland Inseln Faroe Islands Färöer Inseln Fed. Rep. of Germany Deutschland Fernando de Noronha Fernando de Noronha Fiji Fidschi Finland Finnland France Frankreich Franz Josef Land Franz-Josef-Land French Guiana Französisch-Guayana French Polynesia Französisch Polynesien Gabon Gabun Galapagos Islands Galapagos Inseln Georgia Georgia Ghana Ghana Gibraltar Gibraltar Glorioso Islands Glorioso-Inseln Greece Griechenland Greenland Grönland Grenada Grenada Guadeloupe Guadeloupe Guam Guam Guantanamo Bay Guantanamo Bay Guatemala Guatemala Guernsey Guernsey Guinea Guinea Guinea-Bissau Guinea-Bissau Guyana Guyana Haiti Haiti Hawaii Hawaii Heard Island Heard-Insel Honduras Honduras Hong Kong Hongkong Hungary Ungarn ITU HQ ITU HQ Iceland Island India Indien Indonesia Indonesien Iran Iran Iraq Irak Ireland Irland Isle of Man Isle of Man Israel Israel Italy Italien Jamaica Jamaika Jan Mayen Jan Mayen Japan Japan Jersey Jersey Johnston Island Johnston-Insel Jordan Jordanien Juan Fernandez Islands Juan-Fernandez-Inseln Juan de Nova & Europa Juan de Nova & Europa Kaliningrad Kaliningrad Kazakhstan Kasachstan Kenya Kenia Kerguelen Islands Kerguelen-Inseln Kermadec Islands Kermadec-Inseln Kingdom of Eswatini Königreich Eswatini Kure Island Kure-Insel Kuwait Kuwait Kyrgyzstan Kirgisistan Lakshadweep Islands Lakshadweep-Inseln Laos Laos Latvia Lettland Lebanon Libanon Lesotho Lesotho Liberia Liberia Libya Libyen Liechtenstein Liechtenstein Lithuania Litauen Lord Howe Island Lord-Howe-Insel Luxembourg Luxemburg Macao Macau Macquarie Island Macquarie-Insel Madagascar Madagaskar Madeira Islands Madeira-Inseln Malawi Malawi Maldives Malediven Mali Mali Malpelo Island Malpelo-Insel Malta Malta Mariana Islands Marianen Market Reef Marktriff Marquesas Islands Marquesas-Inseln Marshall Islands Marshallinseln Martinique Martinique Mauritania Mauretanien Mauritius Mauritius Mayotte Mayotte Mellish Reef Mellish Riff Mexico Mexiko Micronesia Mikronesien Midway Island Midway-Insel Minami Torishima Minami Torishima Moldova Moldawien Monaco Monaco Mongolia Mongolei Montenegro Montenegro Montserrat Montserrat Morocco Marokko Mount Athos Berg Athos Mozambique Mosambik Myanmar Myanmar N.Z. Subantarctic Is. Subantarktische Inseln Neuseelands Namibia Namibia Nauru Nauru Navassa Island Navassa-Insel Nepal Nepal Netherlands Niederlande New Caledonia Neu-Kaledonien New Zealand Neuseeland Nicaragua Nicaragua Niger Niger Nigeria Nigeria Niue Niue Norfolk Island Norfolkinsel North Cook Islands Nordcookinseln North Macedonia Nordmazedonien Northern Ireland Nordirland Norway Norwegen Ogasawara Ogasawara Oman Oman Pakistan Pakistan Palau Palau Palestine Palästina Palmyra & Jarvis Islands Palmyra und Jarvis-Inseln Panama Panama Papua New Guinea Papua Neu-Guinea Paraguay Paraguay Peru Peru Peter 1 Island Peter-1-Insel Philippines Philippinen Pitcairn Island Pitcairninsel Poland Polen Portugal Portugal Pr. Edward & Marion Is. Pratas Island Pratas-Insel Puerto Rico Puerto Rico Qatar Katar Republic of Korea Republik Korea Republic of Kosovo Republik Kosovo Republic of South Sudan Republik Südsudan Republic of the Congo Republik Kongo Reunion Island Insel La Réunion Revillagigedo Revillagigedo Rodriguez Island Rodriguez-Insel Romania Rumänien Rotuma Island Rotuma-Insel Rwanda Ruanda Saba & St. Eustatius Saba und St. Eustatius (Statia) Sable Island Sable-Insel Samoa Samoa San Andres & Providencia San Andrés und Providencia San Felix & San Ambrosio San Felix und San Ambrosio San Marino San Marino Sao Tome & Principe São Tomé und Príncipe Sardinia Sardinien Saudi Arabia Saudi-Arabien Scarborough Reef Scarborough-Riff Scotland Schottland Senegal Senegal Serbia Serbien Seychelles Seychellen Sierra Leone Sierra Leone Singapore Singapur Sint Maarten Sint Maarten Slovak Republic Slowakische Republik Slovenia Slowenien Solomon Islands Salomon-Inseln Somalia Somalia South Africa Südafrika South Cook Islands Südliche Cookinseln South Georgia Island Insel Südgeorgien South Orkney Islands Südliche Orkney-Inseln South Sandwich Islands Südliche Sandwichinseln South Shetland Islands Südshetlandinseln Sov Mil Order of Malta Souveräner Malteserorden Spain Spanien Spratly Islands Spratly-Inseln Sri Lanka Sri Lanka St. Barthelemy St. Barthelemy St. Helena St. Helena St. Kitts & Nevis St. Kitts und Nevis St. Lucia St. Lucia St. Martin St. Martin St. Paul Island St. Peter & St. Paul St. Peter und St. Paul St. Pierre & Miquelon St. Pierre und Miquelon St. Vincent St. Vincent Sudan Sudan Suriname Surinam Svalbard Spitzbergen Swains Island Swains-Insel Sweden Schweden Switzerland Schweiz Syria Syrien Taiwan Taiwan Tajikistan Tadschikistan Tanzania Tansania Temotu Province Provinz Temotu Thailand Thailand The Gambia Gambia Timor - Leste Timor - Leste Togo Togo Tokelau Islands Tokelau-Inseln Tonga Tonga Trindade & Martim Vaz Trindade und Martim Vaz Trinidad & Tobago Trinidad & Tobago Tristan da Cunha & Gough Islands Tristan da Cunha und Gough-Inseln Tromelin Island Tromelin-Insel Tunisia Tunesien Turkmenistan Turkmenistan Turks & Caicos Islands Turks- und Caicosinseln Tuvalu Tuvalu UK Base Areas on Cyprus Souveräne Militärbasen Akrotiri und Dekelia US Virgin Islands Amerikanische Jungferninseln Uganda Uganda Ukraine Ukraine United Arab Emirates Vereinigte Arabische Emirate United Nations HQ Vereinte Nationen HQ United States Uruguay Uruguay Uzbekistan Usbekistan Vanuatu Vanuatu Vatican City Vatikanstadt Venezuela Venezuela Vietnam Vietnam Wake Island Wake Island Wales Wales Wallis & Futuna Islands Wallis- und Futuna-Inseln West Malaysia West Malaysia Western Kiribati Westkiribati Western Sahara Westsahara Willis Island Willis Island Yemen Jemen Zambia Sambia Zimbabwe Zimbabwe DXCCSubmissionDialog DXCC Submission List DXCC-Einreichungsliste Options Optionen My DXCC Entity Eigener DXCC Eintrag User Filter Benutzer-Filter Category Kategorie Mixed Gemischt CW CW Phone Phonie Digital Digital Confirmed by Bestätigt durch LoTW LoTW Paper Papier Show Anzeigen Not Yet Submitted Noch nicht eingereicht Submitted (Not Granted) Eingereicht (nicht anerkannt) Already Granted Bereits anerkannt Band Scope Bandbereich Select 5-Band DXCC preset bands (80/40/20/15/10m) Vordefinierte 5-Band-DXCC-Bänder auswählen (80/40/20/15/10 m) 5-Band DXCC 5-Band-DXCC Select all DXCC-eligible bands Alle DXCC-berechtigten Bänder auswählen All DXCC Bands Alle DXCC-Bänder Bands Bänder Select options above and the list will update automatically. Wählen Sie die Optionen oben aus und die Liste wird automatisch aktualisiert. Export the contacts listed above to an ADIF file Die oben aufgeführten Kontakte in eine ADIF-Datei exportieren Export Exportieren No User Filter Kein Benutzerfilter Any Band (Entity Level) Beliebiges Band (Entity-Ebene) 5-Band DXCC (80/40/20/15/10m) 5-Band-DXCC (80/40/20/15/10 m) Custom Band Selection Benutzerdefinierte Bandauswahl Entity Entität Prefix Präfix Callsign Rufzeichen Band Band Mode Betriebsart Date Datum Submitted Eingereicht Granted Anerkannt Export ADIF ADIF exportieren No contacts to export. Keine Kontakte zum Exportieren. Failed to retrieve contact records. Kontaktaufzeichnungen konnten nicht abgerufen werden. Export DXCC Submission List as ADIF DXCC-Einreichungsliste als ADIF exportieren any band beliebiges Band 5-band 5-Band all bands alle Bänder %1 selected band(s) %1 ausgewählte Bänder No contacts match the selected criteria. Keine Kontakte entsprechen den ausgewählten Kriterien. %1 %2 %3 — DXCC %4 / %5 %1 %2 %3 — DXCC %4 / %5 band-slot Band-Slot entity Entität entry Eintrag entries Einträge Data New Entity Neuer Eintrag New Band Neues Band New Mode Neuer Mode New Band&Mode Neues Band&Mode New Slot Neuer Slot Confirmed Bestätigt Worked Gearbeitet Hz Hz kHz kHz GHz GHz MHz MHz Yes Ja No Nein Requested Angefordert Queued Wartend Invalid Ungültig Bureau Büro Direct Direkt Electronic Elektronisch Blank Leer Modified Geändert Grayline Grayline Other Andere Short Path Long Path Not Heard Nicht gehört Uncertain Unsicher Straight Key Straight Key Sideswiper Sideswiper Mechanical semi-automatic keyer or Bug Mechanical semi-automatic keyer or Bug Mechanical fully-automatic keyer or Bug Mechanical fully-automatic keyer or Bug Single Paddle Single Paddle Dual Paddle Dual Paddle Computer Driven Computergesteuert Confirmed (AG) Bestätigt (AG) Confirmed (no AG) Bestätigt (non-AG) Unknown Unbekannt Aircraft Scatter Aircraft Scatte Aurora-E Aurora-E Aurora Aurora Back scatter Back scatter EchoLink EchoLink Earth-Moon-Earth Erde-Mond-Erde Sporadic E Sporadic E F2 Reflection F2 Reflektion Field Aligned Irregularities Feldbedingte Unregelmäßigkeiten Ground Wave Bodenwelle Internet-assisted Internet-assisted Ionoscatter Ionoscatter IRLP IRLP Line of Sight Sichtlinie Meteor scatter Terrestrial or atmospheric repeater or transponder Rain scatter Satellite Trans-equatorial Tropospheric ducting DateFormatDelegate Blank Leer DevToolsDialog Developer Tools Entwickler-Tools Debug Log Debug-Log Logging Rules: Protokollierungsregeln: e.g. qlog.ui.*.runtime=true z. B. qlog.ui.*.runtime=true Apply Anwenden Generate Debug File Debug-Datei erzeugen Export File Datei exportieren SQL Console SQL-Konsole Open SQL SQL öffnen Save SQL SQL speichern Run SQL SQL ausführen Export As Exportieren als Enter SQL query here... Ctrl+Return = run SQL-Abfrage hier eingeben... Strg+Eingabe = ausführen TXT CSV ADI Open SQL Query SQL-Abfrage öffnen SQL Files (*.sql);;All Files (*) SQL-Dateien (*.sql);;Alle Dateien (*) Open Error Fehler beim Öffnen Cannot open file: %1 Datei kann nicht geöffnet werden: %1 Save SQL Query SQL-Abfrage speichern Save Error Fehler beim Speichern Cannot save file: %1 Datei kann nicht gespeichert werden: %1 Query saved to %1 Abfrage in %1 gespeichert Error: %1 Fehler: %1 %1 row(s) shown (truncated at %2) in %3 ms %1 Zeile(n) angezeigt (gekürzt auf %2) in %3 ms %1 row(s) returned in %2 ms %1 Zeile(n) in %2 ms zurückgegeben Export Exportieren No results to export. Keine Ergebnisse zum Exportieren. Export Error Exportfehler Cannot open file for writing: %1 Datei kann nicht zum Schreiben geöffnet werden: %1 Exported %1 row(s) to %2 %1 Zeile(n) nach %2 exportiert Text Files (*.txt);;All Files (*) Textdateien (*.txt);;Alle Dateien (*) CSV Files (*.csv);;All Files (*) CSV-Dateien (*.csv);;Alle Dateien (*) ADIF Export ADIF exportieren ADIF export requires the query to include the contacts 'id' column. Example: SELECT id, callsign FROM contacts WHERE ... No valid contact IDs found in the result set. Keine gültigen Kontakt-IDs im Ergebnissatz gefunden. Failed to retrieve contact records: %1 Kontaktaufzeichnungen konnten nicht abgerufen werden: %1 No matching contacts found in the database. Keine passenden Kontakte in der Datenbank gefunden. Logging rules cleared (defaults) Protokollierungsregeln zurückgesetzt (Standard) Logging rules applied Protokollierungsregeln angewendet Save Debug Log Debug-Log speichern No debug log file is currently being written Derzeit wird keine Debug-Logdatei geschrieben Log Files (*.log);;All Files (*) Logdateien (*.log);;Alle Dateien (*) Debug log saved to %1 Debug-Log in %1 gespeichert Failed to copy the debug log file. Die Debug-Logdatei konnte nicht kopiert werden. File logging is disabled Dateiprotokollierung ist deaktiviert Log file: %1 Logdatei: %1 DownloadQSLDialog Download QSLs QSLs herunterladen eQSL eQSL eQSL QTH Profile eQSL QTH Profil QSLs Since QSLs seit QSOs Since QSO seit LoTW LoTW My Callsign Eigenes Rufzeichen &Download &Herunterladen LoTW is not configured properly.<p> Please, use <b>Settings</b> dialog to configure it.</p> LoTW ist nicht richtig eingerichtet.<p> Bitte verwende den <b>Einstellungen</b> Dialog, um es einzurichten.</p> eQSL is not configured properly.<p> Please, use <b>Settings</b> dialog to configure it.</p> eQSL ist nicht richtig eingerichtet.<p> Bitte verwende den <b>Einstellungen</b> Dialog, um es einzurichten.</p> Cancel Abbrechen Downloading from %1 Herunterladen von %1 Processing %1 QSLs Verarbeite %1 QSLs QLog Error QLog Fehler %1 update failed: Aktualisierung von %1 fehlgeschlagen: QLog Information QLog Information No service selected Kein Dienst ausgewählt DxFilterDialog DX Cluster Filters DX Cluster Filter General Filters Allgemeine Filter Bands Bänder FTx (FT8/FT4) FTx (FT8/FT4) Continent Kontinent North America Nordamerika Africa Afrika Antarctica Antarktis South America Südamerika Asia Asien Europe Europa Oceania Ozeanien Modes Betriebsarten Phone Phonie CW CW Digital Digital Log Status Log Status New Mode Neuer Mode New Entity Neuer Eintrag New Band Neues Band New Slot Neuer Slot Worked Gearbeitet Confirmed Bestätigt Extended Filters Erweiterte Filter Spotter Continent Spotter Kontinent Do not show the following spots when they have the same Callsign and their time difference is lower than Time Diff and their frequency difference is lower than Freq Diff Folgende Spots nicht anzeigen, wenn sie dasselbe Rufzeichen haben und der Unterschied in Frequenz und Zeit kleiner als die eingestellten Parameter ist Spots Dedup Spot-Dubletten entfernen Time difference Zeitunterschied s s Frequency difference Frequenzunterschied kHz kHz Member Mitglied No Club List is enabled Keine Clubliste aktiviert DxTableModel Time Zeit Callsign Rufzeichen Frequency Frequenz Mode Betriebsart Spotter Comment Kommentar Continent Kontinent Spotter Continent Spotter Kontinent Band Band Member Mitglied Country Land DxWidget Send DX Cluster Command Sende DX-Cluster Kommando Spots Filtered Gefiltert WCY WCY WWV WWV To All An alle Console Konsole 15-min Trend Full-text search Volltextsuche Search Suchen Close Search Suche schließen Filter... Filter... Filter DXC Filter DXC Spot Last QSO Spot letztes QSO Send last QSO spot Letzten QSO-Spot senden Show HF Stats HF Statistik anzeigen Show VHF Stats VHF Statistik anzeigen Show WCY WCY anzeigen Show WWV WWV anzeigen Column Visibility... Spaltensichtbarkeit... Connect on startup Beim Start verbinden Automatic connection after start Automatische Verbindung nach dem Start Delete Server Löschen Server DXC - Delete Server DXC - Löschen Server Clear Password Passwort löschen Keep Spots Spots merken Spots are not cleared when connecting to a new DX Cluster. Spots werden nicht gelöscht, wenn eine Verbindung zu einem neuen DX-Cluster hergestellt wird. Clear Löschen Clear all data Alle Löschen Search... Suchen... DXC - Search DXC- Suchen Which columns should be displayed Welche Spalten sollen angezeigt werden Insert a <b>hostname:port</b> of DXC Server. Füge <b>hostname:port</b> eines DXC Servers ein. Connect Verbinden My Continent Mein Kontinent Auto Automatisch Connecting... Verbinden... DX Cluster is temporarily unavailable DX-Cluster vorübergehend nicht erreichbar DXC Server Error DXC-Serverfehler An invalid callsign Ungültiges Rufzeichen DX Cluster Password DX Cluster Passwort Security Notice Sicherheitshinweis The password can be sent via an unsecured channel Das Passwort kann über einen ungesicherten Kanal gesendet werden Server Server Username Benutzername Disconnect Trennen DX Cluster Command DX-Cluster Kommando DxccTableModel Worked Gearbeitet eQSL LoTW Paper Papier DxccTableWidget Mode Betriebsart EQSLQSLDownloader Incorrect Password or QTHProfile Id Falsches Passwort oder QTHProfil-Id ADIF file not found in eQSL response Keine ADIF-Datei in der eQSL-Antwort gefunden Incorrect Username or password Falscher Benutzername oder Passwort Unknown Error Unbekannter Fehler Cannot opet temporary file Kann temporäre Datei nicht öffnen Cannot save the image to file Kann das Bild nicht in die Datei speichern EQSLUploader Unknown Reply from eQSL Unbekannte Antwort von eQSL EditActivitiesDialog Edit Activities Aktivitätseditor Activities Aktivitäten Add Hinzufügen Edit Bearbeiten Remove Entfernen ExportDialog Export Selected QSOs Ausgewählte QSOs exportieren CSV POTA POTA Export Type Export-Typ Column set Export-Felder Select one of the pre-defined sets of columns or define your own set of columns Wählen Sie eine der vordefinierten Auswahl von ADIF-Feldern aus oder definieren Sie Ihre eigene Auswahl Edit current set of columns Bearbeiten Sie die aktuelle Auswahl von ADIF-Feldern Edit Bearbeiten Mark exported QSOs As Sent Markieren Sie exportierte QSOs als gesendet Export only QSOs that match the active filters Nur QSOs exportieren, die mit den aktiven Filtern übereinstimmen Filters Filter Export only QSOs that match the selected date range Nur QSOs exportieren, die dem ausgewählten Datumsbereich entsprechen Date Range Datumsbereich Export only QSOs that match the selected My Callsign Nur QSOs exportieren, die mit dem ausgewählten eigenen Rufzeichen übereinstimmen My Callsign Eigenes Rufzeichen Export only QSOs that match the selected My Gridsquare Nur QSOs exportieren, die mit dem ausgewählten eigenen Gitterfeld übereinstimmen My Gridsquare Eigenes Gitterfeld Export only QSOs that match the selected QSL Send Via value Exportieren Sie nur QSOs, die der ausgewählten QSL-Ausgang-Via entsprechen QSL Send via QSL Ausgang via Include unusual QSO Sent statuses Unüblichen QSO Sent-Status einbeziehen Include Sent Status Send-Status mit einbeziehen Under normal circumstances this status means <b>"Ignore/Invalid"</b>.<br/>However, it may sometimes be wanted to ignore this setting when sending a QSL. Unter normalen Umständen bedeutet dieser Status <b>"ignorieren/fehlerhaft"</b>.<br/>Manchmal kann es jedoch sinnvoll sein, diese Einstellung beim Senden einer QSL zu ignorieren. "Ignore" "Ignorieren" Under normal circumstances this status means <b>"do not send"</b>.<br/>However, it may sometimes be wanted to ignore this setting when sending a QSL. Unter normalen Umständen bedeutet dieser Status <b>"nicht senden"</b>.<br/>Manchmal kann es jedoch sinnvoll sein, diese Einstellung beim Senden einer QSL zu ignorieren. "No" "Nein" Resend already sent QSOs Bereits gesendete QSOs erneut senden Already Sent Bereits gesendet User Filter Benutzer-Filter Export QSOs that match the selected user QSO Filter QSOs exportieren, die dem ausgewählten Benutzer-QSO-Filter entsprechen Station Profile Stationsprofil File Datei Browse Durchsuchen ADX ADX JSON JSON Export QSOs QSOs exportieren &Export &Exportieren Export only QSOs matching this station profile Nur QSOs exportieren, die tomuto Stationsprofil entsprechen Exporting... Export wird ausgeführt… Cancel Abbrechen QLog Error QLog Fehler Cannot mark exported QSOs as Sent Exportierte QSOs können nicht als gesendet markiert werden Generic Allgemein QSLs QSL QSL-specific QSL-spezifisch All Alle Minimal Custom 1 Benutzerdefiniert 1 Custom 2 Benutzerdefiniert 2 Custom 3 Benutzerdefiniert 3 ExportPasswordDialog Pack Data & Settings Daten und Einstellungen packen Enter a password to encrypt stored credentials. The password will be needed to restore them later. Geben Sie ein Passwort ein, um die gespeicherten Zugangsdaten zu verschlüsseln. Dieses Passwort wird später benötigt, um sie wiederherzustellen. Password Passwort Random Zufällig Confirm Password Passwort bestätigen Delete passwords from Credential Store after export Passwörter nach dem Export aus dem Credential Store löschen FlrigRigDrv Timeout Zeitüberschreitung FLRig response timeout FLRig-Antwortzeitüberschreitung Network Error Netzwerkfehler HRDLogUploader Response message malformed Antwortnachricht fehlerhaft HamQTHCallbook HamQTH HamQTH HamlibRigDrv None Keine CAT CAT DTR DTR RTS RTS Initialization Error Initialisierungsfehler Cannot set PTT Type PTT-Typ kann nicht eingestellt werden Cannot set PTT Share PTT-Share kann nicht eingestellt werden Cannot set CIV Addr CI-V-Adresse kann nicht gesetzt werden Unsupported Rig Driver Nicht unterstützter Rig-Treiber Cannot set auto_power_on auto_power_on kann nicht gesetzt werden Cannot set no_xchg to 1 no_xchg kann nicht auf 1 gesetzt werden Rig Open Error Verbindung fehlgeschlagen Set TX Frequency Error Fehler beim Setzen der TX-Frequenz Set Frequency Error Fehler bei der Frequenzeinstellung Set Split Error Fehler beim Setzen von Split Set Mode Error Fehler bei der Moduseinstellung Set Split Mode Error Fehler beim Setzen des Split-Modus Set PTT Error Fehler beim Auslösen der PTT Cannot sent Morse This cannot be displayed Cannot stop Morse This cannot be displayed Get PTT Error This cannot be displayed Get Frequency Error Fehler bei der Frequenzabfrage Get Mode Error Fehler bei der Mode-Abfrage Get VFO Error Fehler beim Abrufen des VFO Get PWR Error This cannot be displayed Get PWR (power2mw) Error This cannot be displayed Get RIT Function Error This cannot be displayed Get RIT Error This cannot be displayed Get XIT Function Error This cannot be displayed Get XIT Error This cannot be displayed Get Split Error Get TX Frequency Error Get KeySpeed Error This cannot be displayed Set KeySpeed Error This cannot be displayed HamlibRotDrv Initialization Error Initialisierungsfehler Unsupported Rotator Driver Nicht unterstützter Rotor-Treiber Rot Open Error Verbindung fehlgeschlagen Set Possition Error Fehler beim Einstellen der Position Get Possition Error Fehler beim Abrufen der Position ImportDialog Import Importieren Defaults Voreinstellung Comment Kommentar My Rig Eigener Rig Import all or only QSOs from the given period Alle oder nur QSOs aus dem angegebenen Zeitraum importieren File Datei ADX ADX Browse Durchsuchen My Profile Eigenes Profil If DXCC is missing in the imported record, it will be resolved from the callsign. Wenn DXCC im importierten Datensatz fehlt, wird es aus dem Rufzeichen ermittelt. Fill missing DXCC Entity Information Fehlende DXCC-Entitätsinformationen ergänzen Date Range Zeitraum All Alle Options Optionen &Import &Importieren Select File Datei auswählen The value is used when an input record does not contain the ADIF value Der Wert wird verwendet, wenn ein importierter Datensatz den ADIF-Wert nicht enthält The values below will be used when an input record does not contain the ADIF values Die folgenden Werte werden verwendet, wenn ein importierter Datensatz die ADIF-Werte nicht enthält <p><b>In-Log QSO:</b></p><p> <p><b>Logbuch QSO:</b></p><p> <p><b>Importing:</b></p><p> <p><b>Importieren:</b></p><p> Duplicate QSO Doppeltes QSO <p>Do you want to import duplicate QSO?</p>%1 %2 <p>Doppelte QSOs importieren?</p>%1 %2 Save to File In Datei speichern QLog Import Summary Zusammenfassung QLog Import Import date Datum importieren Imported file Datei importieren Imported: %n contact(s) Importiert: %n Kontakt(e) Warning(s): %n Warnungen: %n Error(s): %n Fehler: %n Details Details Import Result Ergebnis des Imports Save Details... Details speichern... InputPasswordDialog Dialog Do not translate -not used The password will be stored in the Credential Store. Das Passwort wird im Credential Store gespeichert. Remember Password Passwort merken KSTChat Unknown User Unbekannter Benutzer Invalid password Falsches Passwort KSTChatWidget Chat messages Chat-Nachrichten Valuable messages Wertvolle Nachrichten Clear selected Callsign and Chat message entry. Ausgewählten Rufzeichen- und Chat-Nachrichteneintrag löschen. Send chat message Chat-Nachricht senden Column Visibility Spaltensichtbarkeit Which columns should be displayed Welche Spalten sollen angezeigt werden Prepare QSO QSO vorbereiten Transfer Callsign and Gridsquare Information to the New QSO dialog Übertragen Sie Rufzeichen und Gitterfeldinformationen in den Neues QSO Dialog Show About Me Only Nur Informationen über mich anzeigen Show only messages where my callsign is present Nur Nachrichten anzeigen, in denen mein Rufzeichen vorkommt Suppress User To User Unterdrückung von Benutzer zu Benutzer Suppress private messages between two callsigns Private Nachrichten zwischen zwei Rufzeichen unterdrücken Highlight Hervorheben Highlight messages based on the setting Hervorhebung von Meldungen je nach Einstellung Highlight Rules Regeln hervorheben Beam Clear Messages Nachrichten löschen Clear all messages in the window Alle Nachrichten im Fenster löschen You Du KSTHighlightRuleDetail Edit Rule Regel bearbeiten Rule Name Regelname Chat Room Nachrichtenraum Enabled Aktiv Highlight message which match Hervorhebung von Nachrichten, die übereinstimmen All the following conditions Alle folgenden Bedingungen Any of the following conditions Eine der folgenden Bedingungen Add Condition Bedingung hinzufügen All Alle Sender Message Nachricht Gridsquare Gitterfeld Contains enthält Starts with beginnt mit Remove Entfernen Must not be empty Darf nicht leer sein KSTHighlighterSettingDialog Highlight Rules Regeln hervorheben Rules Regeln Add Hinzufügen Edit Bearbeiten Remove Entfernen Name Name State Staat KeySequenceEdit Clear Löschen LoadDatabaseDialog Unpack Data & Settings Daten und Einstellungen entpacken Warning Warnung <html><head/><body><p>⚠ <span style=" font-weight:700;">Current database will be DELETED!</span><br/>⚠ <span style=" font-weight:700;">All stored passwords will be DELETED!</span><br/>⚠ <span style=" font-weight:700;">The application will restart after loading</span>.</p><p>To preserve data, use Pack Data &amp; Settings or Export QSOs first.</p></body></html> <html><head/><body><p>⚠ <span style=" font-weight:700;">Die aktuelle Datenbank wird GELÖSCHT!</span><br/>⚠ <span style=" font-weight:700;">Alle gespeicherten Passwörter werden GELÖSCHT!</span><br/>⚠ <span style=" font-weight:700;">Die Anwendung wird nach dem Laden neu gestartet</span>.</p><p>Um Daten zu sichern, verwenden Sie zuerst Pack Data &amp; Settings oder Export QSOs.</p></body></html> Select Database Datenbank auswählen File: Datei: Browse Durchsuchen Status: No file selected Status: Keine Datei ausgewählt Decrypt Credentials Zugangsdaten entschlüsseln Enter password to decrypt credentials Passwort eingeben, um die Zugangsdaten zu entschlüsseln Password: Passwort: Load && Restart Laden und neu starten Invalid password Falsches Passwort Select Database File Datenbankdatei auswählen QLog Database Export (*.dbe);;All Files (*) QLog-Datenbankexport (*.dbe);;Alle Dateien (*) Cannot create temporary file Temporäre Datei kann nicht erstellt werden Decompressing database... Datenbank wird dekomprimiert… Cannot decompress database file Datenbankdatei kann nicht dekomprimiert werden Cannot open database Datenbank kann nicht geöffnet werden Valid database Gültige Datenbank Different platform Andere Plattform Password required to import credentials Passwort zum Importieren der Zugangsdaten erforderlich No encrypted credentials in database Keine verschlüsselten Zugangsdaten in der Datenbank LogFormat Cannot find My DXCC Entity Info Meine DXCC-Informationen fehlen A minimal set of fields not present (start_time, call, band, mode, station_callsign) Ein minimaler Satz von Datenfeldern, die nicht vorhanden sind (start_time, call, band, mode, station_callsign) Outside the selected Date Range Außerhalb des gewählten Datumsbereichs Duplicate Duplikate DXCC Info is missing DXCC-Informationen fehlen no Station Callsign present Kein Stationsrufzeichen vorhanden Cannot insert to database Einfügen in die Datenbank nicht möglich Imported Importiert DXCC State: DXCC Status: Error Fehler Warning Warnung LogbookModel QSO ID Original descriptions may be more meaningful here? QSO ID Time on Startzeit Time off Endzeit Call Rufzeichen SIG (ASCII) SIG SIG Info (ASCII) SIG Info VUCC VUCC Web Web RST Sent RST Ausgang RST Rcvd RST Eingang Frequency Frequenz Band Band Mode Betriebsart Submode Unterart My City (ASCII) Eigene Stadt (ASCII) My Country (ASCII) Eigenes Land (ASCII) My Name (ASCII) Eigener Name (ASCII) My Postal Code (ASCII) Eigene Postleitzahl (ASCII) My Rig (ASCII) Eigener Rig (ASCII) My Special Interest Activity (ASCII) Eigene spezielle Interessenaktivität (ASCII) My Spec. Interes Activity Info (ASCII) Eigene spezielle Interessenaktivität Info (ASCII) My Spec. Interest Activity Info Eigene spezielle Interessenaktivität Info Name Name Notes (ASCII) Anmerkungen (ASCII) QTH Gridsquare Locator DXCC DXCC Country Land Continent Kontinent RSTs RSTa RSTr RSTe Name (ASCII) Name (ASCII) QTH (ASCII) QTH (ASCII) Country (ASCII) Land (ASCII) CQZ CQZ QSLr QSLe QSLr Date QSLe Datum QSLs QSLa QSLs Date QSLa Datum LoTWr LoTWe LoTWr Date LoTWe Datum LoTWs LoTWa LoTWs Date LoTWa Datum TX PWR TX Leistung Additional Fields Zusatzfelder Address Adresse Age Alter A-Index A-Index Antenna Az Antenne Az Antenna El Antenne El Signal Path Signalweg ARRL Section ARRL Sektion Award Submitted Award eingereicht Award Granted Award erteilt Band RX Band RX Contest Check Contest Püfung Class Klasse ClubLog Upload Date Clublog Uploaddatum ClubLog Upload State Clublog Uploadstatus Comment (ASCII) Kommentar (ASCII) Comment Kommentar County Alt Landkreis Alt Contacted Operator Operator kontaktiert Contest ID Contest ID Credit Submitted Beitrag eingereicht Credit Granted Beitrag bewilligt DCLr Date DCLe Datum DCLs Date DCLa Datum DCLr DCLe DCLs DCLa Email Email Owner Callsign Eigentümer Rufzeichen eQSL AG eQSL AG FISTS Number FISTS Nummer FISTS CC EME Init EME Initialisierung Frequency RX Frequenz RX Guest Operator Gastoperator HRDLog Upload Date HRDLog Uploaddatum HRDLog Upload Status HRDLog Uploadstatus IOTA Island ID IOTA Insel-ID K-Index K-Index Latitude Breitengrad Longitude Längengrad Max Bursts MS Shower Name My Antenna (ASCII) Eigene Antenne (ASCII) My Antenna Eigene Antenne My County Alt Eigener Landkreis Alt My DARC DOK Eigenes DARC DOK Operator Callsign Operator Rufzeichen POTA POTA QRZ Download Date QRZ Herunterladen Datum QRZ Download Status QRZ Herunterladen Status QSLs Message (ASCII) QSLs Message QSL-Nachricht QSLr Message QSLr Via QSLe via QSLs Via QSLa via Region Region Rig (ASCII) RcvPWR RcvNr Nr. erhalten RcvExch Info erhalten SentNr Nr. gesendet SentExch Info gesendet My ARRL Section Eigene ARRL Sektion My WWFF Eigener WWFF WWFF Paper Papier LoTW LoTW eQSL eQSL QSL Received QSL Eingang My City Eigene Stadt Address (ASCII) Adresse (ASCII) Altitude Höhe Gridsquare Extended Erweitertes Gitterfeld DOK DOK Distance Entfernung eQSLr Date eQSLe Datum eQSLs Date eQSLa Datum eQSLr eQSLe eQSLs eQSLa HamlogEU Upload Date HamlogEU Uploaddatum HamlogEU Upload Status HamlogEU Uploadstatus HamQTH Upload Date HamQTH Uploaddatum HamQTH Upload Status HamQTH Uploadstatus CW Key Info CW Key Information CW Key Type CW Key Typ My Altitude Eigene Höhe My County Eigener Landkreis My Country Eigenes Land My CQZ Eigene CQZ My DXCC Eigenes DXCC Land My FISTS Eigene FISTS Nummer My Gridsquare Eigener Locator My Gridsquare Extended Eigener erweiterter Locator My IOTA Eigene IOTA Nummer My IOTA Island ID Eigene IOTA Insel-ID My ITU Eigene ITU Zone My Latitude Eigener Breitengrad My Longitude Eigener Längengrad My CW Key Info Eiene CW Key My CW Key Type Eigener CW Key Typ My Name Eigener Name My Postal Code Eigene Postleitzahl My POTA Ref Eigene POTA Ref My Rig Eigener Rig My Special Interest Activity Eigene spezielle Interessenaktivität My SOTA Eigene SOTA Nummer My State Eigener Staat My Street Eigene Strasse My USA-CA Counties Eigene USA-CA Bezirke My VUCC Grids Eigenes VUCC Gitterfeld Notes Anmerkungen #MS Bursts #MS Pings Contest Precedence Contest Vorrang Propagation Mode Ausbreitungsmodus Public Encryption Key Öffentlicher Chiffrierschlüssel QRZ Upload Date QRZ Uploaddatum QRZ Upload Status QRZ Uploadstatus QSL Message QSL-Nachricht QSL Via QSO Completed QSO abgeschlossen QSO Random Rig SAT Mode SAT Betriebsart SAT Name SAT Name Solar Flux Silent Key Verstorben SKCC Member SKCC Mitglied SOTA SOTA Logging Station Callsign Logging Station Rufzeichen SWL SWL Ten-Ten Number Ten-Ten Nummer UKSMG Member UKSMG Mitglied USA-CA Counties USA-CA Bezirke VE Prov ITU ITU Prefix Präfix State Staat County Landkreis IOTA IOTA QSL Sent QSL Ausgang LogbookWidget Delete Löschen Logbook - Delete QSO Logbuch - Löschen QSO Upload to Clublog Nach Clublog hochladen Lookup on Web Nachschlagen im Web Update from Callbook Update vom Callbook Add Missing Info fehlende Angaben ergänzen Mark QSL RCVD QSL als empfangen markieren Mark QSL Requested QSL als angefordert markieren Filter Callsign Rufzeichen filtern Edit Value Wert Bearbeiten Logbook - Edit Value Logbuch - Wert Bearbeiten Column Visibility Which columns should be displayed Welche Spalten sollen angezeigt werden Export Selected Ausgewählte exportieren Export selected QSOs Ausgewählte QSOs exportieren Send DX Spot QSO-Spot senden Logbook - Send DX Spot Logbuch - QSO-Spot senden Callsign Rufzeichen Gridsquare Gitterfeld POTA POTA SOTA SOTA WWFF WWFF SIG SIG IOTA IOTA Delete the selected contacts? Die ausgewählten Kontakte löschen? Clublog's <b>Immediately Send</b> supports only one-by-one deletion<br><br>Do you want to continue despite the fact<br>that the DELETE operation will not be sent to Clublog? Clublog <b>Sofort Upload</b> unterstützt nur das Löschen eines Datensatzes nach dem anderen.<br><br>Möchten Sie fortfahren, obwohl<br>der DELETE-Vorgang nicht an Clublog gesendet wird? Deleting QSOs QSOs Löschen Update Aktualisieren By updating, all selected rows will be affected.<br>The value currently edited in the column will be applied to all selected rows.<br><br>Do you want to edit them? Durch die Aktualisierung werden alle ausgewählten Zeilen beeinflusst.<br>Der aktuell bearbeitete Wert in der Spalte wird auf alle ausgewählten Zeilen angewendet.<br>Möchten Sie fortfahren? Count: %n Anzahl: %n Anzahl: %n Downloading eQSL Image eQSL-Bild herunterladen Cancel Abbrechen All Bands Alle Bänder All Modes Alle Betriebsarten All Countries Alle Länder No User Filter Kein Benutzerfilter QLog Warning QLog Warnung Each batch supports up to 100 QSOs. Jeder Stapel unterstützt bis zu 100 QSOs. QSOs Update Progress QSOs Update Fortschritt QLog Error QLog Fehler Callbook login failed Callbook-Anmeldung fehlgeschlagen Callbook error: Callbook-Fehler: All Clubs Alle Clubs eQSL Download Image failed: eQSL-Bild download fehlgeschlagen: LotwQSLDownloader Cannot open temporary file Kann temporäre Datei nicht öffnen Incorrect login or password Falscher Benutzername oder falsches Passwort LotwUploader Upload cancelled by user Upload vom Benutzer abgebrochen Upload rejected by LoTW Upload durch LoTW abgelehnt Unexpected response from TQSL server Unerwartete Antwort vom TQSL-Server TQSL utility error TQSL-Utility Fehler TQSLlib error TQSLib Fehler Unable to open input file Kann Eingabedatei nicht öffnen Unable to open output file Kann Ausgabedatei nicht öffnen All QSOs were duplicates or out of date range Alle QSOs waren Duplikate oder außerhalb des Datumsbereichs Some QSOs were duplicates or out of date range Einige QSOs waren Duplikate oder außerhalb des Datumsbereichs Command syntax error Befehls-Syntaxfehler LoTW Connection error (no network or LoTW is unreachable) LoTW Verbindungsfehler (kein Netzwerk oder LoTW nicht erreichbar) Unexpected Error from TQSL Unerwarteter Fehler von TQSL TQSL not found TQSL nicht gefunden TQSL crashed TQSL abgestürzt MainWindow Rig Map Karte Toolbar Werkzeugleiste &File &Datei &Logbook &Logbuch &Equipment &Geräte &Help &Hilfe &Window Fe&nster Se&rvice Clock Uhr WSJTX WSJTX Rotator Rotor Bandmap Online Map Online Karte CW Console Chat Profile Image Profilfoto &Settings Einste&llungen &Import &Importieren &Export &Exportieren Mailing List... Edit Bearbeiten Keep Options Optionen behalten Restore connection options after application restart Verbindungsoptionen nach dem Neustart der Anwendung wiederherstellen Connect R&ig Verbinde R&ig Alerts Alerts Quit Beenden Application - Quit App - Beenden Pack Data && Settings Daten und Einstellungen packen Unpack Data && Settings Daten und Einstellungen entpacken New QSO - Clear Neuer Kontakt – Löschen &About &Über New QSO - Save Neuer Kontakt – Speichern S&tatistics S&tatistik QSL &Gallery QSL &Galerie Developer Tools Entwickler-Tools Run custom read-only SQL queries against the logbook database Benutzerdefinierte SQL-Abfragen (nur lesen) für die Logbuchdatenbank ausführen Print QSL &Labels QSL-Etiketten &drucken Connect R&otator Verbinde R&otor QSO &Filters QSO &Filter &Awards DXCC &Submission List DXCC-&Einreichungsliste Generate a list of contacts to submit for ARRL DXCC award credit Liste von Verbindungen zur Einreichung für ARRL DXCC-Anerkennung erstellen Beep Connect &CW Keyer Verbinde &CW Keyer &Wiki &Wiki Report &Bug... Fehler &melden... &Manual Entry &Manueller Eintrag Switch New Contact dialog to the manually entry mode<br/>(time, freq, profiles etc. are not taken from their common sources) Schalte den Dialog "Neuer Kontakt" in den manuellen Eingabemodus<br/>(Zeit, Frequenz, Profile etc. werden nicht aus ihren gemeinsamen Quellen übernommen) Save Arrangement Arrangement speichern Logbook - Search Callsign Logbuch - Suche New QSO - Add text from Callsign field to Bandmap Neuer Kontakt - Übertragen Sie den Text vom Rufzeichenfeld in die Bandmap Rig - Band Down Rig - Band (-) Rig - Band Up Rig - Band (+) New QSO - Use Callsign from the Whisperer Neuer Kontakt - Verwende Rufzeichen vom Whisperer CW Console - Key Speed Up CW Console - Geschwindigkeit (+) CW Console - Key Speed Down CW Console - Geschwindigkeit (-) CW Console - Profile Up CW Console - CW-Keyer Profil (+) CW Console - Profile Down CW Console - CW-Keyer Profil (-) Rig - PTT On/Off Rig - PTT On/Off All Bands Alle Bänder Each Band Jedes Band Each Band && Mode Jedes Band & Mode No Check Keine Kontrolle Single Eine für alles Per Band Band Stop Stoppen Reset Zurücksetzen None Keine Upload Hochladen Service - Upload QSOs Service – QSO hochladen Download QSLs QSLs herunterladen Service - Download QSLs Service - QSLs herunterladen Theme: Native Thema: Native Theme: QLog Light Thema: QLog Light Theme: QLog Dark Thema: QLog Dark What's New Was ist neu Export Cabrillo Cabrillo exportieren Wsjtx Wsjtx Contest Contest Dupe Check Dupe-Prüfung Sequence Sequenz Linking Exchange With Exchange mit verknüpfen Edit Rules Regeln bearbeiten Clear Löschen Show Alerts Alerts anzeigen About Über DX Cluster Color Theme Farbschema Not enabled for non-Fusion style Für keinen anderen Stil als Fusion zulässig Press to tune the alert Drücken zum Einstellen des Alarms Clublog Immediately Upload Error Clublog-Sofort-Upload-Fehler <b>Error Detail:</b> op: op: A New Version Eine neue Version A new version %1 is available. Eine neue Version %1 ist verfügbar. Remind Me Later Später erinnern Download Herunterladen Failed to encrypt credentials. Verschlüsseln der Zugangsdaten fehlgeschlagen. Database files (*.dbe);;All files (*) Datenbankdateien (*.dbe);;Alle Dateien (*) Failed to create temporary file. Temporäre Datei konnte nicht erstellt werden. Failed to dump the database. Datenbank-Dump fehlgeschlagen. Compressing database... Datenbank wird komprimiert… Database successfully dumped to %1 Datenbank erfolgreich exportiert nach %1 Failed to compress the database. Datenbank konnte nicht komprimiert werden. Failed to prepare database for import. Datenbank konnte nicht für den Import vorbereitet werden. Classic Klassisch Do you want to remove the Contest filter %1? Möchten Sie den Contest-Filter %1 entfernen? Contest: Contest: <h1>QLog %1</h1><p>&copy; 2019 Thomas Gatzweiler DL2IC<br/>&copy; 2021-2026 Ladislav Foldyna OK1MLG<br/>&copy; 2025-2026 Michael Morgan AA5SH<br/>&copy; 2025-2026 Kyle Boyle VE9KZ</p><p>Based on Qt %2<br/>%3<br/>%4<br/>%5</p><p>Icon by <a href='http://www.iconshock.com'>Icon Shock</a><br />Satellite images by <a href='http://www.nasa.gov'>NASA</a><br />ZoneDetect by <a href='https://github.com/BertoldVdb/ZoneDetect'>Bertold Van den Bergh</a><br />TimeZone Database by <a href='https://github.com/evansiroky/timezone-boundary-builder'>Evan Siroky</a> <h1>QLog %1</h1><p>&copy; 2019 Thomas Gatzweiler DL2IC<br/>&copy; 2021-2026 Ladislav Foldyna OK1MLG<br/>&copy; 2025-2026 Michael Morgan AA5SH<br/>&copy; 2025-2026 Kyle Boyle VE9KZ</p><p>Qt %2<br/>%3<br/>%4<br/>%5</p><p>Icon by <a href='http://www.iconshock.com'>Icon Shock</a><br />Satellite images by <a href='http://www.nasa.gov'>NASA</a><br />ZoneDetect by <a href='https://github.com/BertoldVdb/ZoneDetect'>Bertold Van den Bergh</a><br />TimeZone Database by <a href='https://github.com/evansiroky/timezone-boundary-builder'>Evan Siroky</a> N/A MapWebChannelHandler Grid Gitterfeld Gray-Line Beam Aurora MUF IBP Chat WSJTX - CQ WSJTX - CQ Path Weg NewContactWidget Callsign Rufzeichen Date Datum Time On Startzeit W Rig RSTr RSTe TX: RX: RSTs RSTa 80m &Details &Details the contacted station's DARC DOK (District Location Code) (ex. A01) DARC-DOK (Ortsverbandkenner) der kontaktierten Station (z.B. A01) Station Station Info <b>DUPE !!!</b> <b>DUPE !!!</b> Lookup the call on the web. The query URL can be changed in Settings -> Callbook Suchen Sie das Rufzeichen im Internet. Die Abfrage-URL kann unter Einstellungen -> Callbook geändert werden Web Duration Dauer World Wide Flora & Fauna QSL Send Status QSL Ausgangsstatus Paper Papier <b>Yes</b> - an outgoing QSL card has been sent; the QSO has been uploaded to, and accepted by, the online service<br/><b>No</b> - do not send an outgoing QSL card; do not upload the QSO to the online service<br/><b>Requested</b> - the contacted station has requested a QSL card; the contacted station has requested the QSO be uploaded to the online service<br/><b>Queued</b> - an outgoing QSL card has been selected to be sent; a QSO has been selected to be uploaded to the online service<br/> <b>Ja</b> - eine ausgehende QSL-Karte wurde gesendet; das QSO wurde in den Online-Dienst hochgeladen und von diesem akzeptiert.<br/><b>Nein</b> - keine ausgehende QSL-Karte senden; das QSO nicht in den Online-Dienst hochladen.<br/><b>Angefordert</b> - die kontaktierte Station hat eine QSL-Karte angefordert; die kontaktierte Station hat angefordert, dass das QSO in den Online-Dienst hochgeladen wird.<br/><b>Wartend</b> - eine ausgehende QSL-Karte wurde zum Senden ausgewählt; ein QSO wurde zum Hochladen in den Online-Dienst ausgewählt.<br/> LoTW eQSL QSL Send via QSL Ausgang via D&X Stats D&X Stats <b>DXCC Statistics</b> <b>DXCC-Statistik</b> <b>Station Statistics</b> <b>Stationsstatistik</b> Blank Leer My &Notes Eigene &Anmerkungen Member: Mitglied: No Nein Yes Ja Requested Angefordert Queued Wartend QSL via QSL via Propagation Mode Ausbreitungsmodus Bureau Büro Direct Direkt Antenna Antenne MHz M&y Station &Eigene Station Reset Zurücksetzen Save Speichern Frequency Frequenz 59 Mode Betriebsart Ignored Ignoriert Electronic Elektronisch QLog Error QLog Fehler Callbook login failed Callbook-Anmeldung fehlgeschlagen LP LP New Entity! Neuer Eintrag! New Band! Neues Band! New Mode! Neue Betriebsart! New Band & Mode! Neues Band & Betriebsart! New Slot! Neuer Slot! Worked Gearbeitet Confirmed Bestätigt GE GA GM GM GA GT m Callbook search is active Callbook-Suche ist aktiv Contest ID must be filled in to activate Zur Aktivierung muss die Contest-ID ausgefüllt werden It is not the name of the contest but it is an assigned<br>Contest ID (ex. CQ-WW-CW for CQ WW DX Contest (CW)) Description of the contacted station's equipment Beschreibung der Ausrüstung der kontaktierten Station Callbook search is inactive Callbook-Suche ist inaktiv Expand/Collapse Erweitern/Zusammenklappen two or four adjacent Maidenhead grid locators, each four characters long, (ex. EN98,FM08,EM97,FM07) zwei oder vier nebeneinander liegende, jeweils vier Zeichen lange Gitterfelder (z. B. EN98,FM08,EM97,FM07) Special Activity Group Spezielle Aktivitätsgruppe Special Activity Group Information OmnirigRigDrv Rig 1 Rig 1 Rig 2 Rig 2 Initialization Error Initialisierungsfehler Rig status changed Rig-Status geändert Rig is not connected Rig nicht verbunden OmnirigV2RigDrv Rig 1 Rig 1 Rig 2 Rig 2 Rig 3 Rig 3 Rig 4 Rig 4 Initialization Error Initialisierungsfehler Rig status changed Rig-Status geändert Rig is not connected Rig nicht verbunden PSTRotDrv Rot 1 Cannot bind a port Ein Port kann nicht gebunden werden Cannot get IP Address for IP-Adresse kann nicht abgerufen werden No IPv4 Address for Keine IPv4-Adresse für Error Occurred Fehler ist aufgetreten Operation Timeout Zeitüberschreitung PaperQSLDialog Manage QSL Card QSL-Karte verwalten Available QSLs Verfügbare QSL Copy the input file from the source folder to the QLog Internal QSL Storage folder.<br/>The original file remains unchanged in the source folder Kopieren Sie die Bilddatei aus dem Quellordner in den Ordner "QLog Internal QSL Storage".<br/>Die Originaldatei bleibt unverändert im Quellordner Import QSL QSL importieren Add File Datei hinzufügen Remove Entfernen Delete Löschen Delete QSL? Löschen QSL? Open Öffnen Toggle Favorite Favorit PlatformSettingsDialog Platform-specific Settings Plattform-spezifische Einstellungen The database was exported from a different platform. Please verify or update the following settings. You can leave fields empty and configure them later in Settings. Die Datenbank wurde von einer anderen Plattform exportiert. Bitte überprüfen oder aktualisieren Sie die folgenden Einstellungen. Sie können Felder leer lassen und später in den Einstellungen konfigurieren. Setting Einstellungen Value Wert Continue Fortsetzen Select File Datei auswählen All Files (*) Alle Dateien (*) ProfileImageWidget Profile Image Profilfoto QCoreApplication QLog Help QLog Hilfe QMessageBox QLog Error QLog Fehler QLog is already running QLog wird bereits ausgeführt Failed to process pending database import. Ausstehenden Datenbankimport konnte nicht verarbeitet werden. The database was imported successfully, but the stored passwords could not be restored (decryption failed or the data is corrupted). All service passwords have been cleared and must be re-entered in Settings. Die Datenbank wurde erfolgreich importiert, aber die gespeicherten Passwörter konnten nicht wiederhergestellt werden (Entschlüsselung fehlgeschlagen oder Daten sind beschädigt). Alle Service-Passwörter wurden gelöscht und müssen in den Einstellungen erneut eingegeben werden. Could not connect to database. Keine Verbindung zur Datenbank möglich. Could not export a QLog database to ADIF as a backup.<p>Try to export your log to ADIF manually Kann QLog-Datenbank nicht als Backup nach ADIF exportieren.<p>Versuchen Sie, Ihr Log manuell nach ADIF zu exportieren Database migration failed. Migration der Datenbank fehlgeschlagen. QLog Warning QLog Warnung Club List Update failed. Cannot remove old records Aktualisierung der Clubliste fehlgeschlagen. Alte Datensätze können nicht entfernt werden Club List Update failed. Cannot plan new downloads Aktualisierung der Clubliste fehlgeschlagen. Kann keine neuen Downloads durchführen QLog Critical QLog kritischer Fehler Cannot save a password for %1 to the Credential Store Das Passwort für %1 kann nicht im Passwort Speicher gespeichert werden Cannot get a password for %1 from the Credential Store Es kann kein Passwort für %1 aus dem Passwort Speicher abgerufen werden Unexpected Club List download. Canceling next downloads Unerwartete Clubliste herunterladen. Nächste Downloads beenden Unexpected Club List content for Unerwarteter Inhalt der Clubliste für Network error. Cannot download Club List for Netzwerkfehler. Clubliste kann nicht heruntergeladen werden für DXC Server Name Error DXC Server Namensfehler DXC Server address must be in format<p><b>[username@]hostname:port</b> (ex. hamqth.com:7300)</p> Format der DXC-Server-Adresse <p><b>[benutzername@]hostname:Port</b> (z. B. hamqth.com:7300)</p> DX Cluster Password DX Cluster Passwort Invalid Password Falsches Passwort DXC Server Connection Error DXC Server Verbindungsfehler The fields <b>%0</b> will not be saved because the <b>%1</b> is not filled. Die Felder <b>%0</b> werden nicht gespeichert, da <b>%1</b> nicht ausgefüllt ist. Your callsign is empty. Please, set your Station Profile Ihr Rufzeichen ist nicht angegeben. Bitte richten Sie Ihr Stationsprofil ein QLog Info QLog Info Activity name is already exists. Der Aktivitätsname existiert bereits. Rule name is already exists. Name der Regel ist bereits vorhanden. Callsign Regular Expression is incorrect. Der reguläre Ausdruck für das Rufzeichen ist fehlerhaft.. Comment Regular Expression is incorrect. Kommentar Regulärer Ausdruck ist fehlerhaft. Cannot Update Alert Rules Kann Alarmregeln nicht aktualisieren Filter name is already exists. Filtername ist bereits vorhanden. Please, define at least one Station Locations Profile Bitte definieren Sie mindestens ein Stationsstandortprofil WSJTX Multicast is enabled but the Address is not a multicast address. WSJTX Multicast ist aktiviert, aber die Adresse ist keine Multicast-Adresse. Loop detected. Raw UDP forward uses the same port as the WSJT-X receiving port. Schleife erkannt. Raw-UDP-Weiterleitung verwendet denselben Port wie der WSJT-X-Empfangsport. Rig port must be a valid COM port.<br>For Windows use COMxx, for unix-like OS use a path to device Rig port muss ein gültiger COM-Port sein.<br>Für Windows verwende COMxx, für Unix-ähnliche Betriebssysteme verwende einen Pfad zum Gerät Rig PTT port must be a valid COM port.<br>For Windows use COMxx, for unix-like OS use a path to device Rig-PTT-Port muss ein gültiger COM-Port sein. Für Windows verwenden Sie COMxx, für Unix-ähnliche Betriebssysteme verwenden Sie einen Pfad zum Gerät <b>TX Range</b>: Max Frequency must not be 0. <b>TX-Bereich</b>: Max Frequenz darf nicht 0 sein. <b>TX Range</b>: Max Frequency must not be under Min Frequency. <b>TX-Bereich</b>: Die Maximalfrequenz darf nicht niedriger als die Minimalfrequenz sein. Rotator port must be a valid COM port.<br>For Windows use COMxx, for unix-like OS use a path to device Rotor-Port muss ein gültiger COM-Port sein.<br>Für Windows verwenden Sie COMxx, für Unix-ähnliche Betriebssysteme verwenden Sie einen Pfad zum Gerät CW Keyer port must be a valid COM port.<br>For Windows use COMxx, for unix-like OS use a path to device CW Keyer Port muss ein gültiger COM-Port sein.<br>Für Windows verwenden Sie COMxx, für unix-ähnliche Betriebssysteme verwenden Sie einen Pfad zum Gerät Cannot change the CW Keyer Model to <b>Morse over CAT</b><br>No Morse over CAT support for Rig(s) <b>%1</b> Kann das CW-Keyer Modell nicht zu <b>CW-über-CAT</b> ändern.<br>Keine CW-über-CAT Unterstützung für Rig(s) <b>%1</b> Cannot delete the CW Keyer Profile<br>The CW Key Profile is used by Rig(s): <b>%1</b> Kann das CW-Keyer Profil nicht löschen.<br>Das Profil wird verwendet von Rig(s): <b>%1</b> Operator Callsign has an invalid format Das Operator-Rufzeichen hat ein ungültiges Format Gridsquare has an invalid format Gitterfeld hat ein falsches Format VUCC Grids have an invalid format (must be 2 or 4 Gridsquares separated by ',') VUCC Gitterfeld hat ein falsches Format (es müssen 2 oder 4 Gitterfelder sein, getrennt durch ',') Country must not be empty Das Land darf nicht leer sein CQZ must not be empty CQZ darf nicht leer sein ITU must not be empty ITU darf nicht leer sein Callsign has an invalid format Rufzeichen hat ein falsches Format Filename is empty Dateiname ist leer Cannot write to the file Kann nicht in die Datei schreiben QLog Information QLog Information Exported. Exportiert. Exported %n contact(s). %n Kontakt(e) exportiert. Chat Error: Chat Fehler: Cannot update QSO Filter Conditions QSO-Filter kann nicht aktualisiert werden <b>Rig Error:</b> <b>Rotator Error:</b> <b>CW Keyer Error:</b> QObject Cannot connect to DXC Server <p>Reason <b>: Kann keine Verbindung zum DXC Server herstellen <p>Ursache <b>: Connection Refused Verbindung abgelehnt Host closed the connection Der Host hat die Verbindung beendet Host not found Host nicht gefunden Timeout Zeitüberschreitung Network Error Netzwerkfehler Internal Error Interner Fehler Importing Database Datenbank wird importiert Opening Database Datenbank öffnen Backuping Database Datenbank sichern Migrating Database Datenbank migrieren Starting Application Anwendung starten My Rig Eigener Rig Logging Station Callsign Logging-Station Rufzeichen My Gridsquare Eigenes Gitterfeld Operator Name Operator Name Operator Callsign Operator Rufzeichen My City Eigene Stadt My Country Eigenes Land My County Eigener Landkreis My IOTA Eigene IOTA Nummer My SOTA Eigene SOTA Nummer My Special Interest Activity Eigene spezielle Interessenaktivität My Spec. Interes Activity Info Eigene spezielle Interessenaktivität Info My VUCC Grids Eigenes VUCC Gitterfeld My WWFF Eigener WWFF My POTA Ref Eigene POTA Ref My DARC DOK Eigenes DARC DOK My ITU Eigene ITU Zone My CQZ Eigene CQZ My DXCC Eigenes DXCC Land <b>Imported</b>: %n contact(s) <b>Importiert</b>: %n Kontakt(e) <b>Warning(s)</b>: %n <b>Warnungen</b>: %n <b>Error(s)</b>: %n <b>Fehler</b>: %n km km miles mil Not a valid QLog database Keine gültige QLog-Datenbank Database version too new (requires newer QLog version) Datenbankversion zu neu (erfordert neuere QLog-Version) Database is not QLog Export file Datenbank ist keine QLog-Exportdatei TQSL Path TQSL Pfad (Flatpak internal path) (Interner Flatpak-Pfad) Rig Rig Rig PTT Rig rigctld Rotator Rotor CW Keyer CW Key TOTAL Worked Summe Gearbeitet TOTAL Confirmed Summe Bestätigt Confirmed Bestätigt Worked Gearbeitet QRZCallbook QRZ.com QRZ.com QRZUploader General Error Allgemeiner Fehler QSLGalleryDialog QSL Card Gallery QSL-Karten-Galerie Search by callsign... Nach Rufzeichen suchen… Sort by: Sortieren nach: Export Filtered Gefilterte exportieren Date (Newest) Datum (neueste) Date (Oldest) Datum (älteste) Callsign (A-Z) Rufzeichen (A-Z) Callsign (Z-A) Rufzeichen (Z-A) %n QSL card(s) %n QSL-Karte(n) %n QSL-Karte(n) All QSL Cards Alle QSL-Karten Favorites Favoriten By Country Nach Land By Date Nach Datum By Band Nach Band By Mode Nach Modus By Continent Nach Kontinent Remove from Favorites Aus Favoriten entfernen Add to Favorites Zu Favoriten hinzufügen Open Öffnen Save... Speichern… Save QSL Card QSL-Karte speichern Export QSL Cards QSL-Karten exportieren Exported %1 of %2 cards %1 von %2 Karten exportiert QSLImportStatDialog QSL Import Summary Zusammenfassung QSL-Import Summary Zusammenfassung Downloaded: Heruntergeladen: Updated: Aktualisiert: Unmatched: Nicht gefunden: Errors: Fehler: Details Details New QSLs: Neue QSLs: Updated QSOs: Aktualisierte QSOs: Unmatched QSLs: Nicht gefundene QSLs: QSLPrintLabelDialog Print QSL Labels QSL-Etiketten drucken Filter Filter Date Range My Callsign Eigenes Rufzeichen Station Profile Stationsprofil QSL Sent QSL Ausgang User Filter Benutzer-Filter Label Template Etikettenvorlage Page Size: Seitengröße: Columns: Spalte: Rows: Zeile: Label Width: Etikettenbreite: Label Height: Etikettenhöhe: Left Margin: Linker Rand: Top Margin: Oberer Rand: H Spacing: Horizontaler Abstand: V Spacing: Vertikaler Abstand: Label Appearance Erscheinungsbild des Etiketts Print Label Borders Etikettenränder drucken QSOs per Label: QSOs pro Etikett: Footer Left Text: Linker Fußzeilentext: Footer Right Text: Rechter Fußzeilentext: Skip Label: Etikett überspringen: Sans Font: Serifenlose Schrift: Mono Font: Monospace-Schrift: Callsign Size: Größe des Rufzeichens: "To Radio" Size: Größe „To Radio“: "To Radio" Text: Text „To Radio“: Header Size: Kopfzeilen-Größe: Data Size: Datengröße: Date Header Text: Datum-Header-Text: Date Format: Datumsformat: Time Header Text: Zeit-Header-Text: Band Header Text: Band-Header-Text: Mode Header Text: Modus-Header-Text: QSL Header Text: QSL-Header-Text: Extra Column: Zusätzliche Spalte: Extra Column Text Text der zusätzlichen Spalte (DB column name) (Datenbank-Spaltenname) No matching QSOs found Keine passenden QSOs gefunden Page 0 of 0 Seite 0 von 0 Labels: 0 (0 pages) Etiketten: 0 (0 Seiten) Print Drucken Export as PDF Als PDF exportieren Custom Benutzerdefiniert Empty Leer QSOs matching this station profile QSOs, die diesem Stationsprofil entsprechen Labels: %1 (%2 pages) Etiketten: %1 (%2 Seiten) Page %1 of %2 Seite %1 von %2 Export PDF PDF exportieren PDF Files (*.pdf) PDF-Dateien (*.pdf) Mark as Sent Als gesendet markieren Mark printed/exported QSOs as sent? Gedruckte/exportierte QSOs als gesendet markieren? QSODetailDialog Frequency Frequenz dd/MM/yyyy HH:mm:ss Time On Startzeit Time Off Endzeit TX: MHz RX: Blank Leer Callsign Rufzeichen Mode Betriebsart RSTs RSTa RSTr RSTe Band QTH Name Name Comment Kommentar My Notes Eigene Anmerkungen about:blank &Details &Details Country Land Cont Kontinent ITU CQ State Staat County Landkreis Age Alter AF AN AS EU NA OC SA two or four adjacent Gridsquares, each four characters long, (ex. EN98,FM08,EM97,FM07) zwei oder vier nebeneinander liegende, jeweils vier Zeichen lange Gitterfelder (z. B. EN98,FM08,EM97,FM07) IOTA POTA SOTA SIG SIG Info FISTS FISTS SKCC SKCC Ten-Ten Ten-Ten UKSMG UKSMG FISTS CC D&X Stats D&X Stats <b>DXCC Statistics</b> <b>DXCC-Statistik</b> <b>Station Statistics</b> <b>Stationsstatistik</b> Operator Callsign Operator Rufzeichen QSLr Message QSLs Message QSL-Nachricht Contest ID Contest ID Member: Mitglied: DOK Gridsquare Gitterfeld the contacted station's DARC DOK (District Location Code) (ex. A01) DARC-DOK (Ortsverbandkenner) der kontaktierten Station (z.B. A01) VUCC WWFF E-Mail URL Propagation Mode Ausbreitungsmodus Satellite Name Satellit-Name Satellite Mode Satellit-Betriebsart M&y Station &Eigene Station Operator Name Operator Name Rig Antenna Antenne Power Leistung W Sig Info &QSL &QSL - Manage QSL Card QSL-Karte verwalten <b>Yes</b> - an outgoing QSL card has been sent; the QSO has been uploaded to, and accepted by, the online service<br/><b>No</b> - do not send an outgoing QSL card; do not upload the QSO to the online service<br/><b>Requested</b> - the contacted station has requested a QSL card; the contacted station has requested the QSO be uploaded to the online service<br/><b>Queued</b> - an outgoing QSL card has been selected to be sent; a QSO has been selected to be uploaded to the online service<br/> <b>Ja</b> - eine ausgehende QSL-Karte wurde gesendet; das QSO wurde in den Online-Dienst hochgeladen und von diesem akzeptiert.<br/><b>Nein</b> - keine ausgehende QSL-Karte senden; das QSO nicht in den Online-Dienst hochladen.<br/><b>Angefordert</b> - die kontaktierte Station hat eine QSL-Karte angefordert; die kontaktierte Station hat angefordert, dass das QSO in den Online-Dienst hochgeladen wird.<br/><b>Wartend</b> - eine ausgehende QSL-Karte wurde zum Senden ausgewählt; ein QSO wurde zum Hochladen in den Online-Dienst ausgewählt.<br/> QSL Sent via QSL Ausgang via Received Eingang Paper Papier LoTW LoTW eQSL eQSL QSL via Sent Ausgang Show QSL Card QSL-Karte ansehen <b>Yes</b> - an incoming QSL card has been received; the QSO has been confirmed by the online service<br/><b>No</b> - an incoming QSL card has not been received; the QSO has not been confirmed by the online service<br/><b>Requested</b> - the logging station has requested a QSL card; the logging station has requested the QSO be uploaded to the online service<br/> <b>Ja</b> - eine eingehende QSL-Karte wurde angenommen; das QSO wurde vom Online-Dienst bestätigt.<br/><b>Nein</b> - eine eingehende QSL-Karte wurde nicht angenommen; das QSO wurde vom Online-Dienst nicht bestätigt.<br/><b>Angefordert</b> - die loggende Station hat eine QSL-Karte angefordert; die loggende Station hat verlangt, dass das QSO in den Online-Dienst hochgeladen wird.<br/> &Contest RcvNr Nr. erhalten RcvExch Info erhalten SendNr Nr. gesendet SendExch Info gesendet &Reset &Zurücksetzen &Lookup &Suchen No Nein Yes Ja Requested Angefordert Queued Wartend Ignored Ignoriert Bureau Büro Direct Direkt Electronic Elektronisch Submit changes Änderungen übermitteln Really submit all changes? Wirklich alle Änderungen übermitteln? QLog Error QLog Fehler Cannot save all changes - internal error Es können nicht alle Änderungen gespeichert werden - interner Fehler Cannot save all changes - try to reset all changes Es können nicht alle Änderungen gespeichert werden - versuchen Sie, alle Änderungen zurückzusetzen QSO Detail QSO Detail Edit QSO QSO Bearbeiten Downloading eQSL Image eQSL-Bild herunterladen Cancel Abbrechen eQSL Download Image failed: eQSL-Bild download fehlgeschlagen: DX Callsign must not be empty DX-Rufzeichen darf nicht leer sein DX callsign has an incorrect format DX-Rufzeichen hat ein falsches Format TX Frequency or Band must be filled TX-Frequenz oder -Band muss ausgefüllt sein DX Grid has an incorrect format DX Gitterfeld hat ein fehlerhaftes Format Based on callsign, DXCC Country is different from the entered value - expecting Based on callsign, DXCC Continent is different from the entered value - expecting Based on callsign, DXCC ITU is different from the entered value - expecting Based on callsign, DXCC CQZ is different from the entered value - expecting Based on own callsign, own DXCC ITU is different from the entered value - expecting Based on own callsign, own DXCC CQZ is different from the entered value - expecting Based on own callsign, own DXCC Country is different from the entered value - expecting Based on SOTA Summit, Grid does not match SOTA Grid - expecting Based on POTA record, QTH does not match POTA Name - expecting Based on POTA record, Grid does not match POTA Grid - expecting Based on SOTA Summit, my QTH does not match SOTA Summit Name - expecting Based on SOTA Summit, my Grid does not match SOTA Grid - expecting Based on POTA record, my QTH does not match POTA Name - expecting Based on POTA record, my Grid does not match POTA Grid - expecting VUCC has an incorrect format VUCC hat ein fehlerhaftes Format blank Leer Based on Frequencies, Sat Mode should be Sat name must not be empty Der Satellitenname darf nicht leer sein Own Callsign must not be empty Eigenes Rufzeichen darf nicht leer sein Own callsign has an incorrect format Eigenes Rufzeichen hat ein fehlerhaftes Format Own VUCC Grids have an incorrect format Eigenes VUCC Gitterfeld hat ein fehlerhaftes Format LoTW Sent Status to <b>No</b> does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blank LoTW Sent Status <b>Nein</b> macht keinen Sinn, wenn ein QSL Sent Datum gesetzt ist. Setzen Sie das Datum auf 1.1.1900, um das Datumsfeld leer zu lassen Date should be present for LoTW Sent Status <b>Yes</b> Ein Datum sollte für LoTW Sent Status <b>Ja</b> angegeben werden eQSL Sent Status to <b>No</b> does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blank eQSL Sent Status <b>Nein</b> macht keinen Sinn, wenn ein QSL Sent Datum eingestellt ist. Setzen Sie Datum auf 1.1.1900, um das Datumsfeld leer zu lassen Date should be present for eQSL Sent Status <b>Yes</b> Ein Datum sollte für eQSL Sent Status <b>Ja</b> angegeben werden Paper Sent Status to <b>No</b> does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blank Papier Sent Status <b>Nein</b> macht keinen Sinn, wenn ein QSL Sent Datum gesetzt ist. Setzen Sie das Datum auf 1.1.1900, um das Datumsfeld leer zu lassen Date should be present for Paper Sent Status <b>Yes</b> Ein Datum sollte für Papier Sent Status <b>Ja</b> angegeben werden Based on SOTA Summit, QTH does not match SOTA Summit Name - expecting Auf Grundlage der SOTA-Daten stimmt das QTH nicht mit dem SOTA Gipfelname überein - erwartend TX Band should be TX-Band sollte sein RX Band should be RX-Band sollte sein Callbook error: Callbook-Fehler: <b>Warning: </b> <b>Warnung: </b> Validation Überprüfung Yellow marked fields are invalid.<p>Nevertheless, save the changes?</p> Gelb markierte Felder sind ungültig.<p>Dennoch die Änderungen speichern?</p> &Save &Speichern &Edit B&earbeiten QSOFilterDetail QSO Filter Detail QSO Filter Details Filter Name: Filter Name: Find QSO which match QSO mit Suchfilter finden All the following conditions Alle folgenden Bedingungen Any of the following conditions Eine der folgenden Bedingungen Add Condition Bedingung hinzufügen Equal gleich Not Equal nicht gleich Contains enthält Not Contains enthält nicht Greater Than größer als Less Than kleiner als Starts with beginnt mit RegExp Remove Entfernen Must not be empty Darf nicht leer sein QSOFilterDialog QSO Filters QSO-Filter Filters Filter Add Hinzufügen Edit Bearbeiten Remove Entfernen Rig No Rig Profile selected Kein Rig-Profil ausgewählt Rigctld Error Rigctld-Fehler Initialization Error Initialisierungsfehler Internal Error Interner Fehler Cannot open Rig Kann Rig nicht öffnen RigWidget Form RX Disconnected Nicht verbunden MHz MHz Disable Split Split deaktivieren RIT: 0.00000 MHz XIT: 0.00000 MHz PWR: %1W RigctldAdvancedDialog Rigctld Advanced Settings Erweiterte Rigctld-Einstellungen Rigctld Path: Rigctld-Pfad: Leave empty for auto-detection Leer lassen für automatische Erkennung Browse Durchsuchen Auto-detect Rigctld path Rigctld-Pfad automatisch erkennen Auto-Detect Automatische Erkennung Rigctld Version: Rigctld-Version: Additional Arguments: Zusätzliche Argumente: e.g. -v -v for verbose logging z. B. -v -v für ausführliche Protokollierung Cannot be changed Kann nicht geändert werden Auto Detect Automatische Erkennung rigctld was not found on this system. Please install Hamlib or specify the path manually. rigctld wurde auf diesem System nicht gefunden. Bitte installieren Sie Hamlib oder geben Sie den Pfad manuell an. Executable (*.exe);;All files (*.*) Ausführbare Datei (*.exe);;Alle Dateien (*.*) All files (*) Alle Dateien (*) Select rigctld executable Rigctld ausführbare Datei auswählen Not found Nicht gefunden RigctldManager rigctld executable not found in /app/bin/. This should not happen in Flatpak build. Rigctld-Ausführbare Datei wurde in /app/bin/ nicht gefunden. Dies sollte im Flatpak-Build nicht passieren. rigctld executable not found. Please install Hamlib or specify the path in Advanced settings. Rigctld-Ausführbare Datei wurde nicht gefunden. Bitte installieren Sie Hamlib oder geben Sie den Pfad in den erweiterten Einstellungen an. Hamlib major version mismatch: QLog was compiled with Hamlib %1 but rigctld reports version %2.%3.%4. Rig model IDs are incompatible between major versions. Hamlib-Hauptversionskonflikt: QLog wurde mit Hamlib %1 kompiliert, aber rigctld meldet Version %2.%3.%4. Rig-Modell-IDs sind zwischen Hauptversionen nicht kompatibel. Port %1 is already in use. Another rigctld or application may be running on this port. Port %1 wird bereits verwendet. Ein anderer rigctld oder eine Anwendung läuft möglicherweise auf diesem Port. rigctld started but not responding on port %1. Rigctld wurde gestartet, reagiert aber nicht auf Port %1. Failed to start rigctld: %1 %2 Rigctld konnte nicht gestartet werden: %1 %2 rigctld crashed. rigctld ist abgestürzt. rigctld timed out. rigctld hat die Zeitüberschreitung erreicht. Write error with rigctld. Schreibfehler bei rigctld. Read error with rigctld. Lese Fehler bei rigctld. Unknown rigctld error. Unbekannter rigctld-Fehler. Rotator No Rotator Profile selected Kein Rotor-Profil ausgewählt Initialization Error Initialisierungsfehler Internal Error Interner Fehler Cannot open Rotator Kann Rotor nicht öffnen RotatorWidget Form Az: ° Goto Previous Button Profile Vorheriges Tastenprofil Next Button Profile Nächstes Tastenprofil QSO LP QSO Long Path QSO SP QSO Short Path SettingsDialog Settings Einstellungen Station Station Callsign Rufzeichen Rigs Delete Löschen Add Hinzufügen Model Modell SOTA (Optional parameter) SOTA (optional) SOTA SIG IOTA Profile Name Profilname IOTA (Optional parameter) IOTA (optional) SIG Information (Optional parameter) SIG Information (optional) VUCC QTH VUCC Grids (Optional parameter). Ex. EN98,FM08,EM97,FM07 VUCC Gitterfelder (optional). Beisp. EN98,FM08,EM97,FM07 Baudrate Baudrate Default PWR Standard-Ausgangsleistung Enter default PWR (ex. when Rig is disconnected) Standard-Ausgangsleistung eingeben (z.B. wenn der Rig nicht verbunden ist) W 1200 1200 2400 2400 4800 4800 9600 9600 19200 19200 38400 38400 57600 57600 115200 115200 Data Bits Daten Bit Profiles Profile Equipment Geräte Antennas Antennen Profiles Profile Description Beschreibung Use COMxx for Window or path to COM port under Unix-like OS Verwende COMxx für Windows oder den Pfad zum COM-Anschluss unter Unix-ähnlichen Betriebssystemen List of all available CW Shortcuts Profiles Liste der verfügbaren CW Funktionstastenprofile Minimum and maximum TX frequencies. Specific ranges are derived from allowed Band in the Setting. Niedrigste und höchste Sendefrequenzen. Die spezifischen Bereiche ergeben sich aus dem zulässigen Band in der Einstellung. TX Range TX Frequenzbereich - - Enter manually RIT or Transverter Offset Eingabe RIT oder Transverter Offset Enter manually XIT or Transverter offset Eingabe XIT oder Transverter Offset 5 6 6 7 7 8 8 Stop Bits 1 2 2 Flow Control None Hardware Software Parity No Even Odd Space Mark Poll Interval ms Host Name HamLib does not support to change a destination port. HamLib unterstützt keine Änderung eines Zielports. Power Leistung VFO RX Offset (RIT) MHz World Wide Flora & Fauna (Optional parameter) World Wide Flora & Fauna (optional) WWFF Mode Betriebsart Freq Frequenz TX Offset (XIT) PTT State PTT Status Default Speed Standard WPM WPM CW Shortcut Profiles CW Funktionstasten Profile F1 F1 Short Desciption of the Button (up to 7 chars) Kurzbeschreibung der Schaltfläche (bis zu 7 Zeichen) F2 F2 F3 F3 F4 F4 F5 F5 F6 F6 F7 F7 Blank Leer Rig Features Rig Merkmale QSY Wiping POTA SIG (Optional parameter). SIG (optional). SIG Info CW Speed Sync WPM-Sync Rotators Rotoren Query Order Reihenfolge der Abfrage Primary Primär Secondary Sekundär QRZ.com <b>Notice:</b> At least a QRZ XML Subscription is recommended to access detailed information. Without a subscription, you will obtain limited data from QRZ, such as missing grid and other fields. <b>Notiz:</b> Es wird empfohlen, mindestens ein QRZ-XML-Abonnement abzuschließen, um detaillierte Informationen zu erhalten. Ohne ein Abonnement erhalten Sie nur begrenzte Daten von QRZ, z. B. Gitterfeld und andere Felder. QSOs are uploaded immediately QSOs werden sofort hochgeladen Using an internal TQSL instance Verwendung einer internen TQSL Port where QLog listens an incoming traffic from WSJT-X Port, an dem QLog auf eingehenden Datenverkehr von WSJT-X wartet Raw UDP Forward UDP Rohdaten-Weiterleitung Profile name that is used as the alias for the Callsign, Gridsquare, Operator name, and QTH (required parameter) Profilname, der als Alias für Rufzeichen, QTH-Locator, Operator-Name und QTH verwendet wird (erforderlich) CW Keyers CW-Keyer Keyer Profiles Keyer Profile List of all available CW Keyers Liste der verfügbaren CW Keyer Keyer Mode Keyer Modus N/A Assigned CW Keyer Zugeordneter CW-Keyer CW Keyer Speed CW-Keyer WPM Port Type Port Typ Serial Serial User Buttons Profiles Funktionstasten Profile Button 1 Taste 1 Button 2 Taste 2 Button 3 Taste 3 Button 4 Taste 4 ° Operator Name Operator Name ITU ITU CQZ CQZ Operator Callsign Operator Rufzeichen Country Land Station Callsign Logging Station Rufzeichen Callsign of operator (Optional parameter, if different from station callsign) Rufzeichen des Operators (Optionale Angabe, falls es vom Stationsrufzeichen abweicht) County Landkreis Station County Location (Optional parameter) DOK DOK Azimuth Beamwidth Azimuth Offset Valid range value is 0° - 100° (0° Unspecified) Gültiger Wertebereich: 0° - 100° (0° unbestimmt) Unspecified Unbestimmt Swap Paddles Paddles vertauschen Interface Interface Offsets Offset PTT Type PTT Typ PTT Port PTT Port DX Spots to Rig DX-Spots zum Rig Paddle Only Sidetone Sidetone Freq: Sidetone-Frequenz: <DXCALL> = DX Callsign <NAME> = DX Operator Name <RST> = Report 599 <RSTN> = Report 5NN <GREETING> = Greenting GM/GA/GE <QTH> = QTH <MYCALL> = My Callsign <MYNAME> = My Name <MYQTH> = My QTH <MYLOCATOR> = My Gridsquare <MYGRID> = My Gridsquare <MYSIG> = My SIG <MYSIGINFO> = My SIG Information <MYIOTA> = My IOTA <MYSOTA> = MY SOTA <MYWWFT> = My WWFT <MYVUCC> = MY VUCC <MYPWR> = My Power in W <EXCHSTR> = Contest Exchange Message <EXCHNR> = Contest Exchange Serial Number <EXCHNRN> = Contest Exchange Serial Number (9→N, 0→T) <+> = Speed +5 WPM (<++> = +10 WPM, etc.) <-> = Speed -5 WPM (<--> = -10 WPM, etc.) <DXCALL> = DX Rufzeichen <NAME> = DX Operator Name <RST> = Report 599 <RSTN> = Report 5NN <GREETING> = Grussformel GM/GA/GE <QTH> = QTH <MYCALL> = Eigenes Rufzeichen <MYNAME> = Eigener Name <MYQTH> = Eigenes QTH <MYLOCATOR> = Eigenes Gitterfeld <MYSIG> = Eigenes SIG <MYSIGINFO> = Eigene SIG Information <MYIOTA> = Eigenes IOTA <MYSOTA> = Eigenes SOTA <MYWWFT> = Eigenes WWFT <MYVUCC> = Eigenes VUCC <MYPWR> = Eigene Leistung in W <EXCHSTR> = Contest Exchange <EXCHNR> = Contest Exchange Serial Number <EXCHNRN> = Contest Exchange Serial Number (9→N, 0→T) <+> = Geschwindigkeit +5 WPM (<++> = +10 WPM, usw.) <-> = Geschwindigkeit -5 WPM (<--> = -10 WPM, usw.) RX: TX: Split Start rigctld daemon to share rig with other applications (e.g. WSJT-X) Rigctld-Daemon starten, um das Rig mit anderen Anwendungen zu teilen (z. B. WSJT-X) Share Rig via port Rig über Port freigeben Advanced... Erweitert… Rig Port Rig-Port CIV Addr CIV Addr Auto Automatisch RTS RTS DTR DTR Web Lookup Button Schaltfläche Web Suche URL Specify the URL to use for quick search. The <DXCALL> macro will be replaced by the current callsign Geben Sie die URL an, die für die Schnellsuche verwendet werden soll. Das Makro <DXCALL> wird durch das aktuelle Rufzeichen ersetzt Test URL with your Callsign Prüfen Sie die URL mit Ihrem Rufzeichen Test Clubs Active Lists Aktive Listen Immediately Upload Sofort-Upload HRDLog HRDLog It is not a password. It is the upload code received via email after the registration to HRDLOG..net Das ist kein Passwort. Es handelt sich um den Upload-Code, den sie nach der Registrierung bei HRDLOG.net per E-Mail erhalten haben Upload Code Do not translate. Upload Code If it is enabled and Rig is connected then QLog periodically sends On-Air messages to HRDLog Wenn es aktiviert ist und Rig angeschlossen ist, sendet QLog regelmäßig On-Air-Nachrichten an HRDLog Send On-Air On-Air senden Leave empty for auto-detection Leer lassen für automatische Erkennung Auto-detect TQSL path TQSL-Pfad automatisch erkennen Auto-Detect Automatische Erkennung TQSL Version TQSL-Version Default API Key Standard-API-Schlüssel Callsign-specific API Keys API-Schlüssel, die auf das Rufzeichen zugeschnitten sind Wavelog Wavelog API Key API-Schlüssel Danger Zone Gefahrenzone <b>⚠ This is a danger zone. Proceed with caution, as actions performed here cannot be undone and may have a significant impact on your log.</b> <b>⚠ Dies ist eine Gefahrenzone. Gehen Sie vorsichtig vor, da die ausgeführten Aktionen nicht rückgängig gemacht werden können und erhebliche Auswirkungen auf Ihr Log haben können.</b> Delete All QSOs Alle QSOs löschen Delete All Passwords from the Secure Store Alle Passwörter aus dem sicheren Speicher löschen Endpoint Endpunkt Others Andere Status Confirmed By Bestätigt durch Paper Papier Chat <b>Security Notice:</b> QLog stores all passwords in the Secure Storage. Unfortunately, ON4KST uses a protocol where this password is sent over an unsecured channel as plaintext.</p><p>Please exercise caution when choosing your password for this service, as your password is sent over an unsecured channel in plaintext form.</p> <b>Sicherheitshinweis:</b> QLog speichert alle Passwörter im Secure Storage. Leider verwendet ON4KST ein Protokoll, bei dem dieses Passwort über einen ungesicherten Kanal im Klartext gesendet wird.</p><p>Bitte seien Sie vorsichtig, wenn Sie Ihr Passwort für diesen Dienst wählen, da Ihr Passwort über einen ungesicherten Kanal im Klartext gesendet wird.</p> The '>' character is interpreted as a marker for the initial cursor position in the Report column. <br/>Ex.: '5>9' means the cursor will be positioned on the second character Das Zeichen „>“ wird als Markierung für die anfängliche Cursorposition in der Spalte „Report“ interpretiert.<br/>Beispiel: „5>9“ bedeutet, dass sich der Cursor auf dem zweiten Zeichen befindet <p>List of IP addresses to which QLog forwards raw UDP WSJT-X packets.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste der IP-Adressen, an die QLog unbearbeitete UDP WSJT-X-Pakete weiterleitet.</p>Die IP-Adressen werden durch ein Leerzeichen getrennt und haben die Form IP:PORT Join Multicast Multicast verbinden Enable/Disable Multicast option for WSJTX Aktivieren/Deaktivieren der Multicast-Option für WSJTX Multicast Address Multicast Adresse Specify Multicast Address. <br>On some Linux systems it may be necessary to enable multicast on the loop-back network interface. Geben Sie die Multicast-Adresse an. <br>Auf einigen Linux-Systemen kann es erforderlich sein, Multicast auf der Loopback-Netzwerkschnittstelle zu aktivieren. TTL Time-To-Live determines the range<br> over which a multicast packet is propagated in your intranet. Time-To-Live bestimmt den Bereich<br>, über den ein Multicast-Paket in Ihrem Intranet verbreitet wird. Color CQ Spots CQ-Spots einfärben Enable/Disable sending color-coded status indicators back to WSJT-X for each callsign calling CQ Senden farbcodierter Statusindikatoren für jede CQ-rufende Station zurück an WSJT-X aktivieren/deaktivieren Notifications Benachrichtigungen DX Spots <p> List of IP addresses to which QLog sends UDP notification packets with DX Cluster Spots.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste der IP-Adressen, an die QLog UDP-Notification-Pakete mit DX Cluster Spots sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT QSO Changes QSO Änderungen <p> List of IP addresses to which QLog sends UDP notification packets about a new/updated/deleted QSO in the log.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste der IP-Adressen, an die QLog UDP-Benachrichtigungspakete über ein neues/aktualisiertes/gelöschtes QSO im Log sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT Wsjtx CQ Spots <p> List of IP addresses to which QLog sends UDP notification packets with WSJTX CQ Spots.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste der IP-Adressen, an die QLog UDP-Benachrichtigungspakete mit WSJTX CQ Spots sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT Rig Status Rig-Status <p> List of IP addresses to which QLog sends UDP notification packets when Rig State changes.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste der IP-Adressen, an die QLog UDP-Benachrichtigungspakete mit Rig-Status sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT GUI GUI Time Format Zeitformat 24-hour 24-Stunden AM/PM AM/PM Unit System Einheitensystem Metric Metrisch Imperial Imperial Date Format Datumsformat System System Custom Benutzerdefiniert <a href="https://doc.qt.io/qt-6/qdate.html#fromString-1">Time Format Documentation</a> <a href="https://doc.qt.io/qt-6/qdate.html#fromString-1">Dokumentation des Zeitformats</a> Spot Alerts <p> List of IP addresses to which QLog sends UDP notification packets about user Spot Alerts.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste der IP-Adressen, an die QLog UDP-Benachrichtigungspakete über User Spot Alerts sendet.</p>Die IP-Adressen sind durch ein Leerzeichen getrennt und haben das Format IP:PORT LogID <p>Assigned LogID to the current log.</p>The LogID is sent in the Network Nofitication messages as a unique instance identified.<p> The ID is generated automatically and cannot be changed</> <p>Zugeordnete LogID für das aktuelle Protokoll.</p>Die LogID wird in den Netzwerk-Notifizierungsmeldungen als eindeutige Instanzkennung gesendet.<p>Die ID wird automatisch generiert und kann nicht geändert werden</> ex. 192.168.1.1:1234 192.168.2.1:1234 eQSL Browse Durchsuchen LoTW LoTW TQSL Path TQSL Pfad Network Netzwerk Wsjtx Wsjtx Port ClubLog E-Mail E-Mail Sync && QSL Bands Bänder Modes Betriebsarten DXCC Port Operator name (Optional parameter) Operator-Name (optional) Station Gridsquare (Mandatory parameter) Stations-Gitterfeld (erforderlich) Callsign (Mandatory parameter) Rufzeichen (erforderlich) Gridsquare Gitterfeld List of all available Station Profiles Liste der verfügbaren Stations-Profile QTH Name (Optional parameter) QTH Name (optional) List of all available Rigs Liste der verfügbaren Rigs List of all available Antennas Liste der verfügbaren Antennen Callbook HamQTH Username Benutzername Password Passwort Name Name Report Bericht State Staat Start (MHz) Beginn (MHz) End (MHz) Ende (MHz) SAT Mode SAT Betriebsart Disabled Inaktiv Dummy Morse Over CAT CW-über-CAT CWDaemon FLDigi Single Paddle IAMBIC A IAMBIC B Ultimate High High Low Low Press <b>Modify</b> to confirm the profile changes or <b>Cancel</b>. Drücken Sie <b>Ändern</b>, um die Profiländerungen zu bestätigen oder <b>Abbrechen</b>. Must not be empty Darf nicht leer sein Auto Detect Automatische Erkennung TQSL was not found on this system. Please install TQSL or specify the path manually. TQSL wurde auf diesem System nicht gefunden. Bitte installieren Sie TQSL oder geben Sie den Pfad manuell an. Not found Nicht gefunden Rig sharing is only available for Hamlib driver Rig-Freigabe ist nur für den Hamlib-Treiber verfügbar Rig sharing is not available for network connection Rig-Freigabe ist für Netzwerkverbindungen nicht verfügbar Delete Passwords Passwörter löschen All passwords have been deleted Alle Passwörter wurden gelöscht Deleting all QSOs... Alle QSOs werden gelöscht... Error Fehler Failed to delete all QSOs. Alle QSOs konnten nicht gelöscht werden. members Mitglieder Required internet connection during application start Erfordert Internetverbindung beim Start der Anwendung Modify Ändern Special - Omnirig Special - Omnirig Cannot be changed Kann nicht geändert werden WinKey WinKey Select File Datei auswählen ShortcutEditorModel Description Beschreibung Shortcut Tastenkombination Conflict with a built-in shortcut Konflikt mit einer eingebauten Tastenkombination Conflict with a user-defined shortcut Konflikt mit einer benutzerdefinierten Tastenkombination ShowUploadDialog QSOs to Upload QSOs zum Hochladen Selected QSO Ausgewählte QSOs Upload Hochladen SmartSearchBox Search Suchen StatisticsWidget Statistics Statistik My Gridsquare Eigenes Gitterfeld Show on Map Auf Karte ansehen User Filter Benutzer-Filter Confirmed by Bestätigt durch My Callsign Eigenes Rufzeichen Date Range Datumsbereich LoTW LoTW eQSL eQSL Paper Papier Graph Type Diagramm-Typ QSOs per QSOs pro Percents Prozent Top 10 Histogram Histogramm My Antenna Eigene Antenne My Rig Eigener Rig to bis Band Band Confirmed Not Confirmed Year Jahr Month Monat Day in Week Wochentag Hour Stunde Mode Betriebsart Continent Kontinent Propagation Mode Ausbreitungsmodus Confirmed / Not Confirmed Bestätigt / nicht Bestätigt Countries Länder Big Gridsquares Grossfelder Distance Entfernung QSOs Confirmed/Worked Grids Bestätigte / gearbeitete Gitterfelder ODX ODX Sun Son Mon Mon Tue Die Wed Mit Thu Don Fri Fre Sat Sa Not specified Nicht angegeben No User Filter Kein Benutzerfilter Over 50000 QSOs. Display them? Über 50000 QSOs. Anzeigen? Rendering QSOs... Rendern der QSOs… All Alle TCIRigDrv Rig 0 Rig 0 Rig 1 Rig 1 Rig 2 Rig 2 Rig 3 Rig 3 Error Occurred Fehler aufgetreten Rig status changed Rig-Status geändert Rig is not connected Rig nicht verbunden TimestampFormatDelegate Blank Leer ToAllTableModel Time Zeit Spotter Message Nachricht UploadQSODialog Upload QSOs QSOs hochladen eQSL eQSL LoTW LoTW QRZ.com QRZ.com Clublog Clublog HRDLog HRDLog Wavelog Wavelog Filters Filter Station Profile Stationsprofil My Callsign Eigenes Rufzeichen Gridsquare Gitterfeld Include QSOs Status QSOs mit Sendestatus Under normal circumstances this status means <b>"do not send"</b>.<br/>However, it may sometimes be wanted to ignore this setting when sending a QSL. Unter normalen Umständen bedeutet dieser Status <b>"nicht senden"</b>.<br/>Manchmal kann es jedoch sinnvoll sein, diese Einstellung beim Senden einer QSL zu ignorieren. No Nein Under normal circumstances this status means <b>"Ignore/Invalid"</b>.<br/>However, it may sometimes be wanted to ignore this setting when sending a QSL. Unter normalen Umständen bedeutet dieser Status <b>"ignorieren/fehlerhaft"</b>.<br/>Manchmal kann es jedoch sinnvoll sein, diese Einstellung beim Senden einer QSL zu ignorieren. Ignore Ignorieren None Keine QSLs Message QSL-Nachricht Comment Kommentar QSL Message Field QSL-Nachrichtenfeld QTH Profile QTH Profil This option deletes all QSOs in the Clublog<br>and based on filter, it uploads all QSOs regardless of their status. Diese Option löscht alle QSOs im Clublog<br>und lädt basierend auf dem Filter alle QSOs hoch, unabhängig von ihrem Status. Clear Clublog and reupload QSOs Clublog löschen und QSOs erneut hochladen LoTW / TQSL LoTW / TQSL TQSL Station Location TQSL-Stationstandort Station Profile ID Stationsprofil Reupload All Alles erneut hochladen Show QSOs... QSOs anzeigen... &Upload &Hochladen Unspecified Unbestimmt Hide QSOs... QSOs ausblenden... Uploading to %1 Lade hoch zu %1 Cancel Abbrechen QLog Warning - %1 QLog Warnung - %1 Cannot update QSO Status QSO-Status kann nicht aktualisiert werden Cannot upload the QSO(s): Kann QSO(s) nicht hochladen: QLog Information QLog Information No QSO found to upload. Keine QSO zum Hochladen gefunden. QSO(s) were uploaded to the selected services QSOs wurden zu den ausgewählten Diensten hochgeladen Time Zeit Callsign Rufzeichen Mode Betriebsart Upload to Hochladen zu The values below will be used when an input record does not contain the ADIF values Die folgenden Werte werden verwendet, wenn ein importierter Datensatz die ADIF-Werte nicht enthält Any Irgendein Location callsign (%1) and grid (%2) do not match selected filters Standortrufzeichen (%1) und Grid (%2) stimmen nicht mit den ausgewählten Filtern überein Location callsign (%1) does not match selected callsign (%2) Standortrufzeichen (%1) stimmt nicht mit dem ausgewählten Rufzeichen (%2) überein Location grid (%1) does not match selected grid (%2) Standort-Grid (%1) stimmt nicht mit dem ausgewählten Grid (%2) überein Unknown Unbekannt Service is not configured properly.<p> Please, use <b>Settings</b> dialog to configure it.</p> Service ist nicht richtig eingerichtet.<p> Bitte verwende den <b>Einstellungen</b> Dialog, um es einzurichten.</p> UserListModel Callsign Rufzeichen Gridsquare Gitterfeld Distance Entfernung Azimuth Comment Kommentar WCYTableModel Time Zeit K expK A R SFI SA GMF Au WWVTableModel Time Zeit SFI A K Info WsjtxFilterDialog WSJTX Filters WSJTX-Filter General Filters Allgemeine Filter Log Status Log Status New Band Neues Band New Mode Neuer Mode New Entity Neuer Eintrag New Slot Neuer Slot Worked Gearbeitet Confirmed Bestätigt Continent Kontinent North America Nordamerika Europe Europa South America Südamerika Africa Afrika Antarctica Antarktis Asia Asien Oceania Ozeanien Distance more than Entfernung größer als SNR better than SNR besser als dB dB Extended Filters Erweiterte Filter Member Mitglied No Club List is enabled Keine Clubliste aktiviert WsjtxTableModel SNR SNR Callsign Rufzeichen Gridsquare Gitterfeld Distance Entfernung Last Activity Letzte Aktivität Last Message Letzte Nachricht Member Mitglied WsjtxWidget Form Filtered Gefiltert Column Visibility... Spaltensichtbarkeit... Filter... Filter... Which columns should be displayed Welche Spalten sollen angezeigt werden Filter Spots Filter Spots main Run with the specific namespace. Im spezifischen Namensraum ausführen. namespace Namensraum Translation file - absolute or relative path and QM file name. Übersetzungsdatei - Absoluter oder relativer Pfad und Name der QM-Datei. path/QM-filename path/QM-filename Set language. <code> example: 'en' or 'en_US'. Ignore environment setting. Sprache einstellen. Beispiel <code>: 'en' oder 'en_US'. Ignoriert Betriebssystemeinstellungen. code code Writes debug messages to the debug file Schreibt Debugmeldungen in die Debugdatei Process pending database import (internal use) Ausstehenden Datenbankimport verarbeiten (interne Verwendung) Force update of all value lists (DXCC, SATs, etc.) Aktualisierung aller Wertelisten erzwingen (DXCC, SATs usw.) foldynl-QLog-3252ff9/i18n/qlog_es.qm000066400000000000000000007750641517334601000171550ustar00rootroot00000000000000%a#֍.v֍6#֍x֍_֍)֍1#svp4:O46K}^3kx">@<i~(c.4$<44 4-q44744<4xS4A8)8=BEE$iEEE.<EEEE>ExEH5oH5zH5H5H5APT1TATBT\TTD<VEWVEVEAVEc~f-fush2h3Bh3hc|hKlvF/xZx"xœxxSx{{Q{Ms(HͷTQgAc>t"T g(ugv`ac555U5o5\ksssl-˦A˦*˦˦,˦k˦m:ryT̘|+ ||. ||!g|n|o||Kc p 8>ϭ r$ r=բYb ^Q `%n'7I(C)5m=)5)5C2*?*%*0'+.B6+.++Z..Z/Z'05Z405,L607Pvͪ7pvO8b80:d%7:d:$(:$<@̇l\B6KFM5F-?GHw9HzKHHXHHHHrH؄!I(KOI(KI(KI(KI(KGI(KI%IAEIJ(J+J+J+4 J+9J+{J+J5J;ZNJ;"JJJY zJYJYxMJYJY@KI)Kt:L7LG~L|נLbLb/#MQMM^QMy^MAtNQ? NOPvPJ0P~'P9Q-RTn\RxpRR_SISI6S[<SyLSS>S}T_TJTZSTZ?)TZTZ2TZ?]TexTSTT|T!T.T%TUjUVxV'VCV-VoV*VVE3V{V4VEaVE'VE{VEvWWi`FbWm4WmGW3WTXRXRXXX0MX1$:X1%X1~X2$qX2&!X2X3&ZX3X4&Yf1)YiAYiBYnjYQYYY{UZZgX ZgZk8JZv*nZZ{Z_Z˵Z]Z~c[Y3[˜[d\q\\\\2{]3]%:]t^h^ou^A_þeѕvi(KiuCjh2jh3l[!toz>E}wj~vO$kX$$MTr+9lss f(Y`}Ȅix)l6oHOtJ4s!>YJZ)%%w$%%:>KBJ2;Z n:|f"˹.T sNsw"L4s1Ûs27[ $A4&O4yq1Zn1{h?}`7lZt(QpM;/h#y o .JBNA~NK3&2yK&*;023B54q7%8-~ 8 ;JGQ`IDJ#*tLrRDVCW [M1\T_ )pV`͕pqqUuup vri~w 4W`s7 K|&# BNu<#(bP4"( y.ƨ{4OO7obԙ#E1ġۋsJZzz{$j$`Z`0C2m306 6kVcRD! t7 CN*>P;z$^AeA- lp )T%&Ha' *bt+yd,N:k4<eCiGK!^ZK~T'RAGVԐXGVX"Z;Yu<\H \hSv ]~_s&_̆ݼg6snWsnsnQsn8tNt4!u^uuuxwô҉c6}KR4~3Vj^XŃ 3 R5>sH?KcS?F 3 3jxEΖy3*($=@aR,`5ـ^^: nEn]hȡ _0Vc 0l DD~tn~]*w" 4i$*b\E,C/,6S99M:1 :2 :t"tjt`zӾJi0`|݀c5tSB[Uy+X hJ^'S9_n %m,@~+~~UD4UD ' J$X+NA/*/.Uk3$E 8[;?#@B-.BHB[tFGOoZ_Q\1T@V$V^ϛYG0=\z]PbsdS:fTEdiYi l|6mEp-qgu Tuhv3}n}!4}}}}^}m}|?~YQn77)@DWrɳɳ !*.0yas1B|]<"~h)]H~;k'UG*I -I4nI\IIl&nL n4n_JnnOnyo  %w<ŹIŹŹ#  hqNS,,,,']|]#f'HWiy mY0#`#hzhpiU|CHektj#Wk\,˱>fI_O)Z)4))OBŰ>'ȟ^5CA:̖e ̖e#@̖e̖e?vlv/vE³Z&:XQ4@+92cy_m.vѽCBӎ"bӖ֓W2*֓W"DiL/؄"``&N&3軕 tH4["CAXArCS6ȡV3vnvc \ T opq~~m[bU5T&{׫(X(R))*L,u3$E45.4ۂ/68(@8GS<8R<8y<8<8<8|<8W<=s<z=O==?0\+sAl6BsE%_E?FGJ*KHj?KHjgKNKNiKWbdKXeKX<KXiKXyM9U4VVYʌ\\\\4<`bKsc>A czPxqeB7eg47hhMhhH1<hEej|jD jUl6#mϒ~nMsGtv(DvZVsxx{T|L }H{#'#M%X6K]Lb.HH˴Z˴˴[^FF2FxF{F-F_FvN\]#Jmic~2S""%A zQ`3 \b=Ud'&>'&sIRJyDYRh|U(N!N%2£9Hr ~iNt| ,PYy%Y9SOSSS&8h~44"444v 4}I>a)H,,9s?Ĕ#@~El5IS%I~\=+ƨ55t5tsa;cF͜B>m%W1nMLƗ摴q摴+摴摴摴-摴 摴o:摴 2ih82 L h(^9N0vё3ђ4qRTy# 3T{g b!g6$`4)R[*xL-S,C.0 N0DM111h3^W6 ?s@yg@y,4ABaVI{K)IKaLT*MWNN.fOFQbR/TVXPY3[$\u6y\u_\u~d\uv]@Ir]wZawN:b bըri(s~iE0*iE;iEH$iJs/>Zu_y0zFQy{ι|P}|gx#.n@8HueoJIf^0I|>OCؙ6i)Yk4οiOЂG+x Zݮ"Fu1n1a`切/切G44t9 R  syZ2*@d; q zga>2.~jisr B%@&9_(p(\)%+ p,$-ȱ/=/,0E0vB0lO23NO3N3N3N3N3N3N3N,3N}3N4Y5Yo9^a:<>O@BePA)RAuASKFqKiKVKLRNk*NOl[PtX ZZZ[a``y`Q5es|ee$eݽueݽv!fShfSgC@hPzhP}k|]m6)mZ/p&pwiz;Nztc?z{~R%Qd 3Qpe8 ,k+N +NA+N+NyT+NXcK 'YкsEaJeNe30*1D*1!g*1*1*1U, ı9Q633q"|#jfpƁEݣ;LZE .Jyzvؓ~ɿR~C*a]T3DX&g%tttbr‰Ŷr<]ǒ)KBʸ@Пɰ'o՛%lj-t`ۗZ:yf=W>>#;SZW`rwRd04($jTf 5 7 22[ \1 LH  d, ds dZ d L "U (9E (n )W9 )7y +A -4I= /) /J 1h` 6d^ 8n_ :$o =&Qx @ Ao H0 I{I I2V I2r] I2 I2A I2̊ I2 I2Q I2 JhY Jb Mg)( Mgr@ QBby St Tw U Z \ ] ]J _| _a `> aQ c  cN c d5 esDk e e5D eF f M g. i i>mc j2Q j2 j2m rS M| k Ie *A h.P wr } JR T} ^v :} d  S  q{ 44 i iў SU b 3q 3   ql r6 Ert щ=  =DS 2 $ &  'X 'ھ X  k :} Ľ,N ߢC C,h Ck* k = ˰/ ̡ ' 1) u % Jr = 8 p9 嗓   3± , @ O ˿M !U  9u R K C Dg UY * e/ v $b % s" '^ (] (j , q ,6 . 0a 1)1 43%p 6+{ 80h 80 :R# ;s" ;5 =g2 =/ =T > Y > R > ??, AQi$ B5i Gd J.  J. J- P  Tn UMZ U XEc Zr#$d Z# Z ]5D? a-eN a4$u b cn c¤0 d< d<_ d< d< d<n d< di# dU* d)T e U3 eK eKu eK ee! eN e# e g,5e g7J iun iX k# l[ l[O l[ l[ l[#` l o oh= pq r=5 uy6Y v/ v vM . ?% ٴt X #?q k8 j L Zb = bq 4\ 4L # %  ] ϴ p > ydo  }w J1 KI E Cè C C C@ } $ *q  É% ' 8y1 8} Őx M9& LJ y? ȗ6 yU ~D ~ ʀs`[ ʀsw „ „I vJ v3> vػ 7i[i n8 䓳 U'O u u= 5` C F ߚ f .a 瘟 b1 Ne 9B`K 7 < <] <ܴ < 0%P u ! u w ƔM Ɣn I! v]. vW R D 8y 8ڕ nt #} ] ntW X5 c I@F  TA !LXA !d "V )RX )SW ,34 ,KE . .6RM 6bv 8Y ; B3 GCso J N:Y P.g R?Y RR C Te2 TOm Uo@ ZA ] ^ǥ _u# d] f( fF  h7% lX mpz| q< r Z uD> ~`$j- C"&  , - ɤ U βS T $0" 5+ T` .f J 4ǫ \ @d" @dE }, [ n zV {" PuR Puw@ Pu7 Pu4 Pu1 Pu Pu4 Pux Z- x ]^ n& Õi Õ ~ jP 5T ` b ]) e= ۿ8 DR f ܮ = KGڈ lԻ b fM >E@ j m y E9 $ˤ .+ %Q ( ؄ x. 5# i 5# ew + %$  6  >c 0 Ku\ #m $u %z 'K8 (y )V ) *96 +3o ,G{ -a 0 1jg 1 6 7@` 9$ ;{P ;G >Pg ? @_S B9U8 D:t D$ D5Q G Gx[ Gv Ht IH^ۚ J%p K{I&7 N( P P* RVk RV S# S,d S W X X Yrm Y_ [ [ţvM \-7ދ ^ d!, gLa@ it j& wv wxw wZ {x |B&f %"o $ ];  :T { ÒU  ) ) ) )j ) Cʐ 2 C J֘   d  @ @q @ @D $ $ $+ $ i*x2 0 Ҝ t u [5 [5 [62 de n E -~ Vd7= s" sU d d d" d[  3< 6P aj V P <#p B / S & ~$ ~{ .P s\ U1 - 0kw D!  > E   (o %k  t 6 t r jz ' &fC *8 / /kq 0l 0m 0EoH 0Eo 21^) ;3 @d BP KN U Ug Wgo W+/ W= \" \p:/ _9 _*LI arAV cXs iFCu3 m4 m s w0>D w0> 7 P P Pz P -  n  `4# tRP + $ Ȫ S$ +"c +I +uE l' ok r zl PS8 Psȭ )/ y Si 0 Œ4H <{ ȳ? )$ K ƍA R yn % L bP%NP%(P%P%(Q5fRQRFRSATW`Qc }c$d 3{h,hOjhviiش1Diش<iشBiشJj=>p.JNt7zR#̸D3n]~ZP4P#G 19dK}=ţj:#zF!69f4cGWiN ߌ$|6>&TV&S_E#*[zt%SC4[qGE Lޱ  [W0 [W<1 [WH q& q{ ?>#P%A^P%P%iP%y6s?!aB!ab!#s$&$U*}s,w^1a2 L2 [33l303B6$36.l:X6?mP@`EDPEEuHYH#Id61LP>nPYW];^V$-cIucIWiYV)i^)iTrji"lU)?.U}Ѭ΢Y-#Ňɒ&HD_ˉN3Ue_(WN,dp'U#3us[ih~)Gr)PUOO"  ́VNiϘ#Duֻ4`־Ql"Wwh-hj2)TG]]2Q|!"(i)*Editor de actividadesActivity EditorActivityEditor,Nombre de la actividad Activity NameActivityEditor AntenaAntennaActivityEditor$Campos disponiblesAvailable FieldsActivityEditorzCambiar el orden. Desplazar hacia abajo el campo seleccionado*Change the order. Move selected field downActivityEditortCambiar el orden. Mover el campo seleccionado hacia arriba(Change the order. Move selected field upActivityEditorLimpiarClearActivityEditorColumna AColumn AActivityEditorColumna BColumn BActivityEditorColumna CColumn CActivityEditorConectarConnectActivityEditor0Conectar automticamenteConnect automaticallyActivityEditor CamposFieldsActivityEditorNSi no est marcada, el perfil no cambia)If unchecked, the profile does not changeActivityEditor DiseoLayoutActivityEditorrLista de campos en la primera columna de detalles del QSO-List of fields in the first QSO Detail ColumnActivityEditor^Lista de campos de la primera fila de variables(List of fields in the first variable rowActivityEditorrLista de campos de la segunda columna de detalles del QSO.List of fields in the second QSO Detail ColumnActivityEditor^Lista de campos de la segunda fila de variables)List of fields in the second variable rowActivityEditorrLista de campos de la tercera columna de detalles del QSO-List of fields in the third QSO Detail ColumnActivityEditorJLista de campos que pueden utilizarseList of fields that can be usedActivityEditorMover los campos seleccionados de la lista de campos disponibles a la fila A@Move selected fields from the Available Fields List to the Row AActivityEditorMover los campos seleccionados de la lista de campos disponibles a la fila B@Move selected fields from the Available Fields List to the Row BActivityEditor&No debe estar vacoMust not be emptyActivityEditorFNuevas columnas de detalles del QSONew QSO Detail ColumnsActivityEditor(Nuevas filas del QSO New QSO RowsActivityEditorPerfilesProfilesActivityEditorVEliminar el campo seleccionado de la fila A$Remove selected field from the Row AActivityEditorVEliminar el campo seleccionado de la fila B$Remove selected field from the Row BActivityEditor EquipoRigActivityEditor RotorRotatorActivityEditor Fila ARow AActivityEditor Fila BRow BActivityEditorGuardadoSavedActivityEditorEstacinStationActivityEditorSin guardarUnsavedActivityEditorValoresValuesActivityEditor8Disposicin de las ventanas:Window Arrangement:ActivityEditor.*.*AlertRuleDetail fricaAfricaAlertRuleDetail:Detalle de la Regla de AlertaAlert Rule DetailAlertRuleDetail TodosAllAlertRuleDetailAntrtida AntarcticaAlertRuleDetailAsiaAsiaAlertRuleDetail BandasBandsAlertRuleDetailCQZCQZAlertRuleDetailCWCWAlertRuleDetailConfirmado ConfirmedAlertRuleDetailContinente ContinentAlertRuleDetailPasCountryAlertRuleDetailDXDXAlertRuleDetailIndicativo DX DX CallsignAlertRuleDetailCluster DX DX ClusterAlertRuleDetailDigitalDigitalAlertRuleDetailHabilitarEnabledAlertRuleDetail EuropaEuropeAlertRuleDetailFTx (FT8/FT4) FTx (FT8/FT4)AlertRuleDetailIOTAIOTAAlertRuleDetailITUITUAlertRuleDetail&Estado del Registro Log StatusAlertRuleDetailMiembroMemberAlertRuleDetail ModosModesAlertRuleDetail&No debe estar vacoMust not be emptyAlertRuleDetailNueva BandaNew BandAlertRuleDetailNueva Entidad New EntityAlertRuleDetailNuevo ModoNew ModeAlertRuleDetailNuevo SlotNew SlotAlertRuleDetailRNo hay ninguna lista de clubes habilitadaNo Club List is enabledAlertRuleDetailNorteamrica North AmericaAlertRuleDetailOceanaOceaniaAlertRuleDetailPOTAPOTAAlertRuleDetail FonaPhoneAlertRuleDetail$Nombre de la Regla Rule NameAlertRuleDetailSOTASOTAAlertRuleDetailFuentesSourcesAlertRuleDetailSudamrica South AmericaAlertRuleDetailEspecialSpecial ProgramsAlertRuleDetail(Comentario Anunciado Spot CommentAlertRuleDetailAnuncianteSpotterAlertRuleDetail\Utilice expresiones regulares similares a Perl Use Perl-like regular expressionAlertRuleDetail WSJTXWSJTXAlertRuleDetailWWFFWWFFAlertRuleDetailTrabajadoWorkedAlertRuleDetailAgregarAddAlertSettingDialog Reglas de Alerta Alerts RulesAlertSettingDialog EditarEditAlertSettingDialog NombreNameAlertSettingDialog QuitarRemoveAlertSettingDialog ReglasRulesAlertSettingDialog EstadoStateAlertSettingDialogIndicativoCallsignAlertTableModelFrecuencia FrequencyAlertTableModel"ltimo Comentario Last CommentAlertTableModel(ltima Actualizacin Last UpdateAlertTableModelMiembroMemberAlertTableModelModoModeAlertTableModelNombre Regla Rule NameAlertTableModelActualizadoUpdatedAlertTableModel min(s) min(s) AlertWidgetAlertasAlerts AlertWidgetLimpiarClear AlertWidget&Borrar anteriores aClear older than AlertWidget4Visibilidad de Columnas...Column Visibility... AlertWidgetEditar Reglas Edit Rules AlertWidget NuncaNever AlertWidget fricaAfrica AwardsDialogAntrtida Antarctica AwardsDialogAsiaAsia AwardsDialogDiplomaAward AwardsDialogDiplomasAwards AwardsDialogCWCW AwardsDialogConfirmado por Confirmed by AwardsDialogEliminadoDELETED AwardsDialogDXCCDXCC AwardsDialogDigiDigi AwardsDialog EuropaEurope AwardsDialogIOTAIOTA AwardsDialogITUITU AwardsDialog:Ciudades japonesas / Ku / GunJapanese Cities/Ku/Guns AwardsDialogLoTWLoTW AwardsDialogModoMode AwardsDialogMi Entidad DXCCMy DXCC Entity AwardsDialog2Condados de Nueva Zelanda NZ Counties AwardsDialog*Sin filtro de usuarioNo User Filter AwardsDialog"Amrica del Norte North America AwardsDialogNo confirmadoNot-Confirmed Only AwardsDialog"Slo no trabajadoNot-Worked Only AwardsDialogOceanaOceania AwardsDialogOpcionesOptions AwardsDialog"Activador de POTAPOTA Activator AwardsDialogCazador de POTA POTA Hunter AwardsDialog PapelPaper AwardsDialog FonaPhone AwardsDialog$Distritos de RusiaRussian Districts AwardsDialogSOTASOTA AwardsDialogMostrarShow AwardsDialogAmrica del Sur South America AwardsDialogDMEs de Espaa Spanish DMEs AwardsDialog$Condados de EE. UU US Counties AwardsDialog(Distritos de UcraniaUkrainian Districts AwardsDialog"Filtro de usuario User Filter AwardsDialogWACWAC AwardsDialogWASWAS AwardsDialogWAZWAZ AwardsDialogWPXWPX AwardsDialogWWFFWWFF AwardsDialogeQSLeQSL AwardsDialogConfirmado ConfirmedAwardsTableModel Slot: Slots: AwardsTableModelEsperando Still WaitingAwardsTableModelTrabajadoWorkedAwardsTableModel min(s) min(s) BandmapWidgetMapa de BandaBandmap BandmapWidgetCentrar RX Center RX BandmapWidgetBorrar Todo Clear All BandmapWidget&Borrar anteriores a Clear older BandmapWidget,Borrar la banda actualClear the current band BandmapWidgetLCrear una ventana adicional de Bandmap#Create an additional Bandmap Window BandmapWidgetMapa de BandaForm BandmapWidget NuncaNever BandmapWidgetMostrar Banda Show Band BandmapWidgetBMostrar frecuencias de emergenciaShow Emergency Frequencies BandmapWidgetLNo se puede enviar el Texto a la RadioCannot send Text to RigCWCatKeyfNo se puede establecer la velocidad del manipuladorCannot set Keyer SpeedCWCatKeyLNo se puede detener el envo del TextoCannot stop Text SendingCWCatKey@El manipulador no est conectadoKeyer is not connectedCWCatKey8Ninguna Radio est conectadaNo Rig is connectedCWCatKeyDLa Radio no soprte Morse sobre CAT#Rig does not support Morse over CATCWCatKey$Radio no conectadaRig is not connectedCWCatKey PPM WPMCWConsoleWidget&CW&CWCWConsoleWidget(Consola CW - DetenerCW Console - Halt SendingCWConsoleWidget2Perfil del Manipulador CWCW Keyer ProfileCWConsoleWidget BorrarClearCWConsoleWidget:Borrar enviados y consola EcoClear Sent and Echo ConsoleCWConsoleWidgetTexto repetido Echoed textCWConsoleWidgetF1CWConsoleWidgetF2CWConsoleWidgetF3CWConsoleWidgetF4CWConsoleWidgetF5CWConsoleWidgetF6CWConsoleWidgetF7CWConsoleWidgetFormCWConsoleWidgetDetenerHaltCWConsoleWidgetPDetener inmediatamente la transmisin CWImmediately stop CW sendingCWConsoleWidgetS/DN/ACWConsoleWidget:La radio debe estar conectadaRig must be connectedCWConsoleWidgetEnviar Texto Sent textCWConsoleWidget Perfil de atajosShortcuts profileCWConsoleWidgetVelocidadSpeedCWConsoleWidget@Cambiar entre enviar <b>palabras</b> individualmente (separadas por espacios)<br> y enviar el texto completo como un <b>todo</b> (separado por una nueva lnea).Switch between sending words individually (separated by spaces)
and sending the entire text as a whole (separated by a new line).CWConsoleWidgetTexto a Enviar Text to sendCWConsoleWidgetTodoWholeCWConsoleWidgetPalabraWordCWConsoleWidget6No se puede enviar el TextoCannot send Text CWDaemonKeyfNo se puede establecer la velocidad del manipuladorCannot set Keyer Speed CWDaemonKeyLNo se puede detener el envo del TextoCannot stop Text Sending CWDaemonKey@El manipulador no est conectadoKeyer is not connected CWDaemonKey:No se reciben datos de FLDigiCannot receive data from FLDigi CWFldigiKeyHNo se puede enviar el Texto a FLDigiCannot send Text to FLDigi CWFldigiKeyFNo se puede enviar Abortar a FLDigi'Cannot send the Abort command to FLDigi CWFldigiKeyDNo se puede enviar Borrar a FLDigi'Cannot send the Clear command to FLDigi CWFldigiKeyBNo se puede enviar Parar a FLDigi&Cannot send the Stop command to FLDigi CWFldigiKey<No se puede enviar TX a FLDigi$Cannot send the TX command to FLDigi CWFldigiKeyBNo se puede enviar Texto a FLDigi&Cannot send the Text command to FLDigi CWFldigiKeyJEl dispositivo conectado no es FLDigiConnected device is not FLDigi CWFldigiKey.Error de comando FLDigiFLDigi command error CWFldigiKey0Error de conexin FLDigiFLDigi connection error CWFldigiKey\Termin el tiempo de espera de conexin FLDigiFLDigi connection timeout CWFldigiKey@El manipulador no est conectadoKeyer is not connected CWFldigiKeyFNo se puede conectar al Manipulador Cannot open the Keyer connectionCWKeyer"Error de ConexinConnection ErrorCWKeyer(Error al InicializarInitialization ErrorCWKeyerError InternoInternal ErrorCWKeyerRNo Hay Perfil de Manipulador SeleccionadoNo CW Keyer Profile selectedCWKeyer 4000 Hz {1000 ?}1000 HzCWWinKey 4000 Hz {1333 ?}1333 HzCWWinKey 4000 Hz {2000 ?}2000 HzCWWinKey4000 Hz {400 ?}400 HzCWWinKey4000 Hz4000 HzCWWinKey4000 Hz {444 ?}444 HzCWWinKey4000 Hz {500 ?}500 HzCWWinKey4000 Hz {571 ?}571 HzCWWinKey4000 Hz {666 ?}666 HzCWWinKey4000 Hz {800 ?}800 HzCWWinKeyLNo se puede enviar el Texto a la RadioCannot send Text to RigCWWinKeyfNo se puede establecer la velocidad del manipuladorCannot set Keyer SpeedCWWinKeyLNo se puede detener el envo del TextoCannot stop Text SendingCWWinKey*Error de ComunicacinCommunication ErrorCWWinKeyJEl dispositivo conectado no es WinkeyConnected device is not WinKeyCWWinKey@El manipulador no est conectadoKeyer is not connectedCWWinKey -  - CabrilloExportDialog&Exportar&ExportCabrilloExportDialogAdicional AdditionalCabrilloExportDialogDireccin:Address:CabrilloExportDialogAsistido: Assisted:CabrilloExportDialog Banda:Band:CabrilloExportDialogNavegarBrowseCabrilloExportDialog"Exportar CabrilloCabrillo ExportCabrilloExportDialogArchivos Cabrillo (*.log);;Archivos CBR (*.cbr);;Todos los archivos (*)8Cabrillo Files (*.log);;CBR Files (*.cbr);;All Files (*)CabrilloExportDialogIndicativo: Callsign:CabrilloExportDialog^No se puede abrir el archivo %1 para escritura. Cannot open file %1 for writing.CabrilloExportDialog Club:Club:CabrilloExportDialogConcursoContestCabrilloExportDialogFecha/Hora: Date/Time:CabrilloExportDialog EMail:Email:CabrilloExportDialogNExportados %n QSOs al archivo Cabrillo.$Exported %n QSO(s) to Cabrillo file.CabrilloExportDialog(Exportando Cabrillo &Exporting Cabrillo...CabrilloExportDialog^No se pudo preparar la consulta de exportacin.Failed to prepare export query.CabrilloExportDialoglNo se pudieron consultar los QSOs para la exportacin. Failed to query QSOs for export.CabrilloExportDialogArchivo:File:CabrilloExportDialog*Plantilla de formato:Format Template:CabrilloExportDialogLocator GridsquareCabrilloExportDialogUbicacin: Location:CabrilloExportDialogAdministrarManageCabrilloExportDialogMx. 6 lneas Max 6 linesCabrilloExportDialog Modo:Mode:CabrilloExportDialogNombre:Name:CabrilloExportDialoglNo hay indicativos disponibles. Compruebe sus filtros.*No callsign available. Check your filters.CabrilloExportDialogOperador: Operator:CabrilloExportDialogOperadores: Operators:CabrilloExportDialogJSeleccione una plantilla de concurso.!Please select a contest template.CabrilloExportDialog@Seleccione un archivo de salida.Please select an output file.CabrilloExportDialogPotencia:Power:CabrilloExportDialogError de QLog QLog ErrorCabrilloExportDialog&Informacin de QLogQLog InformationCabrilloExportDialogAlerta de QLog QLog WarningCabrilloExportDialogQSO(s): %1 QSO(s): %1CabrilloExportDialogQSOs: ?QSOs: ?CabrilloExportDialog"Comentario libre:Soapbox:CabrilloExportDialog*Estacin y categorasStation & CategoriesCabrilloExportDialogEstacin:Station:CabrilloExportDialog Hora:Time:CabrilloExportDialogTransmisor: Transmitter:CabrilloExportDialog$Filtro de usuario: User Filter:CabrilloExportDialog1.25m (222 MHz)1.25m (222 MHz)CabrilloFormat12 horas12 HoursCabrilloFormat23cm (1.2 GHz)23cm (1.2 GHz)CabrilloFormat24 horas24 HoursCabrilloFormat2m (144 MHz) 2m (144 MHz)CabrilloFormat33cm (902 MHz)33cm (902 MHz)CabrilloFormat6 horas6 HoursCabrilloFormat70cm (432 MHz)70cm (432 MHz)CabrilloFormat Todas las bandas All BandsCabrilloFormatAsistidoAssistedCabrilloFormatRevisar log Check LogCabrilloFormatClsicoClassicCabrilloFormat$Fecha (AAAA-MM-DD)Date (YYYY-MM-DD)CabrilloFormatDigitalDigitalCabrilloFormatDistribuido DistributedCabrilloFormatExpedicin ExpeditionCabrilloFormatFijoFixedCabrilloFormat Frecuencia (kHz)Frequency (kHz)CabrilloFormatHighHighCabrilloFormatLuzLightCabrilloFormatLimitadoLimitedCabrilloFormatLowLowCabrilloFormat MixtoMixedCabrilloFormat MvilMobileCabrilloFormatModo (Cabrillo)Mode (Cabrillo)CabrilloFormatMultioperadorMulti OperatorCabrilloFormatNo asistido Non-AssistedCabrilloFormatNovato/Tcnico Novice/TechCabrilloFormatUnoOneCabrilloFormatMs de 50Over 50CabrilloFormatFRST corto (omitir el ltimo dgito)RST Short (drop last digit)CabrilloFormatSWLSWLCabrilloFormatEscuelaSchoolCabrilloFormatOperador nicoSingle OperatorCabrilloFormat>Texto (alineado a la izquierda)Text (left-aligned)CabrilloFormatHora (HHMM) Time (HHMM)CabrilloFormatDosTwoCabrilloFormatIlimitado UnlimitedCabrilloFormatMaysculas UppercaseCabrilloFormatVHF de 3 bandas VHF 3-BandCabrilloFormatSolo VHF FM VHF FM OnlyCabrilloFormat Nmero con cerosZero-Padded Nr.CabrilloFormatAadir lneaAdd lineCabrilloTemplateDialog:Gestor de plantillas CabrilloCabrillo Template ManagerCabrilloTemplateDialog@No se puede abrir el archivo: %1Cannot open file: %1CabrilloTemplateDialogRNo se puede guardar la plantilla %1: %2Cannot save template '%1': %2CabrilloTemplateDialoghNo se puede iniciar la transaccin de base de datos."Cannot start database transaction.CabrilloTemplateDialog(Nombre del concurso: Contest Name:CabrilloTemplateDialogNombre del concurso segn las reglas. Es posible introducir una cadena personalizada si no est incluida en la lista.qContest name as required by the rules. It is possible to enter a custom string if it is not included in the list.CabrilloTemplateDialog CopiarCopyCabrilloTemplateDialogCopia  %1 Copy - %1CabrilloTemplateDialog4Copiar plantilla existenteCopy existing templateCabrilloTemplateDialog(Modo predeterminado: Default Mode:CabrilloTemplateDialog$Eliminar plantillaDelete TemplateCabrilloTemplateDialog$Eliminar plantillaDelete templateCabrilloTemplateDialog8Eliminar la plantilla %1?Delete template '%1'?CabrilloTemplateDialogExportarExportCabrilloTemplateDialog&Exportacin fallida Export FailedCabrilloTemplateDialog$Exportar plantillaExport TemplateCabrilloTemplateDialog$Exportar plantillaExport templateCabrilloTemplateDialogDNo se pudo escribir el archivo: %1Failed to write file: %1CabrilloTemplateDialog2Archivo no encontrado: %1File not found: %1CabrilloTemplateDialogFormateador FormatterCabrilloTemplateDialogImportarImportCabrilloTemplateDialog&Importacin fallida Import FailedCabrilloTemplateDialog$Importar plantillaImport TemplateCabrilloTemplateDialog$Importar plantillaImport templateCabrilloTemplateDialog\Archivo de plantilla invlido: falta el nombre#Invalid template file: missing nameCabrilloTemplateDialogEtiquetaLabelCabrilloTemplateDialog NuevoNewCabrilloTemplateDialogNueva plantilla New TemplateCabrilloTemplateDialogNueva plantilla New templateCabrilloTemplateDialogDPlantilla Cabrillo de QLog (*.qct)QLog Cabrillo Template (*.qct)CabrilloTemplateDialogError de QLog QLog ErrorCabrilloTemplateDialogAlerta de QLog QLog WarningCabrilloTemplateDialogCampo QSO QSO FieldCabrilloTemplateDialog,Columnas de lnea QSO:QSO Line Columns:CabrilloTemplateDialog6Eliminar lnea seleccionadaRemove selected lineCabrilloTemplateDialogN.Seq.CabrilloTemplateDialog.Nombre de la plantilla:Template Name:CabrilloTemplateDialog AnchoWidthCabrilloTemplateDialogZ<p>Se usar el libro de guaria secundario</p>*

The secondary callbook will be used

CallbookManagerSala de Chat Chat Room ChatWidgetConectarConnect ChatWidget NuevoNew ChatWidgetChat ON4KST ON4KST Chat ChatWidgetChat ON4KST no est configurado apropiadamente.<p> Por favor usar <b>Ajustes</b> para configurarlo.</p>bON4KST Chat is not configured properly.

Please, use Settings dialog to configure it.

 ChatWidgetAlerta de QLog QLog Warning ChatWidgetDesactivadoDisabledCheckBoxDelegateActivadoEnabledCheckBoxDelegate RelojForm ClockWidgetS/DN/A ClockWidgetAmanecerSunrise ClockWidget OcasoSunset ClockWidget&Clave API no vlidaInvalid API KeyCloudlogUploader~La Operacin de Clublog para el indicativo %1 ha fallado.<br>%2/Clublog Operation for Callsign %1 failed.
%2ClubLogUploaderDAjustes de Visibilidad de ColumnasColumn Visibility SettingColumnSettingDialogCondiciones ConditionalsColumnSettingDialogConcursosContestsColumnSettingDialog HechoDoneColumnSettingDialogGeneralGeneralColumnSettingDialogMiembrosMembersColumnSettingDialogMi InformacinMy InfoColumnSettingDialog OtrosOthersColumnSettingDialog.QSL y Libros de GuardiaQSL && CallbooksColumnSettingDialog Seleccionar Todo Select AllColumnSettingGenericDialog Seleccionar Nada Unselect AllColumnSettingGenericDialogDAjustes de Visibilidad de ColumnasColumn Visibility SettingColumnSettingSimpleDialog HechoDoneColumnSettingSimpleDialog, Actualizacin Fallida Update FailedDBSchemaMigrationClublog CTY.XMLClublog CTY.XMLDBSchemaMigrationEntidades DXCC DXCC EntitiesDBSchemaMigrationRegistros IOTA IOTA RecordsDBSchemaMigration Lista de ValoresList of ValuesDBSchemaMigrationHRegistros del Directorio de MiembrosMembership Directory RecordsDBSchemaMigrationRegistros POTA POTA RecordsDBSchemaMigrationCumbres SOTA SOTA SummitsDBSchemaMigration.Informaci de Satlites Sats InfoDBSchemaMigrationActualizando  Updating DBSchemaMigrationRegistros WWFF WWFF RecordsDBSchemaMigrationAfganistn Afghanistan DBStrings2Is. Agalega y San BrandonAgalega & St. Brandon DBStringsIs. Aland Aland Islands DBStrings AlaskaAlaska DBStringsAlbaniaAlbania DBStringsArgeliaAlgeria DBStringsSamoa AmericanaAmerican Samoa DBStrings2Is. San Pablo y msterdamAmsterdam & St. Paul Is. DBStrings*Is. Andamn y NicobarAndaman & Nicobar Is. DBStringsAndorraAndorra DBStrings AngolaAngola DBStringsAnguillaAnguilla DBStringsIs. AnnobnAnnobon Island DBStringsAntrtida Antarctica DBStrings"Antigua y BarbudaAntigua & Barbuda DBStringsArgentina Argentina DBStringsArmeniaArmenia DBStrings ArubaAruba DBStringsIs. AscensinAscension Island DBStringsRusia AsiticaAsiatic Russia DBStrings Turqua AsiticaAsiatic Turkey DBStringsIs. AustralesAustral Islands DBStringsAustralia Australia DBStringsAustriaAustria DBStringsIs. de Aves Aves Island DBStringsAzerbaiyn Azerbaijan DBStrings AzoresAzores DBStringsBahamasBahamas DBStrings BarinBahrain DBStrings&Is. Baker y HowlandBaker & Howland Islands DBStringsIs. BalearesBalearic Islands DBStringsIs. Banana Banaba Island DBStringsBangladesh Bangladesh DBStringsBarbadosBarbados DBStringsBielorrusiaBelarus DBStringsBlgicaBelgium DBStrings BeliceBelize DBStrings BennBenin DBStringsBermudasBermuda DBStrings ButnBhutan DBStringsBoliviaBolivia DBStringsBonaireBonaire DBStrings(Bosnia y HerzegovinaBosnia-Herzegovina DBStringsBotsuanaBotswana DBStrings BouvetBouvet DBStrings BrasilBrazil DBStrings.Is. Vrgenes BritnicasBritish Virgin Islands DBStrings BruniBrunei Darussalam DBStringsBulgariaBulgaria DBStringsBurkina Faso Burkina Faso DBStringsBurundiBurundi DBStringsCWCW DBStringsCamboyaCambodia DBStringsCamernCameroon DBStrings CanadCanada DBStringsIs. CanariasCanary Islands DBStringsCabo Verde Cape Verde DBStringsIs. CaimnCayman Islands DBStrings0Repblica CentroafricanaCentral African Republic DBStrings Kiribati CentralCentral Kiribati DBStringsCeuta y MelillaCeuta & Melilla DBStringsChadChad DBStringsIs. ChagosChagos Islands DBStringsIs. ChathamChatham Islands DBStrings Is. ChesterfieldChesterfield Islands DBStrings ChileChile DBStrings ChinaChina DBStringsIs. de NavidadChristmas Island DBStringsIs. ClippertonClipperton Island DBStrings&Is. Cocos (Keeling)Cocos (Keeling) Islands DBStringsIs. del Coco Cocos Island DBStringsColombiaColombia DBStringsIslas ComorasComoros DBStringsConway Reef Conway Reef DBStringsCrcegaCorsica DBStringsCosta Rica Costa Rica DBStringsCosta de Marfl Cote d'Ivoire DBStrings CretaCrete DBStringsCroaciaCroatia DBStringsIs. Crozet Crozet Island DBStringsCubaCuba DBStringsCurazaoCuracao DBStrings ChipreCyprus DBStrings(Rep. Checa (Chequia)Czech Republic DBStringsDigitalDIGITAL DBStringsCorea del Norte DPR of Korea DBStrings>Repblica Democrtica del CongoDem. Rep. of the Congo DBStringsDinamarcaDenmark DBStringsIs. DesecheoDesecheo Island DBStrings YibutiDjibouti DBStringsDodecaneso Dodecanese DBStringsDominicaDominica DBStringsRep. DominicanaDominican Republic DBStringsIs. Ducie Ducie Island DBStrings Malasia Oriental East Malaysia DBStringsIs. de Pascua Easter Island DBStrings"Kiribati OrientalEastern Kiribati DBStringsEcuadorEcuador DBStrings EgiptoEgypt DBStringsEl Salvador El Salvador DBStringsInglaterraEngland DBStrings"Guinea EcuatorialEquatorial Guinea DBStringsEritreaEritrea DBStringsEstoniaEstonia DBStringsEtiopaEthiopia DBStringsRusia EuropeaEuropean Russia DBStrings.Is. Falkland (Malvinas)Falkland Islands DBStringsIs. Feroe Faroe Islands DBStringsAlemaniaFed. Rep. of Germany DBStrings&Fernando de NoronhaFernando de Noronha DBStringsFiyiFiji DBStringsFinlandiaFinland DBStringsFranciaFrance DBStrings(Tierra Franciso JosFranz Josef Land DBStrings Guayana Francesa French Guiana DBStrings$Polinesia FrancesaFrench Polynesia DBStrings GabnGabon DBStringsIs. GalpagosGalapagos Islands DBStringsGeorgiaGeorgia DBStrings GhanaGhana DBStringsGibraltar Gibraltar DBStringsIs. GloriosoGlorioso Islands DBStrings GreciaGreece DBStringsGroenlandia Greenland DBStringsGranadaGrenada DBStringsGuadalupe Guadeloupe DBStringsGuamGuam DBStrings&Baha de GuantnamoGuantanamo Bay DBStringsGuatemala Guatemala DBStringsGuernseyGuernsey DBStrings GuineaGuinea DBStringsGuinea-Bisu Guinea-Bissau DBStrings GuyanaGuyana DBStrings HaitHaiti DBStrings HawiHawaii DBStringsIs. Heard Heard Island DBStringsHondurasHonduras DBStringsHong Kong Hong Kong DBStringsHungraHungary DBStringsITU GinebraITU HQ DBStringsIslandiaIceland DBStrings IndiaIndia DBStringsIndonesia Indonesia DBStringsIrnIran DBStringsIraqIraq DBStringsIrlandaIreland DBStringsIsla de Man Isle of Man DBStrings IsraelIsrael DBStrings ItaliaItaly DBStringsJamaicaJamaica DBStringsJan Mayen Jan Mayen DBStrings JapnJapan DBStrings JerseyJersey DBStringsIs. JohnstonJohnston Island DBStringsJordaniaJordan DBStrings$Is. Juan FernndezJuan Fernandez Islands DBStrings(Juan de Nova, EuropaJuan de Nova & Europa DBStringsKaliningrado Kaliningrad DBStringsKazajistn Kazakhstan DBStrings KeniaKenya DBStringsIs. KerguelenKerguelen Islands DBStringsIs. KermadecKermadec Islands DBStrings"Reino de EsuatiniKingdom of Eswatini DBStringsIs. Kure Kure Island DBStrings KuwaitKuwait DBStringsKirguistn Kyrgyzstan DBStringsIs. LaquedivasLakshadweep Islands DBStringsLaosLaos DBStringsLetoniaLatvia DBStrings LbanoLebanon DBStrings LesotoLesotho DBStringsLiberiaLiberia DBStrings LibiaLibya DBStringsLiechtenstein Liechtenstein DBStringsLituania Lithuania DBStringsIs. Lord HoweLord Howe Island DBStringsLuxemburgo Luxembourg DBStrings MacaoMacao DBStringsIs. MadquarieMacquarie Island DBStringsMadagascar Madagascar DBStringsIs. MadeiraMadeira Islands DBStrings MalawiMalawi DBStringsMaldivasMaldives DBStringsMalMali DBStringsIs. MalpeloMalpelo Island DBStrings MaltaMalta DBStringsIs. MarianaMariana Islands DBStringsMarket Reef Market Reef DBStringsIs. MarquesasMarquesas Islands DBStringsIs. MarshallMarshall Islands DBStringsMartinica Martinique DBStringsMauritania Mauritania DBStringsMauricio Mauritius DBStringsMayotteMayotte DBStrings Arrecife Mellish Mellish Reef DBStrings MxicoMexico DBStringsMicronesia Micronesia DBStringsIs. Midway Midway Island DBStrings Minami TorishimaMinami Torishima DBStringsMoldaviaMoldova DBStrings MnacoMonaco DBStringsMongoliaMongolia DBStringsMontenegro Montenegro DBStringsMonserrat Montserrat DBStringsMarruecosMorocco DBStringsMonte Athos Mount Athos DBStringsMozambique Mozambique DBStrings$Myanmar (Birmania)Myanmar DBStrings6Islas Subantrticas de N.Z.N.Z. Subantarctic Is. DBStringsNamibiaNamibia DBStrings NauruNauru DBStringsIs. NavassaNavassa Island DBStrings NepalNepal DBStringsPases Bajos Netherlands DBStringsNueva Caledonia New Caledonia DBStringsNueva Zelanda New Zealand DBStringsNicaragua Nicaragua DBStrings NigerNiger DBStringsNigeriaNigeria DBStringsNiueNiue DBStringsIs. NorfolkNorfolk Island DBStrings$Is. Cook del NorteNorth Cook Islands DBStrings&Macedonia del NorteNorth Macedonia DBStrings"Irlanda del NorteNorthern Ireland DBStringsNoruegaNorway DBStringsOgasawara Ogasawara DBStringsOmnOman DBStrings FonaPHONE DBStringsPakistnPakistan DBStrings PalauPalau DBStringsPalestina Palestine DBStrings(Is. Palmyra y JarvisPalmyra & Jarvis Islands DBStrings PanamPanama DBStrings$Papa Nueva GuineaPapua New Guinea DBStringsParaguayParaguay DBStringsPerPeru DBStringsIs. Pedro IPeter 1 Island DBStringsFilipinas Philippines DBStringsIs.PitcairnPitcairn Island DBStringsPoloniaPoland DBStringsPortugalPortugal DBStrings:Is. Prncipe Eduardo y MarionPr. Edward & Marion Is. DBStringsIs. Pratas Pratas Island DBStringsPuerto Rico Puerto Rico DBStrings QatarQatar DBStringsCorea del SurRepublic of Korea DBStrings&Repblica de KosovoRepublic of Kosovo DBStringsSudn del SurRepublic of South Sudan DBStrings&Repblica del CongoRepublic of the Congo DBStringsIs. ReuninReunion Island DBStrings&Islas Revillagigedo Revillagigedo DBStringsIs. RodriguesRodriguez Island DBStringsRumaniaRomania DBStringsIs. Rotuma Rotuma Island DBStrings RuandaRwanda DBStrings(Saba y San EustaquioSaba & St. Eustatius DBStringsIs. Sable Sable Island DBStrings SamoaSamoa DBStrings0San Andrs y ProvidenciaSan Andres & Providencia DBStrings0San Flix y San AmbrosioSan Felix & San Ambrosio DBStringsSan Marino San Marino DBStrings*Santo Tom y PrncipeSao Tome & Principe DBStringsCerdeaSardinia DBStringsArabia Saudita Saudi Arabia DBStrings(Arrecife ScarboroughScarborough Reef DBStringsEscociaScotland DBStringsSenegalSenegal DBStrings SerbiaSerbia DBStringsSeychelles Seychelles DBStringsSierra Leona Sierra Leone DBStringsSingapur Singapore DBStringsSint Maarten Sint Maarten DBStringsRep. EslovaquiaSlovak Republic DBStringsEsloveniaSlovenia DBStringsIs. SalomnSolomon Islands DBStringsSomaliaSomalia DBStringsSudfrica South Africa DBStrings Is. Cook del SurSouth Cook Islands DBStrings(Is. Georgias del SurSouth Georgia Island DBStrings&Is. Orcadas del SurSouth Orkney Islands DBStrings(Is. Sandwich del SurSouth Sandwich Islands DBStrings(Is. Shetland del SurSouth Shetland Islands DBStringsOrden de MaltaSov Mil Order of Malta DBStrings EspaaSpain DBStringsIs. SpratlySpratly Islands DBStringsSri Lanka Sri Lanka DBStrings$Isla San BartolomSt. Barthelemy DBStringsSanta Helena St. Helena DBStrings,San Cristbal y NievesSt. Kitts & Nevis DBStrings&Isla de Santa Luca St. Lucia DBStrings$Isla de San Martn St. Martin DBStrings Is. de San PabloSt. Paul Island DBStrings*San Pedro y San PabloSt. Peter & St. Paul DBStrings(San Pedro y MiquelnSt. Pierre & Miquelon DBStrings Isla San Vicente St. Vincent DBStrings SudnSudan DBStringsSurinamSuriname DBStringsSvalbardSvalbard DBStringsIs. Swains Swains Island DBStrings SueciaSweden DBStrings Suiza Switzerland DBStrings SiriaSyria DBStrings TaiwnTaiwan DBStringsTajikistan Tajikistan DBStringsTanzaniaTanzania DBStrings Provincia TemotuTemotu Province DBStringsTailandiaThailand DBStrings Gambia The Gambia DBStringsTimor Oriental Timor - Leste DBStringsTogoTogo DBStringsIs. TokelauTokelau Islands DBStrings TongaTonga DBStrings6Islas Trinidad y Martn VazTrindade & Martim Vaz DBStrings"Trinidad y TobagoTrinidad & Tobago DBStrings<Islas Tristn de Acua y Gough Tristan da Cunha & Gough Islands DBStringsIs. TromelinTromelin Island DBStrings TnezTunisia DBStringsTurkmenistn Turkmenistan DBStrings&Is. Turcas y CaicosTurks & Caicos Islands DBStrings TuvaluTuvalu DBStrings>rea Soberana Inglesa en ChipreUK Base Areas on Cyprus DBStrings.Is. Vrgenes AmericanasUS Virgin Islands DBStrings UgandaUganda DBStringsUcraniaUkraine DBStrings,Emiratos rabes UnidosUnited Arab Emirates DBStringsONU Nueva YorkUnited Nations HQ DBStringsEstados Unidos United States DBStringsUruguayUruguay DBStringsUzbekistan Uzbekistan DBStringsVanuatuVanuatu DBStrings&Ciudad del Vaticano Vatican City DBStringsVenezuela Venezuela DBStringsVietnamVietnam DBStringsWake Is. Wake Island DBStrings GalesWales DBStrings&Wallis y Futuna Is.Wallis & Futuna Islands DBStrings>Malasia Occidental (Peninsular) West Malaysia DBStrings&Kiribati OccidentalWestern Kiribati DBStrings"Sahara OccidentalWestern Sahara DBStringsWillis Is. Willis Island DBStrings YemenYemen DBStrings ZambiaZambia DBStringsZimbabueZimbabwe DBStrings.%1 %2 %3  DXCC %4 / %5%1 %2 %3 — DXCC %4 / %5DXCCSubmissionDialog6%1 banda(s) seleccionada(s)%1 selected band(s)DXCCSubmissionDialog DXCC de 5 bandas 5-Band DXCCDXCCSubmissionDialogFDXCC de 5 bandas (80/40/20/15/10 m)5-Band DXCC (80/40/20/15/10m)DXCCSubmissionDialog5 bandas5-bandDXCCSubmissionDialog*Todas las bandas DXCCAll DXCC BandsDXCCSubmissionDialogYa concedidoAlready GrantedDXCCSubmissionDialogDCualquier banda (nivel de entidad)Any Band (Entity Level)DXCCSubmissionDialog BandaBandDXCCSubmissionDialog Alcance de banda Band ScopeDXCCSubmissionDialog BandasBandsDXCCSubmissionDialogCWCWDXCCSubmissionDialogIndicativoCallsignDXCCSubmissionDialogCategoraCategoryDXCCSubmissionDialogConfirmado por Confirmed byDXCCSubmissionDialogBSeleccin personalizada de bandasCustom Band SelectionDXCCSubmissionDialog&Lista de envo DXCCDXCC Submission ListDXCCSubmissionDialog FechaDateDXCCSubmissionDialogDigitalDigitalDXCCSubmissionDialogEntidadEntityDXCCSubmissionDialogExportarExportDXCCSubmissionDialogExportar ADIF Export ADIFDXCCSubmissionDialogRExportar la lista de envo DXCC como ADIF#Export DXCC Submission List as ADIFDXCCSubmissionDialogpExportar los contactos listados arriba a un archivo ADIF0Export the contacts listed above to an ADIF fileDXCCSubmissionDialogdNo se pudieron obtener los registros de contactos.#Failed to retrieve contact records.DXCCSubmissionDialogConcedidoGrantedDXCCSubmissionDialogLoTWLoTWDXCCSubmissionDialog MixtoMixedDXCCSubmissionDialogModoModeDXCCSubmissionDialogMi Entidad DXCCMy DXCC EntityDXCCSubmissionDialog*Sin filtro de usuarioNo User FilterDXCCSubmissionDialogrNingn contacto coincide con los criterios seleccionados.(No contacts match the selected criteria.DXCCSubmissionDialog>No hay contactos para exportar.No contacts to export.DXCCSubmissionDialogAn no enviadoNot Yet SubmittedDXCCSubmissionDialogOpcionesOptionsDXCCSubmissionDialog PapelPaperDXCCSubmissionDialog FonaPhoneDXCCSubmissionDialogPrefijoPrefixDXCCSubmissionDialogSeleccionar bandas predefinidas DXCC de 5 bandas (80/40/20/15/10 m)1Select 5-Band DXCC preset bands (80/40/20/15/10m)DXCCSubmissionDialog`Seleccionar todas las bandas elegibles para DXCCSelect all DXCC-eligible bandsDXCCSubmissionDialogSeleccione las opciones anteriores y la lista se actualizar automticamente.%1 ligne(s) exporte(s) vers %2Exported %1 row(s) to %2DevToolsDialognImpossible de copier le fichier de journal de dbogage."Failed to copy the debug log file.DevToolsDialogvImpossible de rcuprer les enregistrements de contacts: %1&Failed to retrieve contact records: %1DevToolsDialog`La journalisation dans un fichier est dsactiveFile logging is disabledDevToolsDialog<Gnrer un fichier de dbogageGenerate Debug FileDevToolsDialog`Fichiers journaux (*.log);;Tous les fichiers (*) Log Files (*.log);;All Files (*)DevToolsDialog.Fichier de journal : %1 Log file: %1DevToolsDialog2Rgles de journalisation:Logging Rules:DevToolsDialogFRgles de journalisation appliquesLogging rules appliedDevToolsDialoghRgles de journalisation rinitialises (par dfaut) Logging rules cleared (defaults)DevToolsDialogAucun fichier de journal de dbogage n est actuellement en cours d criture,No debug log file is currently being writtenDevToolsDialogvAucun contact correspondant trouv dans la base de donnes.+No matching contacts found in the database.DevToolsDialog4Aucun rsultat exporter.No results to export.DevToolsDialogAucun identifiant de contact valide trouv dans le jeu de rsultats.-No valid contact IDs found in the result set.DevToolsDialog$Erreur d ouverture Open ErrorDevToolsDialogOuvrir SQLOpen SQLDevToolsDialog*Ouvrir la requte SQLOpen SQL QueryDevToolsDialog6Requte enregistre dans %1Query saved to %1DevToolsDialogExcuter SQLRun SQLDevToolsDialogConsole SQL SQL ConsoleDevToolsDialogVFichiers SQL (*.sql);;Tous les fichiers (*) SQL Files (*.sql);;All Files (*)DevToolsDialogDEnregistrer le journal de dbogageSave Debug LogDevToolsDialog.Erreur d enregistrement Save ErrorDevToolsDialogEnregistrer SQLSave SQLDevToolsDialog4Enregistrer la requte SQLSave SQL QueryDevToolsDialogZFichiers texte (*.txt);;Tous les fichiers (*)!Text Files (*.txt);;All Files (*)DevToolsDialog:p. ex. qlog.ui.*.runtime=truee.g. qlog.ui.*.runtime=trueDevToolsDialog@La mise jour de %1 a chou : %1 update failed: DownloadQSLDialog&Tlcharger &DownloadDownloadQSLDialogAnnulerCancelDownloadQSLDialog&Tlcharger les QSL Download QSLsDownloadQSLDialog0Tlchargement depuis %1Downloading from %1DownloadQSLDialogLoTWLoTWDownloadQSLDialogLoTW n'est pas configur correctement.<p> Veuillez utiliser la fentre des <b>Paramtres</b> pour le configurer.</p>[LoTW is not configured properly.

Please, use Settings dialog to configure it.

DownloadQSLDialogMon indicatif My CallsignDownloadQSLDialog2Aucun service slectionnNo service selectedDownloadQSLDialog(Traitement de %1 QSLProcessing %1 QSLsDownloadQSLDialogErreur QLog QLog ErrorDownloadQSLDialog Information QLogQLog InformationDownloadQSLDialogQSL depuis le QSLs SinceDownloadQSLDialogQSO depuis le QSOs SinceDownloadQSLDialogeQSLeQSLDownloadQSLDialogProfil QTH eQSLeQSL QTH ProfileDownloadQSLDialogeQSL n'est pas configur correctement.<p> Veuillez utiliser la fentre des <b>Paramtres</b> pour le configurer.</p>[eQSL is not configured properly.

Please, use Settings dialog to configure it.

DownloadQSLDialog kHz kHzDxFilterDialogAfriqueAfricaDxFilterDialogAntarctique AntarcticaDxFilterDialogAsieAsiaDxFilterDialog BandesBandsDxFilterDialogCWCWDxFilterDialogConfirm ConfirmedDxFilterDialogContinent ContinentDxFilterDialog$Filtres DX ClusterDX Cluster FiltersDxFilterDialogNumriqueDigitalDxFilterDialog`Ne pas afficher les spots suivants s'ils ont le mme indicatif et que leur diffrence de temps est infrieure Time Diff et leur diffrence de frquence infrieure Freq DiffDo not show the following spots when they have the same Callsign and their time difference is lower than Time Diff and their frequency difference is lower than Freq DiffDxFilterDialog EuropeEuropeDxFilterDialogFiltres tendusExtended FiltersDxFilterDialogFTx (FT8/FT4) FTx (FT8/FT4)DxFilterDialog.Diffrence de frquenceFrequency differenceDxFilterDialog Filtres gnrauxGeneral FiltersDxFilterDialogStatut du log Log StatusDxFilterDialog MembreMemberDxFilterDialog ModesModesDxFilterDialogNouvelle bandeNew BandDxFilterDialogNouvelle entit New EntityDxFilterDialogNouveau modeNew ModeDxFilterDialogNouveau crneauNew SlotDxFilterDialogDAucune liste de club n'est activeNo Club List is enabledDxFilterDialog Amrique du Nord North AmericaDxFilterDialogOcanieOceaniaDxFilterDialog PhoniePhoneDxFilterDialogAmrique du Sud South AmericaDxFilterDialog.Dduplication des spots Spots DedupDxFilterDialog*Continent du spotteurSpotter ContinentDxFilterDialog&Diffrence de tempsTime differenceDxFilterDialogContactWorkedDxFilterDialogssDxFilterDialog BandeBand DxTableModelIndicatifCallsign DxTableModelCommentaireComment DxTableModelContinent Continent DxTableModelPaysCountry DxTableModelFrquence Frequency DxTableModel MembreMember DxTableModelModeMode DxTableModelSpotteurSpotter DxTableModel*Continent du spotteurSpotter Continent DxTableModel HeureTime DxTableModelTendance 15 min 15-min TrendDxWidget*Un indicatif invalideAn invalid callsignDxWidgetAutoAutoDxWidgetPConnexion automatique aprs le dmarrage Automatic connection after startDxWidgetEffacerClearDxWidget.Effacer le mot de passeClear PasswordDxWidget4Effacer toutes les donnesClear all dataDxWidget&Fermer la recherche Close SearchDxWidget4Visibilit des colonnes...Column Visibility...DxWidgetConnecterConnectDxWidget,Connecter au dmarrageConnect on startupDxWidgetConnexion... Connecting...DxWidgetConsoleConsoleDxWidget&Commande DX ClusterDX Cluster CommandDxWidget.Mot de passe DX ClusterDX Cluster PasswordDxWidgetZLe DX Cluster est temporairement indisponible%DX Cluster is temporarily unavailableDxWidget4DXC - Supprimer le serveurDXC - Delete ServerDxWidget DXC - Rechercher DXC - SearchDxWidget$Erreur serveur DXCDXC Server ErrorDxWidget(Supprimer le serveur Delete ServerDxWidgetDconnecter DisconnectDxWidgetFiltrer DXC Filter DXCDxWidgetFiltrer... Filter...DxWidget FiltrFilteredDxWidget*Recherche plein texteFull-text searchDxWidgetTEntrez un <b>hte:port</b> de serveur DXC.,Insert a hostname:port of DXC Server.DxWidget Garder les spots Keep SpotsDxWidgetMon continent My ContinentDxWidgetRechercherSearchDxWidgetRechercher... Search...DxWidget Avis de scuritSecurity NoticeDxWidget>Envoyer une commande DX ClusterSend DX Cluster CommandDxWidget<Envoyer le spot du dernier QSOSend last QSO spotDxWidgetServeurServerDxWidget"Afficher stats HF Show HF StatsDxWidget$Afficher stats VHFShow VHF StatsDxWidgetAfficher WCYShow WCYDxWidgetAfficher WWVShow WWVDxWidget,Spotter le dernier QSO Spot Last QSODxWidget SpotsSpotsDxWidgetLes spots ne sont pas effacs lors de la connexion un nouveau DX Cluster.:Spots are not cleared when connecting to a new DX Cluster.DxWidgettLe mot de passe peut tre envoy via un canal non scuris1The password can be sent via an unsecured channelDxWidget tousTo AllDxWidgetUtilisateurUsernameDxWidgetWCYWCYDxWidgetWWVWWVDxWidgetNQuelles colonnes doivent tre affiches!Which columns should be displayedDxWidgetLoTWLoTWDxccTableModel PapierPaperDxccTableModelContactWorkedDxccTableModeleQSLeQSLDxccTableModelModeModeDxccTableWidgetXFichier ADIF non trouv dans la rponse eQSL$ADIF file not found in eQSL responseEQSLQSLDownloaderRImpossible d'ouvrir le fichier temporaireCannot opet temporary fileEQSLQSLDownloaderbImpossible de sauvegarder l'image dans le fichierCannot save the image to fileEQSLQSLDownloaderTMot de passe ou ID de profil QTH incorrect#Incorrect Password or QTHProfile IdEQSLQSLDownloaderJIdentifiant ou mot de passe incorrectIncorrect Username or passwordEQSLQSLDownloaderErreur inconnue Unknown ErrorEQSLQSLDownloader0Rponse inconnue de eQSLUnknown Reply from eQSL EQSLUploaderActivits ActivitiesEditActivitiesDialogAjouterAddEditActivitiesDialogModifierEditEditActivitiesDialog,Modifier les activitsEdit ActivitiesEditActivitiesDialogSupprimerRemoveEditActivitiesDialog"Ignorer""Ignore" ExportDialog "Non""No" ExportDialog&Exporter&Export ExportDialogADXADX ExportDialogTousAll ExportDialogDj envoy Already Sent ExportDialogParcourirBrowse ExportDialogCSVCSV ExportDialogAnnulerCancel ExportDialoghImpossible de marquer les QSO exports comme Envoys!Cannot mark exported QSOs as Sent ExportDialogJeu de colonnes Column set ExportDialogPersonnalis 1Custom 1 ExportDialogPersonnalis 2Custom 2 ExportDialogPersonnalis 3Custom 3 ExportDialogPlage de dates Date Range ExportDialogModifierEdit ExportDialogDModifier le jeu de colonnes actuelEdit current set of columns ExportDialog Exporter les QSO Export QSOs ExportDialogExporter les QSO correspondant au filtre utilisateur slectionn3Export QSOs that match the selected user QSO Filter ExportDialog:Exporter les QSO slectionnsExport Selected QSOs ExportDialog$Type d'exportation Export Type ExportDialogExporter uniquement les QSO correspondant ce profil de station.Export only QSOs matching this station profile ExportDialogxExporter uniquement les QSO correspondant aux filtres actifs.Export only QSOs that match the active filters ExportDialogvExporter uniquement les QSO correspondant "Mon Indicatif"4Export only QSOs that match the selected My Callsign ExportDialogExporter uniquement les QSO correspondant mon Locator (Gridsquare)6Export only QSOs that match the selected My Gridsquare ExportDialognExporter uniquement les QSO avec ce mode d'envoi de QSL;Export only QSOs that match the selected QSL Send Via value ExportDialoglExporter uniquement les QSO de la priode slectionne3Export only QSOs that match the selected date range ExportDialog*Exportation en cours & Exporting... ExportDialogFichierFile ExportDialogFiltresFilters ExportDialogGnriqueGeneric ExportDialog2Inclure le statut d'envoiInclude Sent Status ExportDialog\Inclure les statuts d'envoi de QSO inhabituels!Include unusual QSO Sent statuses ExportDialogJSONJSON ExportDialogLMarquer les QSO exports comme envoysMark exported QSOs As Sent ExportDialogMinimalMinimal ExportDialogMon indicatif My Callsign ExportDialogMon Locator My Gridsquare ExportDialogPOTAPOTA ExportDialogErreur QLog QLog Error ExportDialogEnvoyer QSL via QSL Send via ExportDialog$Spcifique aux QSL QSL-specific ExportDialogQSLQSLs ExportDialog:Renvoyer les QSO dj envoysResend already sent QSOs ExportDialogSlectionnez un des jeux de colonnes prdfinis ou dfinissez le vtreOSelect one of the pre-defined sets of columns or define your own set of columns ExportDialog"Profil de stationStation Profile ExportDialog0En temps normal, ce statut signifie <b>"Ignorer/Invalide"</b>.<br/>Cependant, il peut tre souhaitable d'ignorer ce paramtre lors de l'envoi d'une QSL.Under normal circumstances this status means "Ignore/Invalid".
However, it may sometimes be wanted to ignore this setting when sending a QSL. ExportDialog,En temps normal, ce statut signifie <b>"ne pas envoyer"</b>.<br/>Cependant, il peut tre souhaitable d'ignorer ce paramtre lors de l'envoi d'une QSL.Under normal circumstances this status means "do not send".
However, it may sometimes be wanted to ignore this setting when sending a QSL. ExportDialog$Filtre utilisateur User Filter ExportDialog2Confirmer le mot de passeConfirm PasswordExportPasswordDialogSupprimer les mots de passe du gestionnaire d'identifiants aprs export3Delete passwords from Credential Store after exportExportPasswordDialog Entrez un mot de passe pour chiffrer vos identifiants enregistrs. Ce mot de passe sera ncessaire pour les restaurer ultrieurement.bEnter a password to encrypt stored credentials. The password will be needed to restore them later.ExportPasswordDialogDArchiver les donnes et paramtresPack Data & SettingsExportPasswordDialogMot de passePasswordExportPasswordDialogAlatoireRandomExportPasswordDialog@Dlai de rponse de FLRig expirFLRig response timeout FlrigRigDrvErreur rseau Network Error FlrigRigDrvDlai expirTimeout FlrigRigDrv8Message de rponse mal formResponse message malformedHRDLogUploader HamQTHHamQTHHamQTHCallbookCATCAT HamlibRigDrv:Impossible d'envoyer du MorseCannot sent Morse HamlibRigDrvHImpossible de dfinir l'adresse CI-VCannot set CIV Addr HamlibRigDrvNImpossible de dfinir le partage du PTTCannot set PTT Share HamlibRigDrvHImpossible de dfinir le type de PTTCannot set PTT Type HamlibRigDrvFImpossible de dfinir auto_power_onCannot set auto_power_on HamlibRigDrvBImpossible de dfinir no_xchg 1Cannot set no_xchg to 1 HamlibRigDrv:Impossible d'arrter le MorseCannot stop Morse HamlibRigDrvDTRDTR HamlibRigDrvRErreur lors de la lecture de la frquenceGet Frequency Error HamlibRigDrvnErreur lors de la lecture de la vitesse de manipulationGet KeySpeed Error HamlibRigDrvBErreur lors de la lecture du modeGet Mode Error HamlibRigDrv@Erreur lors de la lecture du PTT Get PTT Error HamlibRigDrvVErreur lors de la lecture de puissance (mW)Get PWR (power2mw) Error HamlibRigDrvRErreur lors de la lecture de la puissance Get PWR Error HamlibRigDrv@Erreur lors de la lecture du RIT Get RIT Error HamlibRigDrvXErreur lors de la lecture de la fonction RITGet RIT Function Error HamlibRigDrv@Erreur lors de la lecture du VFO Get VFO Error HamlibRigDrv@Erreur lors de la lecture du XIT Get XIT Error HamlibRigDrvXErreur lors de la lecture de la fonction XITGet XIT Function Error HamlibRigDrv.Erreur d'initialisationInitialization Error HamlibRigDrv AucunNone HamlibRigDrvRTSRTS HamlibRigDrvBErreur d'ouverture du transceiverRig Open Error HamlibRigDrvLErreur lors du rglage de la frquenceSet Frequency Error HamlibRigDrvhErreur lors du rglage de la vitesse de manipulationSet KeySpeed Error HamlibRigDrv<Erreur lors du rglage du modeSet Mode Error HamlibRigDrv:Erreur lors du rglage du PTT Set PTT Error HamlibRigDrv>Erreur lors du rglage du splitSet Split Error HamlibRigDrvHErreur lors du rglage du mode splitSet Split Mode Error HamlibRigDrvRErreur lors du rglage de la frquence TXSet TX Frequency Error HamlibRigDrvDPilote de transceiver non supportUnsupported Rig Driver HamlibRigDrvPErreur lors de la lecture de la positionGet Possition Error HamlibRotDrv.Erreur d'initialisationInitialization Error HamlibRotDrv6Erreur d'ouverture du rotorRot Open Error HamlibRotDrvJErreur lors du rglage de la positionSet Possition Error HamlibRotDrv8Pilote de rotor non supportUnsupported Rotator Driver HamlibRotDrv&Importer&Import ImportDialog<<p><b>Importation :</b></p><p>

Importing:

 ImportDialogD<p><b>QSO dans le log :</b></p><p>

In-Log QSO:

 ImportDialogf<p>Voulez-vous importer le QSO en double ?</p>%1 %20

Do you want to import duplicate QSO?

%1 %2 ImportDialogADXADX ImportDialogTousAll ImportDialogParcourirBrowse ImportDialogCommentaireComment ImportDialogPlage de dates Date Range ImportDialogPar dfautDefaults ImportDialogDtailsDetails ImportDialogQSO en double Duplicate QSO ImportDialogErreur : %nErreurs : %n Error(s): %n ImportDialogFichierFile ImportDialogfComplter les informations d entit DXCC manquantes$Fill missing DXCC Entity Information ImportDialogSi le DXCC manque dans l enregistrement import, il sera dtermin partir de l indicatif.QIf DXCC is missing in the imported record, it will be resolved from the callsign. ImportDialogImportationImport ImportDialog2Rsultat de l'importation Import Result ImportDialogxImporter tous les QSO ou seulement ceux d'une priode donne-Import all or only QSOs from the given period ImportDialog$Date d'importation Import date ImportDialogFichier import Imported file ImportDialog(Import : %n contact,Imports : %n contactsImported: %n contact(s) ImportDialogMon profil My Profile ImportDialogMon transceiverMy Rig ImportDialogOptionsOptions ImportDialog8Rsum de l'importation QLogQLog Import Summary ImportDialog4Enregistrer les dtails...Save Details... ImportDialog6Sauvegarder dans un fichier Save to File ImportDialog.Slectionner un fichier Select File ImportDialogLa valeur est utilise lorsqu'un enregistrement d'entre ne contient pas la valeur ADIFFThe value is used when an input record does not contain the ADIF value ImportDialogLes valeurs ci-dessous seront utilises lorsqu'un enregistrement d'entre ne contient pas les valeurs ADIFSThe values below will be used when an input record does not contain the ADIF values ImportDialog$Avertissement : %n&Avertissements : %nWarning(s): %n ImportDialogFentreDialogInputPasswordDialog.Retenir le mot de passeRemember PasswordInputPasswordDialogLe mot de passe sera enregistr dans le gestionnaire d'identifiants.4The password will be stored in the Credential Store.InputPasswordDialog*Mot de passe invalideInvalid passwordKSTChat&Utilisateur inconnu Unknown UserKSTChatAzimut (Beam)Beam KSTChatWidget,Messages de discussion Chat messages KSTChatWidget(Effacer les messagesClear Messages KSTChatWidgetNEffacer tous les messages de la fentre Clear all messages in the window KSTChatWidgetEffacer l'indicatif slectionn et le message de discussion saisi./Clear selected Callsign and Chat message entry. KSTChatWidget.Visibilit des colonnesColumn Visibility KSTChatWidget Mise en vidence Highlight KSTChatWidget4Rgles de mise en videnceHighlight Rules KSTChatWidgetdMettre en vidence les messages selon les rglages'Highlight messages based on the setting KSTChatWidgetPrparer le QSO Prepare QSO KSTChatWidget$Envoyer le messageSend chat message KSTChatWidget*M'afficher uniquementShow About Me Only KSTChatWidgettAfficher uniquement les messages mentionnant mon indicatif/Show only messages where my callsign is present KSTChatWidgetJSupprimer "Utilisateur Utilisateur"Suppress User To User KSTChatWidgetfSupprimer les messages privs entre deux indicatifs/Suppress private messages between two callsigns KSTChatWidgetTransfrer l'indicatif et le Locator vers la fentre de nouveau QSOBTransfer Callsign and Gridsquare Information to the New QSO dialog KSTChatWidget&Messages importantsValuable messages KSTChatWidgetNQuelles colonnes doivent tre affiches!Which columns should be displayed KSTChatWidgetVousYou KSTChatWidget*Ajouter une condition Add ConditionKSTHighlightRuleDetailTousAllKSTHighlightRuleDetail>Toutes les conditions suivantesAll the following conditionsKSTHighlightRuleDetail<L'une des conditions suivantesAny of the following conditionsKSTHighlightRuleDetail&Salon de discussion Chat RoomKSTHighlightRuleDetailContientContainsKSTHighlightRuleDetail"Modifier la rgle Edit RuleKSTHighlightRuleDetail ActivEnabledKSTHighlightRuleDetailLocator GridsquareKSTHighlightRuleDetail^Mettre en vidence les messages correspondant Highlight message which matchKSTHighlightRuleDetailMessageMessageKSTHighlightRuleDetail*Ne doit pas tre videMust not be emptyKSTHighlightRuleDetailSupprimerRemoveKSTHighlightRuleDetailNom de la rgle Rule NameKSTHighlightRuleDetailExpditeurSenderKSTHighlightRuleDetailCommence par Starts withKSTHighlightRuleDetailAjouterAddKSTHighlighterSettingDialogModifierEditKSTHighlighterSettingDialog4Rgles de mise en videnceHighlight RulesKSTHighlighterSettingDialogNomNameKSTHighlighterSettingDialogSupprimerRemoveKSTHighlighterSettingDialog RglesRulesKSTHighlighterSettingDialogtatStateKSTHighlighterSettingDialogEffacerClearKeySequenceEdit0<html><head/><body><p>& <span style=" font-weight:700;">La base de donnes actuelle sera SUPPRIME !</span><br/>& <span style=" font-weight:700;">Tous les mots de passe enregistrs seront SUPPRIMS !</span><br/>& <span style=" font-weight:700;">L'application redmarrera aprs le chargement</span>.</p><p>Pour prserver les donnes, utilisez d'abord Pack Data &amp; Settings ou Export QSOs.</p></body></html>o

Current database will be DELETED!
All stored passwords will be DELETED!
The application will restart after loading.

To preserve data, use Pack Data & Settings or Export QSOs first.

LoadDatabaseDialogParcourirBrowseLoadDatabaseDialogRImpossible de crer le fichier temporaireCannot create temporary fileLoadDatabaseDialogpImpossible de dcompresser le fichier de base de donnesCannot decompress database fileLoadDatabaseDialogLImpossible d'ouvrir la base de donnesCannot open databaseLoadDatabaseDialogLDcompression de la base de donnes...Decompressing database...LoadDatabaseDialog6Dchiffrer les identifiantsDecrypt CredentialsLoadDatabaseDialog*Plateforme diffrenteDifferent platformLoadDatabaseDialognEntrez le mot de passe pour dchiffrer les identifiants%Enter password to decrypt credentialsLoadDatabaseDialogFichier :File:LoadDatabaseDialog*Mot de passe invalideInvalid passwordLoadDatabaseDialog*Charger && RedmarrerLoad && RestartLoadDatabaseDialogbAucun identifiant chiffr dans la base de donnes$No encrypted credentials in databaseLoadDatabaseDialogdMot de passe requis pour importer les identifiants'Password required to import credentialsLoadDatabaseDialogMot de passe : Password:LoadDatabaseDialogzExport de base de donnes QLog (*.dbe);;Tous les fichiers (*)+QLog Database Export (*.dbe);;All Files (*)LoadDatabaseDialog>Slectionner la base de donnesSelect DatabaseLoadDatabaseDialogTSlectionner le fichier de base de donnesSelect Database FileLoadDatabaseDialogDStatut : Aucun fichier slectionnStatus: No file selectedLoadDatabaseDialogLDballer les donnes et les paramtresUnpack Data & SettingsLoadDatabaseDialog,Base de donnes valideValid databaseLoadDatabaseDialogAvertissementWarningLoadDatabaseDialogUn ensemble minimal de champs est manquant (start_time, call, band, mode, station_callsign)TA minimal set of fields not present (start_time, call, band, mode, station_callsign) LogFormathImpossible de trouver mes informations d'entit DXCCCannot find My DXCC Entity Info LogFormatXImpossible d'insrer dans la base de donnesCannot insert to database LogFormatJLes informations DXCC sont manquantesDXCC Info is missing LogFormattat DXCC : DXCC State: LogFormatDoublon Duplicate LogFormat ErreurError LogFormatImportImported LogFormatVEn dehors de la plage de dates slectionneOutside the selected Date Range LogFormatAvertissementWarning LogFormatDaucun indicatif de station prsentno Station Callsign present LogFormatNb rafales MS #MS Bursts LogbookModelNb pings MS #MS Pings LogbookModelIndice AA-Index LogbookModelSection ARRL ARRL Section LogbookModel&Champs additionnelsAdditional Fields LogbookModelAdresseAddress LogbookModelAdresse (ASCII)Address (ASCII) LogbookModelgeAge LogbookModelAltitudeAltitude LogbookModelAzimut Antenne Antenna Az LogbookModel"lvation Antenne Antenna El LogbookModel&Rcompense accorde Award Granted LogbookModel$Rcompense soumiseAward Submitted LogbookModel BandeBand LogbookModelBande RXBand RX LogbookModelCQZCQZ LogbookModelInfos cl CW CW Key Info LogbookModelType de cl CW CW Key Type LogbookModelIndicatifCall LogbookModel ClasseClass LogbookModel(Date d'envoi ClubLogClubLog Upload Date LogbookModel(tat d'envoi ClubLogClubLog Upload State LogbookModelCommentaireComment LogbookModel&Commentaire (ASCII)Comment (ASCII) LogbookModel$Oprateur contactContacted Operator LogbookModel*Vrification Concours Contest Check LogbookModelID Concours Contest ID LogbookModel(Precedence (Contest)Contest Precedence LogbookModelContinent Continent LogbookModelPaysCountry LogbookModelPays (ASCII)Country (ASCII) LogbookModel ComtCounty LogbookModelComt Alt County Alt LogbookModelCrdit accordCredit Granted LogbookModelCrdit soumisCredit Submitted LogbookModelDCLrDCLr LogbookModelDate DCLr DCLr Date LogbookModelDCLsDCLs LogbookModelDate DCLs DCLs Date LogbookModelDOKDOK LogbookModelDXCCDXCC LogbookModelDistanceDistance LogbookModelInit EMEEME Init LogbookModel EmailEmail LogbookModelFISTS CCFISTS CC LogbookModelNumro FISTS FISTS Number LogbookModelFrquence Frequency LogbookModelFrquence RX Frequency RX LogbookModelLocator Gridsquare LogbookModelLocator tenduGridsquare Extended LogbookModel Oprateur invitGuest Operator LogbookModel&Date d'envoi HRDLogHRDLog Upload Date LogbookModel*Statut d'envoi HRDLogHRDLog Upload Status LogbookModel&Date d'envoi HamQTHHamQTH Upload Date LogbookModel*Statut d'envoi HamQTHHamQTH Upload Status LogbookModel*Date d'envoi HamlogEUHamlogEU Upload Date LogbookModel.Statut d'envoi HamlogEUHamlogEU Upload Status LogbookModelIOTAIOTA LogbookModelID le IOTAIOTA Island ID LogbookModelITUITU LogbookModelIndice KK-Index LogbookModelLatitudeLatitude LogbookModelLoTWLoTW LogbookModel LoTWrLoTWr LogbookModelDate LoTWr LoTWr Date LogbookModel LoTWsLoTWs LogbookModelDate LoTWs LoTWs Date LogbookModelBIndicatif de la station de saisieLogging Station Callsign LogbookModelLongitude Longitude LogbookModel4Essaim MS (Mtor Scatter)MS Shower Name LogbookModel(Rafales max (Bursts) Max Bursts LogbookModelModeMode LogbookModelMa section ARRLMy ARRL Section LogbookModelMon altitude My Altitude LogbookModelMon antenne My Antenna LogbookModel&Mon antenne (ASCII)My Antenna (ASCII) LogbookModelMa zone CQMy CQZ LogbookModel&Infos sur ma cl CWMy CW Key Info LogbookModel$Mon type de cl CWMy CW Key Type LogbookModelMa villeMy City LogbookModel Ma ville (ASCII)My City (ASCII) LogbookModelMon pays My Country LogbookModel Mon pays (ASCII)My Country (ASCII) LogbookModel*Mon dpartement/comt My County LogbookModel*Mon dpartement (Alt) My County Alt LogbookModelMon DOK (DARC) My DARC DOK LogbookModelMon DXCCMy DXCC LogbookModelMon n FISTSMy FISTS LogbookModelMon Locator My Gridsquare LogbookModel(Mon Locator (tendu)My Gridsquare Extended LogbookModelMon IOTAMy IOTA LogbookModel"Mon ID d'le IOTAMy IOTA Island ID LogbookModelMa zone ITUMy ITU LogbookModelMa latitude My Latitude LogbookModelMa longitude My Longitude LogbookModelMon nomMy Name LogbookModelMon nom (ASCII)My Name (ASCII) LogbookModelMa rf. POTA My POTA Ref LogbookModelMon code postalMy Postal Code LogbookModel.Mon code postal (ASCII)My Postal Code (ASCII) LogbookModelMa station/TRXMy Rig LogbookModel,Ma station/TRX (ASCII)My Rig (ASCII) LogbookModelMon SOTAMy SOTA LogbookModel8Infos activit spc. (ASCII)&My Spec. Interes Activity Info (ASCII) LogbookModel(Infos activit spc.My Spec. Interest Activity Info LogbookModel*Mon activit spcialeMy Special Interest Activity LogbookModel:Mon activit spciale (ASCII)$My Special Interest Activity (ASCII) LogbookModel"Mon tat/ProvinceMy State LogbookModel Ma rue My Street LogbookModel"Mes comts USA-CAMy USA-CA Counties LogbookModel"Mes locators VUCC My VUCC Grids LogbookModelMon WWFFMy WWFF LogbookModelNomName LogbookModelNom (ASCII) Name (ASCII) LogbookModel NotesNotes LogbookModelNotes (ASCII) Notes (ASCII) LogbookModel0Indicatif de l'oprateurOperator Callsign LogbookModel2Indicatif du propritaireOwner Callsign LogbookModelPOTAPOTA LogbookModel PapierPaper LogbookModelPrfixePrefix LogbookModel&Mode de propagationPropagation Mode LogbookModel6Cl de chiffrement publiquePublic Encryption Key LogbookModel4Date de tlchargement QRZQRZ Download Date LogbookModel2Statut tlchargement QRZQRZ Download Status LogbookModel*Date d'envoi vers QRZQRZ Upload Date LogbookModel*Statut envoi vers QRZQRZ Upload Status LogbookModelMessage QSL QSL Message LogbookModelQSL Reue QSL Received LogbookModelQSL EnvoyeQSL Sent LogbookModelQSL viaQSL Via LogbookModelQSLrQSLr LogbookModelDate QSLr QSLr Date LogbookModel"Message QSL reue QSLr Message LogbookModelQSL reue viaQSLr Via LogbookModelQSLsQSLs LogbookModelDate QSLs QSLs Date LogbookModel&Message QSL envoye QSLs Message LogbookModel6Message QSL envoye (ASCII)QSLs Message (ASCII) LogbookModelQSL envoye viaQSLs Via LogbookModelQSO termin QSO Completed LogbookModel ID QSOQSO ID LogbookModelQSO alatoire QSO Random LogbookModelQTHQTH LogbookModelQTH (ASCII) QTH (ASCII) LogbookModelRST ReuRST Rcvd LogbookModelRST EnvoyRST Sent LogbookModelRSTrRSTr LogbookModelRSTeRSTs LogbookModelchange reuRcvExch LogbookModelN reuRcvNr LogbookModelPuissance reueRcvPWR LogbookModel RgionRegion LogbookModelTRXRig LogbookModelTRX (ASCII) Rig (ASCII) LogbookModelMode SatelliteSAT Mode LogbookModel Nom du SatelliteSAT Name LogbookModelSIGSIG LogbookModelSIG (ASCII) SIG (ASCII) LogbookModelInfos SIGSIG Info LogbookModel"Infos SIG (ASCII)SIG Info (ASCII) LogbookModelMembre SKCC SKCC Member LogbookModelSOTASOTA LogbookModelSWLSWL LogbookModelchange envoySentExch LogbookModelN envoySentNr LogbookModel Chemin du Signal Signal Path LogbookModelSilent Key (SK) Silent Key LogbookModelFlux solaire Solar Flux LogbookModeltatState LogbookModelSous-modeSubmode LogbookModel TX PWRTX PWR LogbookModelNumro Ten-TenTen-Ten Number LogbookModelHeure finTime off LogbookModelHeure dbutTime on LogbookModelMembre UKSMG UKSMG Member LogbookModelComts USA-CAUSA-CA Counties LogbookModelProvince VEVE Prov LogbookModelVUCCVUCC LogbookModelWWFFWWFF LogbookModelWebWeb LogbookModeleQSLeQSL LogbookModeleQSL AGeQSL AG LogbookModel eQSLreQSLr LogbookModelDate eQSLr eQSLr Date LogbookModel eQSLseQSLs LogbookModelDate eQSLs eQSLs Date LogbookModel8Ajouter les infos manquantesAdd Missing Info LogbookWidget"Toutes les bandes All Bands LogbookWidgetTous les clubs All Clubs LogbookWidgetTous les pays All Countries LogbookWidgetTous les modes All Modes LogbookWidget^La mise jour affectera toutes les lignes slectionnes.<br>La valeur dite dans la colonne sera applique toute la slection.<br><br>Voulez-vous valider la modification ?By updating, all selected rows will be affected.
The value currently edited in the column will be applied to all selected rows.

Do you want to edit them? LogbookWidget$Erreur Callbook : Callbook error:  LogbookWidget<chec de connexion au CallbookCallbook login failed LogbookWidgetIndicatifCallsign LogbookWidgetAnnulerCancel LogbookWidgetpL'option <b>Envoi immdiat</b> de Clublog ne supporte que la suppression unitaire.<br><br>Voulez-vous continuer sachant que l'opration de SUPPRESSION ne sera pas transmise Clublog ?Clublog's Immediately Send supports only one-by-one deletion

Do you want to continue despite the fact
that the DELETE operation will not be sent to Clublog? LogbookWidget0Visibilit des colonnes Column Visibility  LogbookWidgetNombre : %nNombre : %n Count: %n LogbookWidgetSupprimerDelete LogbookWidgetJSupprimer les contacts slectionns ?Delete the selected contacts? LogbookWidget8Suppression des QSO en cours Deleting QSOs LogbookWidget<Tlchargement de l'image eQSLDownloading eQSL Image LogbookWidgetHChaque lot supporte jusqu' 100 QSO.#Each batch supports up to 100 QSOs. LogbookWidget$Modifier la valeur Edit Value LogbookWidget*Exporter la slectionExport Selected LogbookWidget:Exporter les QSO slectionnsExport selected QSOs LogbookWidget*Filtrer par indicatifFilter Callsign LogbookWidgetLocator Gridsquare LogbookWidgetIOTAIOTA LogbookWidget@Carnet de trafic - Supprimer QSOLogbook - Delete QSO LogbookWidgetJCarnet de trafic - Modifier la valeurLogbook - Edit Value LogbookWidgetDCarnet de trafic - Envoyer Spot DXLogbook - Send DX Spot LogbookWidget*Rechercher sur le Web Lookup on Web LogbookWidget.Marquer QSL comme reue Mark QSL RCVD LogbookWidget(Marquer QSL demandeMark QSL Requested LogbookWidget0Aucun filtre utilisateurNo User Filter LogbookWidgetPOTAPOTA LogbookWidgetErreur QLog QLog Error LogbookWidget$Avertissement QLog QLog Warning LogbookWidgetJProgression de la mise jour des QSOQSOs Update Progress LogbookWidgetSIGSIG LogbookWidgetSOTASOTA LogbookWidget$Envoyer un Spot DX Send DX Spot LogbookWidgetMettre jourUpdate LogbookWidget0Mise jour via CallbookUpdate from Callbook LogbookWidget(Envoyer vers ClublogUpload to Clublog LogbookWidgetWWFFWWFF LogbookWidget2Quelles colonnes afficher!Which columns should be displayed LogbookWidgetTchec du tlchargement de l'image eQSL : eQSL Download Image failed:  LogbookWidgetRImpossible d'ouvrir le fichier temporaireCannot open temporary fileLotwQSLDownloaderJIdentifiant ou mot de passe incorrectIncorrect login or passwordLotwQSLDownloaderpTous les QSO taient des doublons ou hors plage de dates-All QSOs were duplicates or out of date range LotwUploader:Erreur de syntaxe de commandeCommand syntax error LotwUploaderxErreur de connexion LoTW (pas de rseau ou LoTW injoignable)9LoTW Connection error (no network or LoTW is unreachable) LotwUploaderpCertains QSO taient des doublons ou hors plage de dates.Some QSOs were duplicates or out of date range LotwUploaderTQSL a plant TQSL crashed LotwUploader TQSL introuvableTQSL not found LotwUploader6Erreur de l'utilitaire TQSLTQSL utility error LotwUploaderErreur TQSLlib TQSLlib error LotwUploaderNImpossible d'ouvrir le fichier d'entreUnable to open input file LotwUploaderPImpossible d'ouvrir le fichier de sortieUnable to open output file LotwUploader2Erreur inattendue de TQSLUnexpected Error from TQSL LotwUploaderDRponse inattendue du serveur TQSL$Unexpected response from TQSL server LotwUploader<Envoi annul par l'utilisateurUpload cancelled by user LotwUploader*Envoi rejet par LoTWUpload rejected by LoTW LotwUploader &propos&About MainWindow&Diplmes&Awards MainWindow&quipement &Equipment MainWindow&Exporter&Export MainWindow&Fichier&File MainWindow &Aide&Help MainWindow&Importer&Import MainWindow"&Carnet de trafic&Logbook MainWindow Saisie &manuelle &Manual Entry MainWindow&Rglages &Settings MainWindow &Wiki&Wiki MainWindow&Fentre&Window MainWindow8<b>Dtail de l'erreur :</b> Error Detail:  MainWindown<h1>QLog %1</h1><p>&copy; 2019 Thomas Gatzweiler DL2IC<br/>&copy; 2021-2026 Ladislav Foldyna OK1MLG<br/>&copy; 2025-2026 Michael Morgan AA5SH<br/>&copy; 2025-2026 Kyle Boyle VE9KZ</p><p>Bas sur Qt %2<br/>%3<br/>%4<br/>%5</p><p>Icnes par <a href='http://www.iconshock.com'>Icon Shock</a><br />Images satellites par <a href='http://www.nasa.gov'>NASA</a><br />ZoneDetect par <a href='https://github.com/BertoldVdb/ZoneDetect'>Bertold Van den Bergh</a><br />Base de donnes TimeZone par <a href='https://github.com/evansiroky/timezone-boundary-builder'>Evan Siroky</a>)

QLog %1

© 2019 Thomas Gatzweiler DL2IC
© 2021-2026 Ladislav Foldyna OK1MLG
© 2025-2026 Michael Morgan AA5SH
© 2025-2026 Kyle Boyle VE9KZ

Based on Qt %2
%3
%4
%5

Icon by Icon Shock
Satellite images by NASA
ZoneDetect by Bertold Van den Bergh
TimeZone Database by Evan Siroky MainWindow6Nouvelle version disponible A New Version MainWindowNUne nouvelle version %1 est disponible.A new version %1 is available. MainWindow proposAbout MainWindowAlertesAlerts MainWindowToutes bandes All Bands MainWindow*Quitter l'applicationApplication - Quit MainWindow Carte des bandesBandmap MainWindowBipBeep MainWindowConsole CW CW Console MainWindow@Console CW - Diminuer la vitesseCW Console - Key Speed Down MainWindowBConsole CW - Augmenter la vitesseCW Console - Key Speed Up MainWindow:Console CW - Profil prcdentCW Console - Profile Down MainWindow6Console CW - Profil suivantCW Console - Profile Up MainWindowChatChat MainWindowClassiqueClassic MainWindowEffacerClear MainWindowHorlogeClock MainWindow>Erreur d'envoi immdiat Clublog Clublog Immediately Upload Error MainWindow Thme de couleur Color Theme MainWindow2Compression de la base...Compressing database... MainWindow:Connecter le manipulateur &CWConnect &CW Keyer MainWindow"Connecter le T&RX Connect R&ig MainWindow&Connecter le r&otorConnect R&otator MainWindow$Concours (Contest)Contest MainWindowConcours :  Contest:  MainWindowDX Cluster DX Cluster MainWindow2&Liste de soumission DXCCDXCC &Submission List MainWindownFichiers base de donnes (*.dbe);;Tous les fichiers (*)%Database files (*.dbe);;All files (*) MainWindowXBase de donnes exporte avec succs vers %1"Database successfully dumped to %1 MainWindowOutils devDeveloper Tools MainWindow`Voulez-vous supprimer le filtre de concours %1 ?,Do you want to remove the Contest filter %1? MainWindowTlchargerDownload MainWindowRcuprer QSL Download QSLs MainWindowVrif. Doublons Dupe Check MainWindowPar bande Each Band MainWindow"Par bande && modeEach Band && Mode MainWindowModifierEdit MainWindow&Modifier les rgles Edit Rules MainWindow"Exporter CabrilloExport Cabrillo MainWindow\chec de la compression de la base de donnes. Failed to compress the database. MainWindowPchec de cration du fichier temporaire. Failed to create temporary file. MainWindowZchec de l'exportation de la base de donnes.Failed to dump the database. MainWindowLchec du chiffrement des identifiants.Failed to encrypt credentials. MainWindowlchec de la prparation de la base pour l'importation.&Failed to prepare database for import. MainWindowGnrer une liste de contacts soumettre pour le crdit ARRL DXCC@Generate a list of contacts to submit for ARRL DXCC award credit MainWindow*Conserver les options Keep Options MainWindow&Lier l'change avecLinking Exchange With MainWindowJCarnet de trafic - Chercher indicatifLogbook - Search Callsign MainWindow*Liste de diffusion...Mailing List... MainWindow CarteMap MainWindowN/DN/A MainWindownNouveau QSO - Ajouter l'indicatif la carte des bandes1New QSO - Add text from Callsign field to Bandmap MainWindow*Nouveau QSO - EffacerNew QSO - Clear MainWindow2Nouveau QSO - EnregistrerNew QSO - Save MainWindow^Nouveau QSO - Utiliser l'indicatif du Whisperer)New QSO - Use Callsign from the Whisperer MainWindowPas de vrif.No Check MainWindow AucunNone MainWindowHNon activ pour le style hors-Fusion Not enabled for non-Fusion style MainWindowCarte en ligne Online Map MainWindow>Sauvegarder donnes && rglagesPack Data && Settings MainWindowPar bandePer Band MainWindow8Appuyez pour rgler l'alertePress to tune the alert MainWindow8&Imprimer les tiquettes QSLPrint QSL &Labels MainWindowImage de profil Profile Image MainWindow&Galerie QSL QSL &Gallery MainWindow&Filtres de QSO QSO &Filters MainWindowQuitterQuit MainWindow0Me le rappeler plus tardRemind Me Later MainWindow&Signaler un &bug...Report &Bug... MainWindowRinitialiserReset MainWindowbRestaurer les options de connexion au redmarrage4Restore connection options after application restart MainWindowTRXRig MainWindow,TRX - Bande infrieureRig - Band Down MainWindow,TRX - Bande suprieure Rig - Band Up MainWindow TRX - PTT On/OffRig - PTT On/Off MainWindow RotorRotator MainWindowExcuter des requtes SQL personnalises en lecture seule sur la base de donnes du logbook=Run custom read-only SQL queries against the logbook database MainWindowS&tatistiques S&tatistics MainWindow4Enregistrer la dispositionSave Arrangement MainWindowSe&rvicesSe&rvice MainWindowSquenceSequence MainWindow<Service - Rcupration des QSLService - Download QSLs MainWindow.Service - Envoi des QSOService - Upload QSOs MainWindow(Afficher les alertes Show Alerts MainWindow SimpleSingle MainWindow ArrtStop MainWindowPasser la saisie de contact en mode manuel<br/>(l'heure, la frquence et les profils ne sont plus synchroniss)|Switch New Contact dialog to the manually entry mode
(time, freq, profiles etc. are not taken from their common sources) MainWindowThme : Natif Theme: Native MainWindow&Thme : QLog SombreTheme: QLog Dark MainWindow$Thme : QLog ClairTheme: QLog Light MainWindowBarre d'outilsToolbar MainWindow:Restaurer donnes && rglagesUnpack Data && Settings MainWindowEnvoyerUpload MainWindow WSJTXWSJTX MainWindowNouveauts What's New MainWindow WSJTXWsjtx MainWindow op : op:  MainWindow AuroreAuroraMapWebChannelHandlerRayon (Beam)BeamMapWebChannelHandlerChatChatMapWebChannelHandler2Ligne de gris (Gray-Line) Gray-LineMapWebChannelHandlerGrille/LocatorGridMapWebChannelHandlerIBPIBPMapWebChannelHandlerMUFMUFMapWebChannelHandlerChemin/TrajetPathMapWebChannelHandler"WSJTX - Appels CQ WSJTX - CQMapWebChannelHandler MHz MHzNewContactWidget W WNewContactWidget m mNewContactWidget&Dtails&DetailsNewContactWidget5959NewContactWidget80m80mNewContactWidget$<b>DOUBLON !!!</b>DUPE !!!NewContactWidget0<b>Statistiques DXCC</b>DXCC StatisticsNewContactWidgetB<b>Statistiques de la station</b>Station StatisticsNewContactWidget<b>Oui</b> - une carte QSL a t envoye ; le QSO a t transmis et accept par le service en ligne<br/><b>Non</b> - ne pas envoyer de QSL ; ne pas transmettre le QSO au service en ligne<br/><b>Demand</b> - le correspondant a demand une QSL ou un envoi vers un service en ligne<br/><b>En file d'attente</b> - la QSL ou l'envoi vers le service est programm<br/>Yes - an outgoing QSL card has been sent; the QSO has been uploaded to, and accepted by, the online service
No - do not send an outgoing QSL card; do not upload the QSO to the online service
Requested - the contacted station has requested a QSL card; the contacted station has requested the QSO be uploaded to the online service
Queued - an outgoing QSL card has been selected to be sent; a QSO has been selected to be uploaded to the online service
NewContactWidgetAntenneAntennaNewContactWidgetVideBlankNewContactWidget BureauBureauNewContactWidget<chec de connexion au CallbookCallbook login failedNewContactWidget2Recherche Callbook activeCallbook search is activeNewContactWidget6Recherche Callbook inactiveCallbook search is inactiveNewContactWidgetIndicatifCallsignNewContactWidgetConfirm ConfirmedNewContactWidgetlL'ID du Concours doit tre renseign pour l'activation(Contest ID must be filled in to activateNewContactWidgetStats D&X D&X StatsNewContactWidgetDateDateNewContactWidgetfDescription de l'quipement de la station contacte0Description of the contacted station's equipmentNewContactWidget DirectDirectNewContactWidget DureDurationNewContactWidgetlectronique ElectronicNewContactWidget$Dvelopper/RduireExpand/CollapseNewContactWidgetFrquence FrequencyNewContactWidget&GA (Good Afternoon)GANewContactWidget"GE (Good Evening)GENewContactWidget"GM (Good Morning)GMNewContactWidget IgnorIgnoredNewContactWidget InfosInfoNewContactWidgetCe n'est pas le nom complet du concours mais l'ID attribu<br>(ex. CQ-WW-CW pour le CQ WW DX Contest CW)oIt is not the name of the contest but it is an assigned
Contest ID (ex. CQ-WW-CW for CQ WW DX Contest (CW)) NewContactWidgetLP (Long Path)LPNewContactWidgetLoTWLoTWNewContactWidgetRechercher l'indicatif sur le web. L'URL peut tre modifie dans Rglages -> CallbookPLookup the call on the web. The query URL can be changed in Settings -> CallbookNewContactWidgetM&a Station M&y StationNewContactWidgetMembre :Member:NewContactWidgetModeModeNewContactWidgetMes &Notes My &NotesNewContactWidget,Nouveau Bande & Mode !New Band & Mode!NewContactWidget Nouvelle Bande ! New Band!NewContactWidget"Nouvelle Entit ! New Entity!NewContactWidgetNouveau Mode ! New Mode!NewContactWidgetNouveau Slot ! New Slot!NewContactWidgetNonNoNewContactWidget PapierPaperNewContactWidget&Mode de propagationPropagation ModeNewContactWidgetErreur QLog QLog ErrorNewContactWidget Statut envoi QSLQSL Send StatusNewContactWidgetQSL envoye via QSL Send viaNewContactWidgetQSL viaQSL viaNewContactWidget"En file d'attenteQueuedNewContactWidgetRST reuRSTrNewContactWidgetRST envoyRSTsNewContactWidget RX : RX: NewContactWidgetDemand RequestedNewContactWidget RinitResetNewContactWidgetTRXRigNewContactWidgetEnregistrerSaveNewContactWidget4Groupe d'Activit SpcialeSpecial Activity GroupNewContactWidgetTInformations du Groupe d'Activit Spciale"Special Activity Group InformationNewContactWidgetStationStationNewContactWidget TX : TX: NewContactWidgetHeure dbutTime OnNewContactWidgetWebWebNewContactWidget"Contact (Worked)WorkedNewContactWidget>World Wide Flora & Fauna (WWFF)World Wide Flora & FaunaNewContactWidgetOuiYesNewContactWidgeteQSLeQSLNewContactWidgetle DOK (District Location Code) DARC de la station contacte (ex. A01)Cthe contacted station's DARC DOK (District Location Code) (ex. A01)NewContactWidgetdeux ou quatre locators adjacents (Maidenhead), chacun de quatre caractres (ex. JN18,JN19...)ctwo or four adjacent Maidenhead grid locators, each four characters long, (ex. EN98,FM08,EM97,FM07)NewContactWidget.Erreur d'initialisationInitialization Error OmnirigRigDrvTransceiver 1Rig 1 OmnirigRigDrvTransceiver 2Rig 2 OmnirigRigDrvBLe transceiver n'est pas connectRig is not connected OmnirigRigDrv6Le statut du poste a changRig status changed OmnirigRigDrv.Erreur d'initialisationInitialization ErrorOmnirigV2RigDrvTransceiver 1Rig 1OmnirigV2RigDrvTransceiver 2Rig 2OmnirigV2RigDrvTransceiver 3Rig 3OmnirigV2RigDrvTransceiver 4Rig 4OmnirigV2RigDrvBLe transceiver n'est pas connectRig is not connectedOmnirigV2RigDrv6Le statut du poste a changRig status changedOmnirigV2RigDrv4Impossible de lier un portCannot bind a port PSTRotDrvLImpossible d'obtenir l'adresse IP pourCannot get IP Address for PSTRotDrv.Une erreur est survenueError Occurred PSTRotDrv.Pas d'adresse IPv4 pourNo IPv4 Address for PSTRotDrv.Dlai d'attente dpassOperation Timeout PSTRotDrvRotor 1Rot 1 PSTRotDrv$Ajouter un fichierAdd FilePaperQSLDialogQSL disponiblesAvailable QSLsPaperQSLDialogCopie le fichier d'entre du dossier source vers le stockage QSL interne de QLog.<br/>Le fichier original reste inchang dans le dossier sourceCopy the input file from the source folder to the QLog Internal QSL Storage folder.
The original file remains unchanged in the source folderPaperQSLDialogSupprimerDeletePaperQSLDialog$Supprimer la QSL ? Delete QSL?PaperQSLDialogImporter QSL Import QSLPaperQSLDialog$Grer la carte QSLManage QSL CardPaperQSLDialog OuvrirOpenPaperQSLDialogRetirerRemovePaperQSLDialog6Ajouter/Retirer des favorisToggle FavoritePaperQSLDialog*Tous les fichiers (*) All Files (*)PlatformSettingsDialogContinuerContinuePlatformSettingsDialogLParamtres spcifiques la plateformePlatform-specific SettingsPlatformSettingsDialog.Slectionner le fichier Select FilePlatformSettingsDialogParamtreSettingPlatformSettingsDialogLa base de donnes a t exporte depuis une plateforme diffrente. Veuillez vrifier ou mettre jour les paramtres suivants. Vous pouvez laisser les champs vides et les configurer plus tard dans les Paramtres.The database was exported from a different platform. Please verify or update the following settings. You can leave fields empty and configure them later in Settings.PlatformSettingsDialog ValeurValuePlatformSettingsDialogImage de profil Profile ImageProfileImageWidgetAide de QLog QLog HelpQCoreApplication2<b>Erreur Keyer CW :</b> CW Keyer Error:  QMessageBox8<b>Erreur Transceiver :</b> Rig Error:  QMessageBox,<b>Erreur Rotor :</b> Rotator Error:  QMessageBoxl<b>Plage TX</b> : La frquence max ne doit pas tre 0.-TX Range: Max Frequency must not be 0. QMessageBox<b>Plage TX</b> : La frquence max ne doit pas tre infrieure la frquence min.?TX Range: Max Frequency must not be under Min Frequency. QMessageBox<Ce nom d'activit existe dj. Activity name is already exists. QMessageBox@La zone CQ ne doit pas tre videCQZ must not be empty QMessageBox(Le port du keyer CW doit tre un port COM valide.<br>Pour Windows, utilisez COMxx, pour les OS de type Unix, utilisez un chemin vers le priphriquegCW Keyer port must be a valid COM port.
For Windows use COMxx, for unix-like OS use a path to device QMessageBoxjL'expression rgulire de l'indicatif est incorrecte.)Callsign Regular Expression is incorrect. QMessageBoxJLe format de l'indicatif est invalideCallsign has an invalid format QMessageBox^Impossible de mettre jour les rgles d'alerteCannot Update Alert Rules QMessageBoxImpossible de changer le modle de keyer CW en <b>Morse via CAT</b><br>Pas de support Morse via CAT pour le(s) poste(s) <b>%1</b>kCannot change the CW Keyer Model to Morse over CAT
No Morse over CAT support for Rig(s) %1 QMessageBoxImpossible de supprimer le profil de keyer CW<br>Ce profil est utilis par le(s) poste(s) : <b>%1</b>UCannot delete the CW Keyer Profile
The CW Key Profile is used by Rig(s): %1 QMessageBoxImpossible de rcuprer un mot de passe pour %1 depuis le gestionnaire d'identifiants6Cannot get a password for %1 from the Credential Store QMessageBoxImpossible de sauvegarder un mot de passe pour %1 dans le gestionnaire d'identifiants5Cannot save a password for %1 to the Credential Store QMessageBoxpImpossible de mettre jour les conditions du filtre QSO#Cannot update QSO Filter Conditions QMessageBoxFImpossible d'crire dans le fichierCannot write to the file QMessageBox"Erreur de Chat :  Chat Error:  QMessageBoxMise jour de la liste des clubs choue. Impossible de planifier les nouveaux tlchargements2Club List Update failed. Cannot plan new downloads QMessageBoxMise jour de la liste des clubs choue. Impossible de supprimer les anciens enregistrements2Club List Update failed. Cannot remove old records QMessageBoxjL'expression rgulire du commentaire est incorrecte.(Comment Regular Expression is incorrect. QMessageBox`Impossible de se connecter la base de donnes.Could not connect to database. QMessageBoxImpossible d'exporter la base QLog vers ADIF pour sauvegarde.<p>Essayez d'exporter votre carnet de trafic en ADIF manuellement_Could not export a QLog database to ADIF as a backup.

Try to export your log to ADIF manually QMessageBox:Le pays ne doit pas tre videCountry must not be empty QMessageBox.Mot de passe DX ClusterDX Cluster Password QMessageBoxDErreur de connexion au serveur DXCDXC Server Connection Error QMessageBox8Erreur de nom de serveur DXCDXC Server Name Error QMessageBoxL'adresse du serveur DXC doit tre au format<p><b>[utilisateur@]hte:port</b> (ex. hamqth.com:7300)</p>`DXC Server address must be in format

[username@]hostname:port (ex. hamqth.com:7300)

 QMessageBoxXLa migration de la base de donnes a chou.Database migration failed. QMessageBox&%n contact export.*%n contacts exports.Exported %n contact(s). QMessageBoxExport. Exported. QMessageBoxchec du traitement de l'importation de la base de donnes en attente.*Failed to process pending database import. QMessageBox4Le nom de fichier est videFilename is empty QMessageBox:Ce nom de filtre existe dj.Filter name is already exists. QMessageBoxBLe format du Locator est invalide Gridsquare has an invalid format QMessageBoxBLa zone ITU ne doit pas tre videITU must not be empty QMessageBox*Mot de passe invalideInvalid Password QMessageBoxBoucle dtecte. Le transfert UDP brut utilise le mme port que le port de rception WSJT-X.OLoop detected. Raw UDP forward uses the same port as the WSJT-X receiving port. QMessageBoxErreur rseau. Impossible de tlcharger la liste des clubs pour,Network error. Cannot download Club List for QMessageBox^L'indicatif de l'oprateur a un format invalide'Operator Callsign has an invalid format QMessageBoxxVeuillez dfinir au moins un profil d'emplacement de station5Please, define at least one Station Locations Profile QMessageBoxQLog Critique QLog Critical QMessageBoxErreur QLog QLog Error QMessageBoxInfo QLog QLog Info QMessageBox Information QLogQLog Information QMessageBox$Avertissement QLog QLog Warning QMessageBoxDQLog est dj en cours d'excutionQLog is already running QMessageBoxLe port PTT doit tre un port COM valide.<br>Pour Windows, utilisez COMxx, pour les OS de type Unix, utilisez un chemin vers le priphriquefRig PTT port must be a valid COM port.
For Windows use COMxx, for unix-like OS use a path to device QMessageBox.Le port du transceiver doit tre un port COM valide.<br>Pour Windows, utilisez COMxx, pour les OS de type Unix, utilisez un chemin vers le priphriquebRig port must be a valid COM port.
For Windows use COMxx, for unix-like OS use a path to device QMessageBox"Le port du rotor doit tre un port COM valide.<br>Pour Windows, utilisez COMxx, pour les OS de type Unix, utilisez un chemin vers le priphriquefRotator port must be a valid COM port.
For Windows use COMxx, for unix-like OS use a path to device QMessageBox8Ce nom de rgle existe dj.Rule name is already exists. QMessageBoxLa base de donnes a t importe avec succs, mais les mots de passe stocks n'ont pas pu tre restaurs (chec du dchiffrement ou donnes corrompues). Tous les mots de passe des services ont t effacs et doivent tre saisis nouveau dans les Paramtres.The database was imported successfully, but the stored passwords could not be restored (decryption failed or the data is corrupted). All service passwords have been cleared and must be re-entered in Settings. QMessageBoxLes champs <b>%0</b> ne seront pas sauvegards car <b>%1</b> n'est pas renseign.KThe fields %0 will not be saved because the %1 is not filled. QMessageBoxXContenu inattendu de la liste des clubs pour Unexpected Club List content for QMessageBoxTlchargement inattendu de la liste des clubs. Annulation des tlchargements suivants7Unexpected Club List download. Canceling next downloads QMessageBoxLes carrs VUCC ont un format invalide (doit tre 2 ou 4 Locators spars par des virgules)OVUCC Grids have an invalid format (must be 2 or 4 Gridsquares separated by ',') QMessageBoxLe multicast WSJT-X est activ mais l'adresse n'est pas une adresse multicast.FWSJTX Multicast is enabled but the Address is not a multicast address. QMessageBoxVotre indicatif est vide. Veuillez configurer votre profil de station8Your callsign is empty. Please, set your Station Profile QMessageBox0(chemin interne Flatpak)(Flatpak internal path)QObject$<b>Erreur</b> : %n&<b>Erreurs</b> : %nError(s): %nQObject6<b>Import</b> : %n contact:<b>Imports</b> : %n contactsImported: %n contact(s)QObject2<b>Avertissement</b> : %n4<b>Avertissements</b> : %nWarning(s): %nQObject@Sauvegarde de la base de donnesBackuping DatabaseQObjectKeyer CWCW KeyerQObjecttImpossible de se connecter au serveur DXC <p>Raison <b> : ,Cannot connect to DXC Server

Reason : QObjectConfirm ConfirmedQObject"Connexion refuseConnection RefusedQObjectFLe fichier n'est pas un export QLog Database is not QLog Export fileQObjectVersion de la base trop rcente (ncessite une version plus rcente de QLog)6Database version too new (requires newer QLog version)QObject6L'hte a ferm la connexionHost closed the connectionQObject Hte introuvableHost not foundQObjectBImportation de la base de donnesImporting DatabaseQObjectErreur InterneInternal ErrorQObject<Indicatif de la station de logLogging Station CallsignQObject>Migration de la base de donnesMigrating DatabaseQObjectMa zone CQMy CQZQObjectMa villeMy CityQObjectMon pays My CountryQObject*Mon dpartement/comt My CountyQObjectMon DOK (DARC) My DARC DOKQObjectMon DXCCMy DXCCQObjectMon Locator My GridsquareQObjectMon IOTAMy IOTAQObjectMa zone ITUMy ITUQObjectMa rf. POTA My POTA RefQObjectMon transceiverMy RigQObjectMon SOTAMy SOTAQObject,Info activit spcialeMy Spec. Interes Activity InfoQObject*Mon activit spcialeMy Special Interest ActivityQObjectMes carrs VUCC My VUCC GridsQObjectMon WWFFMy WWFFQObjectErreur Rseau Network ErrorQObject:Base de donnes QLog invalideNot a valid QLog databaseQObject>Ouverture de la base de donnesOpening DatabaseQObject0Indicatif de l'oprateurOperator CallsignQObject$Nom de l'oprateur Operator NameQObject PosteRigQObjectPTT PosteRig PTTQObjectrigctld Poste Rig rigctldQObject RotorRotatorQObject4Dmarrage de l'applicationStarting ApplicationQObjectTOTAL confirmsTOTAL ConfirmedQObjectTOTAL contacts TOTAL WorkedQObjectChemin TQSL TQSL PathQObject.Dlai d'attente dpassTimeoutQObjectkmkmQObject millesmilesQObjectQRZ.comQRZ.com QRZCallbookErreur gnrale General Error QRZUploader%n carte QSL%n cartes QSL%n QSL card(s)QSLGalleryDialog&Ajouter aux favorisAdd to FavoritesQSLGalleryDialog*Toutes les cartes QSL All QSL CardsQSLGalleryDialogPar BandeBy BandQSLGalleryDialogPar Continent By ContinentQSLGalleryDialogPar Pays By CountryQSLGalleryDialogPar DateBy DateQSLGalleryDialogPar ModeBy ModeQSLGalleryDialogIndicatif (A-Z)Callsign (A-Z)QSLGalleryDialogIndicatif (Z-A)Callsign (Z-A)QSLGalleryDialog$Date (plus rcent) Date (Newest)QSLGalleryDialog$Date (plus ancien) Date (Oldest)QSLGalleryDialog Exporter filtrsExport FilteredQSLGalleryDialog.Exporter les cartes QSLExport QSL CardsQSLGalleryDialog4%1 cartes sur %2 exportesExported %1 of %2 cardsQSLGalleryDialogFavoris FavoritesQSLGalleryDialog OuvrirOpenQSLGalleryDialog*Galerie de cartes QSLQSL Card GalleryQSLGalleryDialog&Retirer des favorisRemove from FavoritesQSLGalleryDialog0Enregistrer la carte QSL Save QSL CardQSLGalleryDialogEnregistrer...Save...QSLGalleryDialog2Chercher par indicatif...Search by callsign...QSLGalleryDialogTrier par :Sort by:QSLGalleryDialogDtailsDetailsQSLImportStatDialogTlcharges : Downloaded:QSLImportStatDialogErreurs :Errors:QSLImportStatDialog Nouvelles QSL :  New QSLs: QSLImportStatDialog6Rsum de l'importation QSLQSL Import SummaryQSLImportStatDialog RsumSummaryQSLImportStatDialog(QSL non apparies : Unmatched QSLs: QSLImportStatDialogNon apparies : Unmatched:QSLImportStatDialog"QSO mis jour : Updated QSOs: QSLImportStatDialogMises jour :Updated:QSLImportStatDialog*Taille To Radio :"To Radio" Size:QSLPrintLabelDialog(Texte To Radio :"To Radio" Text:QSLPrintLabelDialog&(nom de colonne BD)(DB column name)QSLPrintLabelDialog2Texte d en-tte de bande:Band Header Text:QSLPrintLabelDialog,Taille de l indicatif:Callsign Size:QSLPrintLabelDialogColonne:Columns:QSLPrintLabelDialogPersonnalisCustomQSLPrintLabelDialog&Taille des donnes: Data Size:QSLPrintLabelDialogFormat de date: Date Format:QSLPrintLabelDialog0Texte d en-tte de date:Date Header Text:QSLPrintLabelDialogPlage de dates Date RangeQSLPrintLabelDialogVideEmptyQSLPrintLabelDialogExporter en PDF Export PDFQSLPrintLabelDialogExporter en PDF Export as PDFQSLPrintLabelDialogDTexte de la colonne supplmentaireExtra Column TextQSLPrintLabelDialog.Colonne supplmentaire: Extra Column:QSLPrintLabelDialogFiltrerFilterQSLPrintLabelDialog:Texte de pied de page gauche:Footer Left Text:QSLPrintLabelDialog8Texte de pied de page droit:Footer Right Text:QSLPrintLabelDialog,Espacement horizontal: H Spacing:QSLPrintLabelDialog(Taille de l en-tte: Header Size:QSLPrintLabelDialog0Apparence de l tiquetteLabel AppearanceQSLPrintLabelDialog.Hauteur de l tiquette: Label Height:QSLPrintLabelDialog$Modle d tiquetteLabel TemplateQSLPrintLabelDialog0Largeur de l tiquette : Label Width:QSLPrintLabelDialog4tiquettes : %1 (%2 pages)Labels: %1 (%2 pages)QSLPrintLabelDialog0tiquettes : 0 (0 pages)Labels: 0 (0 pages)QSLPrintLabelDialogMarge gauche: Left Margin:QSLPrintLabelDialog(Marquer comme envoy Mark as SentQSLPrintLabelDialogbMarquer les QSO imprims/exports comme envoys ?#Mark printed/exported QSOs as sent?QSLPrintLabelDialog0Texte d en-tte du mode:Mode Header Text:QSLPrintLabelDialog"Police monospace: Mono Font:QSLPrintLabelDialogMon indicatif My CallsignQSLPrintLabelDialog<Aucun QSO correspondant trouvNo matching QSOs foundQSLPrintLabelDialog(Fichiers PDF (*.pdf)PDF Files (*.pdf)QSLPrintLabelDialogPage %1 sur %2 Page %1 of %2QSLPrintLabelDialogPage 0 sur 0 Page 0 of 0QSLPrintLabelDialogTaille de page: Page Size:QSLPrintLabelDialogImprimerPrintQSLPrintLabelDialogHImprimer les bordures des tiquettesPrint Label BordersQSLPrintLabelDialog6Imprimer les tiquettes QSLPrint QSL LabelsQSLPrintLabelDialog(Texte d en-tte QSL:QSL Header Text:QSLPrintLabelDialogQSL EnvoyeQSL SentQSLPrintLabelDialogPQSO correspondant ce profil de station"QSOs matching this station profileQSLPrintLabelDialog$QSO par tiquette:QSOs per Label:QSLPrintLabelDialog Ligne:Rows:QSLPrintLabelDialog$Police sans-serif: Sans Font:QSLPrintLabelDialog(Ignorer l tiquette: Skip Label:QSLPrintLabelDialog"Profil de stationStation ProfileQSLPrintLabelDialog6Texte d en-tte de l heure:Time Header Text:QSLPrintLabelDialog"Marge suprieure: Top Margin:QSLPrintLabelDialog$Filtre utilisateur User FilterQSLPrintLabelDialog(Espacement vertical: V Spacing:QSLPrintLabelDialog MHz MHzQSODetailDialog W WQSODetailDialog&Concours&ContestQSODetailDialog&Dtails&DetailsQSODetailDialog&Modifier&EditQSODetailDialog&Recherche&LookupQSODetailDialog&QSL&QSLQSODetailDialog&Rinitialiser&ResetQSODetailDialog&Sauvegarder&SaveQSODetailDialog--QSODetailDialog0<b>Statistiques DXCC</b>DXCC StatisticsQSODetailDialogB<b>Statistiques de la station</b>Station StatisticsQSODetailDialog&<b>Attention : </b>Warning: QSODetailDialogp<b>Oui</b> - une carte QSL entrante a t reue ; le QSO a t confirm par le service en ligne<br/><b>Non</b> - aucune carte QSL n'a t reue ; le QSO n'a pas t confirm par le service en ligne<br/><b>Demande</b> - la station a demand une carte QSL ou le tlchargement du QSO vers le service en ligne<br/>lYes - an incoming QSL card has been received; the QSO has been confirmed by the online service
No - an incoming QSL card has not been received; the QSO has not been confirmed by the online service
Requested - the logging station has requested a QSL card; the logging station has requested the QSO be uploaded to the online service
QSODetailDialog<b>Oui</b> - une carte QSL sortante a t envoye ; le QSO a t accept par le service en ligne<br/><b>Non</b> - ne pas envoyer de carte QSL ; ne pas envoyer le QSO au service en ligne<br/><b>Demande</b> - la station contacte a demand une carte QSL ou l'envoi vers le service en ligne<br/><b>En attente</b> - une carte QSL ou un envoi vers le service en ligne a t mis en file d'attente<br/>Yes - an outgoing QSL card has been sent; the QSO has been uploaded to, and accepted by, the online service
No - do not send an outgoing QSL card; do not upload the QSO to the online service
Requested - the contacted station has requested a QSL card; the contacted station has requested the QSO be uploaded to the online service
Queued - an outgoing QSL card has been selected to be sent; a QSO has been selected to be uploaded to the online service
QSODetailDialogAFAFQSODetailDialogANANQSODetailDialogASASQSODetailDialoggeAgeQSODetailDialogAntenneAntennaQSODetailDialog BandeBandQSODetailDialogbD'aprs les frquences, le mode Sat devrait tre )Based on Frequencies, Sat Mode should be QSODetailDialogD'aprs la rfrence POTA, le locator ne correspond pas au locator POTA - attendu : @Based on POTA record, Grid does not match POTA Grid - expecting QSODetailDialogD'aprs la rfrence POTA, le QTH ne correspond pas au nom POTA - attendu : ?Based on POTA record, QTH does not match POTA Name - expecting QSODetailDialogD'aprs la rfrence POTA, mon locator ne correspond pas au locator POTA - attendu : CBased on POTA record, my Grid does not match POTA Grid - expecting QSODetailDialogD'aprs la rfrence POTA, mon QTH ne correspond pas au nom POTA - attendu : BBased on POTA record, my QTH does not match POTA Name - expecting QSODetailDialogD'aprs le sommet SOTA, le locator ne correspond pas au locator SOTA - attendu : @Based on SOTA Summit, Grid does not match SOTA Grid - expecting QSODetailDialogD'aprs le sommet SOTA, le QTH ne correspond pas au nom du sommet - attendu : FBased on SOTA Summit, QTH does not match SOTA Summit Name - expecting QSODetailDialogD'aprs le sommet SOTA, mon locator ne correspond pas au locator SOTA - attendu : CBased on SOTA Summit, my Grid does not match SOTA Grid - expecting QSODetailDialogD'aprs le sommet SOTA, mon QTH ne correspond pas au nom du sommet - attendu : IBased on SOTA Summit, my QTH does not match SOTA Summit Name - expecting QSODetailDialogD'aprs l'indicatif, la zone CQ diffre de la valeur saisie - attendu : LBased on callsign, DXCC CQZ is different from the entered value - expecting QSODetailDialogD'aprs l'indicatif, le continent DXCC diffre de la valeur saisie - attendu : RBased on callsign, DXCC Continent is different from the entered value - expecting QSODetailDialogD'aprs l'indicatif, le pays DXCC diffre de la valeur saisie - attendu : PBased on callsign, DXCC Country is different from the entered value - expecting QSODetailDialogD'aprs l'indicatif, la zone ITU diffre de la valeur saisie - attendu : LBased on callsign, DXCC ITU is different from the entered value - expecting QSODetailDialogD'aprs votre indicatif, votre zone CQ diffre de la valeur saisie - attendu : TBased on own callsign, own DXCC CQZ is different from the entered value - expecting QSODetailDialogD'aprs votre indicatif, votre pays DXCC diffre de la valeur saisie - attendu : XBased on own callsign, own DXCC Country is different from the entered value - expecting QSODetailDialogD'aprs votre indicatif, votre zone ITU diffre de la valeur saisie - attendu : TBased on own callsign, own DXCC ITU is different from the entered value - expecting QSODetailDialogVideBlankQSODetailDialog BureauBureauQSODetailDialogCQCQQSODetailDialog*Erreur du callbook : Callbook error: QSODetailDialogIndicatifCallsignQSODetailDialogAnnulerCancelQSODetailDialogxImpossible de sauvegarder les modifications - erreur interne(Cannot save all changes - internal errorQSODetailDialogImpossible de sauvegarder - essayez de rinitialiser les modifications2Cannot save all changes - try to reset all changesQSODetailDialogCommentaireCommentQSODetailDialog Cont.ContQSODetailDialogID du concours Contest IDQSODetailDialogPaysCountryQSODetailDialog ComtCountyQSODetailDialogStats D&X D&X StatsQSODetailDialogDOKDOKQSODetailDialogHL'indicatif DX ne doit pas tre videDX Callsign must not be emptyQSODetailDialogJLe format du locator DX est incorrectDX Grid has an incorrect formatQSODetailDialogRLe format de l'indicatif DX est incorrect#DX callsign has an incorrect formatQSODetailDialogUne date doit tre renseigne si le statut d'envoi LoTW est <b>Oui</b>6Date should be present for LoTW Sent Status YesQSODetailDialogUne date doit tre renseigne si le statut d'envoi Papier est <b>Oui</b>7Date should be present for Paper Sent Status YesQSODetailDialogUne date doit tre renseigne si le statut d'envoi eQSL est <b>Oui</b>6Date should be present for eQSL Sent Status YesQSODetailDialog DirectDirectQSODetailDialog<Tlchargement de l'image eQSLDownloading eQSL ImageQSODetailDialog E-mailE-MailQSODetailDialogEUEUQSODetailDialogModifier le QSOEdit QSOQSODetailDialoglectronique ElectronicQSODetailDialog FISTSFISTSQSODetailDialogFISTS CCFISTS CCQSODetailDialogFrquence FrequencyQSODetailDialogLocator GridsquareQSODetailDialogIOTAIOTAQSODetailDialogITUITUQSODetailDialogIgnoreIgnoredQSODetailDialogLoTWLoTWQSODetailDialog"Le statut d'envoi LoTW sur <b>Non</b> est incohrent si une date d'envoi QSL est dfinie. Mettez la date au 01/01/1900 pour laisser le champ videLoTW Sent Status to No does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blankQSODetailDialogM&a station M&y StationQSODetailDialog$Grer la carte QSLManage QSL CardQSODetailDialogMembre :Member:QSODetailDialogModeModeQSODetailDialogMes notesMy NotesQSODetailDialogNANAQSODetailDialogNomNameQSODetailDialogNonNoQSODetailDialogOCOCQSODetailDialog0Indicatif de l'oprateurOperator CallsignQSODetailDialog$Nom de l'oprateur Operator NameQSODetailDialogJVotre indicatif ne doit pas tre videOwn Callsign must not be emptyQSODetailDialogXLe format de vos locators VUCC est incorrect'Own VUCC Grids have an incorrect formatQSODetailDialogTLe format de votre indicatif est incorrect$Own callsign has an incorrect formatQSODetailDialogPOTAPOTAQSODetailDialog PapierPaperQSODetailDialog&Le statut d'envoi Papier sur <b>Non</b> est incohrent si une date d'envoi QSL est dfinie. Mettez la date au 01/01/1900 pour laisser le champ videPaper Sent Status to No does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blankQSODetailDialogPuissancePowerQSODetailDialog&Mode de propagationPropagation ModeQSODetailDialogErreur QLog QLog ErrorQSODetailDialogQSL envoye via QSL Sent viaQSODetailDialogQSL viaQSL viaQSODetailDialogMessage QSLr QSLr MessageQSODetailDialogMessage QSLs QSLs MessageQSODetailDialogDtail du QSO QSO DetailQSODetailDialogQTHQTHQSODetailDialogEn attenteQueuedQSODetailDialogRSTrRSTrQSODetailDialogRSTsRSTsQSODetailDialog2La bande RX devrait tre RX Band should be QSODetailDialog RX : RX: QSODetailDialogchange ReuRcvExchQSODetailDialogN ReuRcvNrQSODetailDialogrVoulez-vous vraiment soumettre toutes les modifications ?Really submit all changes?QSODetailDialog ReueReceivedQSODetailDialogDemande RequestedQSODetailDialogquipementRigQSODetailDialogSASAQSODetailDialogSIGSIGQSODetailDialogInfo SIGSIG InfoQSODetailDialogSKCCSKCCQSODetailDialogSOTASOTAQSODetailDialogRLe nom du satellite ne doit pas tre videSat name must not be emptyQSODetailDialogMode satelliteSatellite ModeQSODetailDialog Nom du satelliteSatellite NameQSODetailDialogchange EnvoySendExchQSODetailDialogN EnvoySendNrQSODetailDialogEnvoyeSentQSODetailDialog*Afficher la carte QSL Show QSL CardQSODetailDialogInfo SigSig InfoQSODetailDialogtatStateQSODetailDialog6Soumettre les modificationsSubmit changesQSODetailDialog2La bande TX devrait tre TX Band should be QSODetailDialog`La frquence TX ou la bande doit tre renseigne#TX Frequency or Band must be filledQSODetailDialog TX : TX: QSODetailDialogTen-TenTen-TenQSODetailDialogHeure finTime OffQSODetailDialogHeure dbutTime OnQSODetailDialog UKSMGUKSMGQSODetailDialogURLURLQSODetailDialogVUCCVUCCQSODetailDialog8Le format VUCC est incorrectVUCC has an incorrect formatQSODetailDialogValidation ValidationQSODetailDialogWWFFWWFFQSODetailDialogLes champs marqus en jaune sont invalides.<p>Sauvegarder tout de mme les modifications ?</p>GYellow marked fields are invalid.

Nevertheless, save the changes?

QSODetailDialogOuiYesQSODetailDialogabout:blank about:blankQSODetailDialogvideblankQSODetailDialog&dd/MM/yyyy HH:mm:ssdd/MM/yyyy HH:mm:ssQSODetailDialogeQSLeQSLQSODetailDialogTchec du tlchargement de l'image eQSL : eQSL Download Image failed: QSODetailDialog"Le statut d'envoi eQSL sur <b>Non</b> est incohrent si une date d'envoi QSL est dfinie. Mettez la date au 01/01/1900 pour laisser le champ videeQSL Sent Status to No does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blankQSODetailDialogle DOK (District Location Code) DARC de la station contacte (ex. A01)Cthe contacted station's DARC DOK (District Location Code) (ex. A01)QSODetailDialogdeux ou quatre locators adjacents, de quatre caractres chacun (ex. JN18,JN19,JN28,JN29)Vtwo or four adjacent Gridsquares, each four characters long, (ex. EN98,FM08,EM97,FM07)QSODetailDialog*Ajouter une condition Add ConditionQSOFilterDetail>Toutes les conditions suivantesAll the following conditionsQSOFilterDetail<L'une des conditions suivantesAny of the following conditionsQSOFilterDetailContientContainsQSOFilterDetail gal EqualQSOFilterDetailNom du filtre : Filter Name:QSOFilterDetail>Trouver les QSO correspondant Find QSO which matchQSOFilterDetailSuprieur  Greater ThanQSOFilterDetailInfrieur  Less ThanQSOFilterDetail*Ne doit pas tre videMust not be emptyQSOFilterDetailNe contient pas Not ContainsQSOFilterDetailDiffrent de Not EqualQSOFilterDetail(Dtail du filtre QSOQSO Filter DetailQSOFilterDetailExp. RgulireRegExpQSOFilterDetailSupprimerRemoveQSOFilterDetailCommence par Starts withQSOFilterDetailAjouterAddQSOFilterDialogModifierEditQSOFilterDialogFiltresFiltersQSOFilterDialogFiltres de QSO QSO FiltersQSOFilterDialogSupprimerRemoveQSOFilterDialog8Impossible d'ouvrir le posteCannot open RigRig.Erreur d'initialisationInitialization ErrorRigErreur interneInternal ErrorRigLAucun profil de dca (Rig) slectionnNo Rig Profile selectedRigErreur Rigctld Rigctld ErrorRig MHz MHz RigWidget&Dsactiver le split Disable Split RigWidgetDconnect Disconnected RigWidgetFormulaireForm RigWidgetPWR : %1WPWR: %1W RigWidget"RIT : 0.00000 MHzRIT: 0.00000 MHz RigWidgetRXRX RigWidget"XIT : 0.00000 MHzXIT: 0.00000 MHz RigWidget6Arguments supplmentaires :Additional Arguments:RigctldAdvancedDialog*Tous les fichiers (*) All files (*)RigctldAdvancedDialogAuto-dtection Auto DetectRigctldAdvancedDialogAuto-dtection Auto-DetectRigctldAdvancedDialogDAuto-dtecter le chemin de RigctldAuto-detect Rigctld pathRigctldAdvancedDialogParcourirBrowseRigctldAdvancedDialog0Ne peut pas tre modifiCannot be changedRigctldAdvancedDialogVExcutable (*.exe);;Tous les fichiers (*.*)#Executable (*.exe);;All files (*.*)RigctldAdvancedDialogHLaisser vide pour une auto-dtectionLeave empty for auto-detectionRigctldAdvancedDialogNon trouv Not foundRigctldAdvancedDialog4Paramtres avancs RigctldRigctld Advanced SettingsRigctldAdvancedDialog Chemin Rigctld : Rigctld Path:RigctldAdvancedDialog(Version de Rigctld :Rigctld Version:RigctldAdvancedDialogBSlectionner l'excutable rigctldSelect rigctld executableRigctldAdvancedDialog:ex: -v -v pour un log verbeuxe.g. -v -v for verbose loggingRigctldAdvancedDialogrigctld n'a pas t trouv sur ce systme. Veuillez installer Hamlib ou spcifier le chemin manuellement.Yrigctld was not found on this system. Please install Hamlib or specify the path manually.RigctldAdvancedDialogJchec du dmarrage de rigctld : %1 %2Failed to start rigctld: %1 %2RigctldManager|Discordance de version majeure de Hamlib : QLog a t compil avec Hamlib %1 mais rigctld indique la version %2.%3.%4. Les ID de modles de postes sont incompatibles entre versions majeures.Hamlib major version mismatch: QLog was compiled with Hamlib %1 but rigctld reports version %2.%3.%4. Rig model IDs are incompatible between major versions.RigctldManagerLe port %1 est dj utilis. Une autre instance de rigctld ou une autre application utilise probablement ce port.VPort %1 is already in use. Another rigctld or application may be running on this port.RigctldManager>Erreur de lecture avec rigctld.Read error with rigctld.RigctldManager0Erreur rigctld inconnue.Unknown rigctld error.RigctldManager>Erreur d'criture avec rigctld.Write error with rigctld.RigctldManager"rigctld a plant.rigctld crashed.RigctldManagerL'excutable rigctld est introuvable dans /app/bin/. Cela ne devrait pas arriver avec un build Flatpak.Srigctld executable not found in /app/bin/. This should not happen in Flatpak build.RigctldManagerL'excutable rigctld est introuvable. Veuillez installer Hamlib ou spcifier le chemin dans les paramtres avancs.]rigctld executable not found. Please install Hamlib or specify the path in Advanced settings.RigctldManagerlrigctld est dmarr mais ne rpond pas sur le port %1..rigctld started but not responding on port %1.RigctldManagerJDlai d'attente dpass pour rigctld.rigctld timed out.RigctldManager8Impossible d'ouvrir le rotorCannot open RotatorRotator.Erreur d'initialisationInitialization ErrorRotatorErreur interneInternal ErrorRotatorBAucun profil de rotor slectionnNo Rotator Profile selectedRotatorAz :Az: RotatorWidgetFormulaireForm RotatorWidgetAller Goto RotatorWidget2Profil de boutons suivantNext Button Profile RotatorWidget6Profil de boutons prcdentPrevious Button Profile RotatorWidget QSO LPQSO LP RotatorWidget*QSO Grand Chemin (LP) QSO Long Path RotatorWidget QSO SPQSO SP RotatorWidget*QSO Petit Chemin (SP)QSO Short Path RotatorWidget° RotatorWidget MHz MHzSettingsDialog Profils ProfilesSettingsDialog W WSettingsDialog MPM (WPM) WPMSettingsDialog ms msSettingsDialog--SettingsDialog11SettingsDialog 115200115200SettingsDialog12001200SettingsDialog 1920019200SettingsDialog22SettingsDialog24 heures24-hourSettingsDialog24002400SettingsDialog 3840038400SettingsDialog48004800SettingsDialog55SettingsDialog 5760057600SettingsDialog66SettingsDialog77SettingsDialog88SettingsDialog96009600SettingsDialog8<DXCALL> = Indicatif du correspondant <NAME> = Prnom du correspondant <RST> = Report 599 <RSTN> = Report 5NN <GREETING> = Salutations (GM/GA/GE) <QTH> = QTH distant <MYCALL> = Mon indicatif <MYNAME> = Mon prnom <MYQTH> = Mon QTH <MYLOCATOR> = Mon localisateur (Grid) <MYGRID> = Mon localisateur (Grid) <MYSIG> = Mon SIG <MYSIGINFO> = Mes infos SIG <MYIOTA> = Mon IOTA <MYSOTA> = Mon SOTA <MYWWFT> = Mon WWFF <MYVUCC> = Mon VUCC <MYPWR> = Ma puissance (W) <EXCHSTR> = Message d'change concours <EXCHNR> = Numro de srie concours <EXCHNRN> = Numro de srie concours (9!N, 0!T) <+> = Vitesse +5 MPM (<++> = +10 MPM, etc.) <-> = Vitesse -5 MPM (<--> = -10 MPM, etc.) g = DX Callsign = DX Operator Name = Report 599 = Report 5NN = Greenting GM/GA/GE = QTH = My Callsign = My Name = My QTH = My Gridsquare = My Gridsquare = My SIG = My SIG Information = My IOTA = MY SOTA = My WWFT = MY VUCC = My Power in W = Contest Exchange Message = Contest Exchange Serial Number = Contest Exchange Serial Number (9→N, 0→T) <+> = Speed +5 WPM (<++> = +10 WPM, etc.) <-> = Speed -5 WPM (<--> = -10 WPM, etc.) SettingsDialog<a href="https://doc.qt.io/qt-6/qdate.html#fromString-1">Documentation du format d'heure</a>VTime Format DocumentationSettingsDialogh<b>Note :</b> Un abonnement QRZ XML est recommand pour accder aux informations dtailles. Sans abonnement, les donnes seront limites (localisateur ou autres champs manquants).Notice: At least a QRZ XML Subscription is recommended to access detailed information. Without a subscription, you will obtain limited data from QRZ, such as missing grid and other fields.SettingsDialog<b>Note de scurit :</b> QLog stocke les mots de passe de manire scurise. Hlas, ON4KST utilise un protocole o le mot de passe transite en clair sur un canal non scuris.</p><p>Soyez prudent lors du choix de votre mot de passe pour ce service.</p>HSecurity Notice: QLog stores all passwords in the Secure Storage. Unfortunately, ON4KST uses a protocol where this password is sent over an unsecured channel as plaintext.

Please exercise caution when choosing your password for this service, as your password is sent over an unsecured channel in plaintext form.

SettingsDialog\<b>& Ceci est une zone dangereuse. Procdez avec prudence, car les actions effectues ne peuvent pas tre annules et peuvent avoir un impact important sur votre journal.</b>⚠ This is a danger zone. Proceed with caution, as actions performed here cannot be undone and may have a significant impact on your log.SettingsDialogz<p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP lors de l'ajout/modification/suppression d'un QSO.</p>Les adresses sont spares par des espaces (format IP:PORT).

List of IP addresses to which QLog sends UDP notification packets about a new/updated/deleted QSO in the log.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialogb<p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP pour les alertes de spots utilisateur.</p>Les adresses sont spares par des espaces (format IP:PORT).

List of IP addresses to which QLog sends UDP notification packets about user Spot Alerts.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialogF<p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP des spots du cluster DX.</p>Les adresses sont spares par des espaces (format IP:PORT).

List of IP addresses to which QLog sends UDP notification packets with DX Cluster Spots.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialogD<p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP des spots CQ de WSJT-X.</p>Les adresses sont spares par des espaces (format IP:PORT).

List of IP addresses to which QLog sends UDP notification packets with WSJTX CQ Spots.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialog`<p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP lors d'un changement d'tat du poste.</p>Les adresses sont spares par des espaces (format IP:PORT).

List of IP addresses to which QLog sends UDP notification packets when Rig State changes.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialogv<p>LogID assign au carnet actuel.</p>Le LogID est envoy dans les notifications rseau comme identifiant unique d'instance.<p>L'ID est gnr automatiquement et ne peut tre modifi.</p>

Assigned LogID to the current log.

The LogID is sent in the Network Nofitication messages as a unique instance identified.

The ID is generated automatically and cannot be changedSettingsDialog.<p>Liste des adresses IP vers lesquelles QLog redirige les paquets UDP bruts de WSJT-X.</p>Les adresses sont spares par des espaces (format IP:PORT).

List of IP addresses to which QLog forwards raw UDP WSJT-X packets.

The IP addresses are separated by a space and have the form IP:PORTSettingsDialog AM/PMAM/PMSettingsDialogCl APIAPI KeySettingsDialogListes actives Active ListsSettingsDialogAjouterAddSettingsDialogAvanc... Advanced...SettingsDialogPTous les mots de passe ont t supprimsAll passwords have been deletedSettingsDialogAntennesAntennasSettingsDialog.Manipulateur CW assignAssigned CW KeyerSettingsDialogAutoAutoSettingsDialogAuto-dtection Auto DetectSettingsDialogAuto-dtection Auto-DetectSettingsDialog:Auto-dtection du chemin TQSLAuto-detect TQSL pathSettingsDialog:Largeur de faisceau azimutal Azimuth Beamwidth SettingsDialogOffset azimutalAzimuth OffsetSettingsDialog BandesBandsSettingsDialogVitesse (Bauds)BaudrateSettingsDialogVideBlankSettingsDialogParcourirBrowseSettingsDialogBouton 1Button 1SettingsDialogBouton 2Button 2SettingsDialogBouton 3Button 3SettingsDialogBouton 4Button 4SettingsDialogAdresse CI-VCIV AddrSettingsDialogZone CQCQZSettingsDialog.Vitesse manipulateur CWCW Keyer SpeedSettingsDialog0Cls tlgraphiques (CW) CW KeyersSettingsDialog0Profils de raccourcis CWCW Shortcut ProfilesSettingsDialog$Synchro vitesse CW CW Speed SyncSettingsDialogCWDaemonCWDaemonSettingsDialog.Nomenclature (Callbook)CallbookSettingsDialogIndicatifCallsignSettingsDialogBIndicatif (paramtre obligatoire)Callsign (Mandatory parameter)SettingsDialogIndicatif de l'oprateur (optionnel, si diffrent de celui de la station)MCallsign of operator (Optional parameter, if different from station callsign)SettingsDialog,Cls API par indicatifCallsign-specific API KeysSettingsDialog0Ne peut pas tre modifiCannot be changedSettingsDialogChatChatSettingsDialogClubLogClubLogSettingsDialog ClubsClubsSettingsDialog(Colorer les spots CQColor CQ SpotsSettingsDialogPaysCountrySettingsDialog ComtCountySettingsDialogPersonnalisCustomSettingsDialogDOKDOKSettingsDialogDTRDTRSettingsDialogSpots DXDX SpotsSettingsDialog,Spots DX vers le posteDX Spots to RigSettingsDialogDXCCDXCCSettingsDialogZone dangereuse Danger ZoneSettingsDialogBits de donnes Data BitsSettingsDialogFormat de date Date FormatSettingsDialog$Cl API par dfautDefault API KeySettingsDialog$Puissance par df. Default PWRSettingsDialog$Vitesse par dfaut Default SpeedSettingsDialogSupprimerDeleteSettingsDialogfSupprimer tous les mots de passe du coffre scuris*Delete All Passwords from the Secure StoreSettingsDialog.Supprimer tous les QSOsDelete All QSOsSettingsDialog6Supprimer les mots de passeDelete PasswordsSettingsDialog>Suppression de tous les QSOs...Deleting all QSOs...SettingsDialogDescription DescriptionSettingsDialogDsactivDisabledSettingsDialogDummy (fictif)DummySettingsDialog E-MailE-MailSettingsDialogbActiver/Dsactiver l'option Multicast pour WSJT-X)Enable/Disable Multicast option for WSJTXSettingsDialogActiver/Dsactiver l'envoi d'indicateurs d'tat colors WSJT-X pour chaque indicatif appelant CQ`Enable/Disable sending color-coded status indicators back to WSJT-X for each callsign calling CQSettingsDialogFin (MHz) End (MHz)SettingsDialog0Point d'accs (Endpoint)EndpointSettingsDialogpEntrer la puissance par dfaut (ex: si poste dconnect)0Enter default PWR (ex. when Rig is disconnected)SettingsDialog^Entrer manuellement l'offset RIT ou Transverter(Enter manually RIT or Transverter OffsetSettingsDialog^Entrer manuellement l'offset XIT ou Transverter(Enter manually XIT or Transverter offsetSettingsDialogquipement EquipmentSettingsDialog ErreurErrorSettingsDialogPairEvenSettingsDialogF1F1SettingsDialogF2F2SettingsDialogF3F3SettingsDialogF4F4SettingsDialogF5F5SettingsDialogF6F6SettingsDialogF7F7SettingsDialog FLDigiFLDigiSettingsDialogLImpossible de supprimer tous les QSOs.Failed to delete all QSOs.SettingsDialog Contrle de flux Flow ControlSettingsDialog Frq.FreqSettingsDialogInterface (GUI)GUISettingsDialogLocator GridsquareSettingsDialog HRDLogHRDLogSettingsDialognHamLib ne permet pas de changer le port de destination.5HamLib does not support to change a destination port.SettingsDialog HamQTHHamQTHSettingsDialogMatriel (Hard)HardwareSettingsDialogHaut (High)HighSettingsDialogNom d'hte Host NameSettingsDialogIAMBIC AIAMBIC ASettingsDialogIAMBIC BIAMBIC BSettingsDialogIOTAIOTASettingsDialog4IOTA (paramtre optionnel)IOTA (Optional parameter)SettingsDialogZone ITUITUSettingsDialogSi activ et le poste connect, QLog envoie priodiquement des messages "On-Air" HRDLog\If it is enabled and Rig is connected then QLog periodically sends On-Air messages to HRDLogSettingsDialogEnvoi immdiatImmediately UploadSettingsDialogImprialImperialSettingsDialogInterface InterfaceSettingsDialogCe n'est pas un mot de passe. C'est le code d'envoi reu par email aprs l'inscription sur HRDLOG.netdIt is not a password. It is the upload code received via email after the registration to HRDLOG..netSettingsDialog,Rejoindre le MulticastJoin MulticastSettingsDialog(Mode du manipulateur Keyer ModeSettingsDialog.Profils de manipulateurKeyer ProfilesSettingsDialogDLaisser vide pour l'auto-dtectionLeave empty for auto-detectionSettingsDialogPListe de toutes les antennes disponiblesList of all available AntennasSettingsDialog\Liste de tous les manipulateurs CW disponiblesList of all available CW KeyersSettingsDialoglListe de tous les profils de raccourcis CW disponibles+List of all available CW Shortcuts ProfilesSettingsDialogTListe de tous les transceivers disponiblesList of all available RigsSettingsDialog`Liste de tous les profils de station disponibles&List of all available Station ProfilesSettingsDialogLoTWLoTWSettingsDialog LogIDLogIDSettingsDialogBas (Low)LowSettingsDialogMarkMarkSettingsDialogMtriqueMetricSettingsDialogFrquences TX mini et maxi. Les plages spcifiques sont drives des bandes autorises dans les paramtres.aMinimum and maximum TX frequencies. Specific ranges are derived from allowed Band in the Setting.SettingsDialogModeModeSettingsDialog ModleModelSettingsDialog ModesModesSettingsDialogModifierModifySettingsDialogMorse via CATMorse Over CATSettingsDialog"Adresse MulticastMulticast AddressSettingsDialog*Ne doit pas tre videMust not be emptySettingsDialogN/DN/ASettingsDialogNomNameSettingsDialog RseauNetworkSettingsDialogNonNoSettingsDialog AucunNoneSettingsDialogNon trouv Not foundSettingsDialogNotifications NotificationsSettingsDialog ImpairOddSettingsDialogOffsetsOffsetsSettingsDialog0Indicatif de l'oprateurOperator CallsignSettingsDialog$Nom de l'oprateur Operator NameSettingsDialogPNom de l'oprateur (paramtre optionnel)"Operator name (Optional parameter)SettingsDialog AutresOthersSettingsDialogPOTAPOTASettingsDialogPort PTTPTT PortSettingsDialogtat du PTT PTT StateSettingsDialogType de PTTPTT TypeSettingsDialog<Sidetone (palettes uniquement)Paddle Only SidetoneSettingsDialog PapierPaperSettingsDialog ParitParitySettingsDialogMot de passePasswordSettingsDialog4Intervalle d'interrogation Poll IntervalSettingsDialogPortPortSettingsDialog Port Port SettingsDialogType de port Port TypeSettingsDialogrPort sur lequel QLog coute le trafic provenant de WSJT-X7Port where QLog listens an incoming traffic from WSJT-XSettingsDialogPuissancePowerSettingsDialogAppuyez sur <b>Modifier</b> pour confirmer les changements de profil ou sur <b>Annuler</b>.DPress Modify to confirm the profile changes or Cancel.SettingsDialogPrimairePrimarySettingsDialogNom du profil Profile NameSettingsDialogNom du profil utilis comme alias pour l'indicatif, le localisateur, l'oprateur et le QTH (obligatoire) qProfile name that is used as the alias for the Callsign, Gridsquare, Operator name, and QTH (required parameter) SettingsDialogProfilsProfilesSettingsDialogQRZ.comQRZ.comSettingsDialog*Modifications de QSO  QSO Changes SettingsDialogFLes QSOs sont envoys immdiatementQSOs are uploaded immediatelySettingsDialog$Effacement sur QSY QSY WipingSettingsDialogQTHQTHSettingsDialog@Nom du QTH (paramtre optionnel)QTH Name (Optional parameter)SettingsDialog Ordre de requte Query OrderSettingsDialogRTSRTSSettingsDialogOffset RX (RIT)RX Offset (RIT)SettingsDialog RX : RX: SettingsDialog*Redirection UDP bruteRaw UDP ForwardSettingsDialog ReportReportSettingsDialogpConnexion internet requise au dmarrage de l'application5Required internet connection during application startSettingsDialog0Fonctionnalits du poste Rig FeaturesSettingsDialogPort du posteRig PortSettingsDialogtat du poste Rig StatusSettingsDialogLe partage du poste n'est pas disponible pour les connexions rseau3Rig sharing is not available for network connectionSettingsDialogzLe partage du poste n'est disponible qu'avec le pilote Hamlib/Rig sharing is only available for Hamlib driverSettingsDialogTransceiversRigsSettingsDialog RotorsRotatorsSettingsDialogMode SATSAT ModeSettingsDialogSIGSIGSettingsDialog4SIG (paramtre optionnel).SIG (Optional parameter).SettingsDialogInfo SIGSIG InfoSettingsDialogJInformation SIG (paramtre optionnel)$SIG Information (Optional parameter)SettingsDialogSOTASOTASettingsDialog4SOTA (paramtre optionnel)SOTA (Optional parameter)SettingsDialogSecondaire SecondarySettingsDialog.Slectionner un fichier Select FileSettingsDialog Envoyer "On-Air" Send On-AirSettingsDialog SrieSerialSettingsDialogParamtresSettingsSettingsDialog:Partager le poste via le portShare Rig via portSettingsDialogRDescription courte du bouton (7 car. max).Short Desciption of the Button (up to 7 chars)SettingsDialog Frq. sidetone :Sidetone Freq:SettingsDialogSimple palette Single PaddleSettingsDialogLogiciel (Soft)SoftwareSettingsDialog SpaceSpaceSettingsDialog"Spcial - OmnirigSpecial - OmnirigSettingsDialog8Spcifier l'adresse Multicast. <br>Sur certains systmes Linux, il peut tre ncessaire d'activer le multicast sur l'interface de boucle locale (loop-back).Specify Multicast Address.
On some Linux systems it may be necessary to enable multicast on the loop-back network interface.SettingsDialogSpcifier l'URL pour la recherche rapide. La macro <DXCALL> sera remplace par l'indicatif courantdSpecify the URL to use for quick search. The macro will be replaced by the current callsignSettingsDialog Alertes de spots Spot AlertsSettingsDialogDbut (MHz) Start (MHz)SettingsDialogLancer le dmon rigctld pour partager le poste avec d'autres applis (ex: WSJT-X)GStart rigctld daemon to share rig with other applications (e.g. WSJT-X)SettingsDialogtat / ProvinceStateSettingsDialogStationStationSettingsDialog.Indicatif de la stationStation CallsignSettingsDialogVLocalisation du comt (paramtre optionnel),Station County Location (Optional parameter)SettingsDialogPLocalisateur de la station (obligatoire)(Station Gridsquare (Mandatory parameter)SettingsDialog&Statut confirm parStatus Confirmed BySettingsDialogBits d'arrt Stop BitsSettingsDialog*Inverser les palettes Swap PaddlesSettingsDialogSync && QSL Sync && QSLSettingsDialogSystmeSystemSettingsDialogChemin TQSL TQSL PathSettingsDialogVersion de TQSL TQSL VersionSettingsDialogTQSL n'a pas t trouv sur ce systme. Veuillez installer TQSL ou spcifier le chemin manuellement.TTQSL was not found on this system. Please install TQSL or specify the path manually.SettingsDialogTTLTTLSettingsDialogOffset TX (XIT)TX Offset (XIT)SettingsDialogPlage TXTX RangeSettingsDialog TX : TX: SettingsDialogTestTestSettingsDialogBTester l'URL avec votre indicatifTest URL with your CallsignSettingsDialog<Le caractre '>' sert de marqueur pour la position initiale du curseur dans la colonne Report. <br/>Ex: '5>9' positionnera le curseur sur le second caractre.The '>' character is interpreted as a marker for the initial cursor position in the Report column.
Ex.: '5>9' means the cursor will be positioned on the second characterSettingsDialogFormat d'heure Time FormatSettingsDialogLe TTL (Time-To-Live) dtermine la porte de propagation<br> d'un paquet multicast sur votre intranet. dTime-To-Live determines the range
over which a multicast packet is propagated in your intranet. SettingsDialogURLURLSettingsDialogUltimaticeUltimateSettingsDialog Systme d'units Unit SystemSettingsDialogNon spcifi UnspecifiedSettingsDialogCode d'envoi Upload CodeSettingsDialogUtiliser COMxx pour Windows ou le chemin vers le port sous Linux/Unix;Use COMxx for Window or path to COM port under Unix-like OSSettingsDialog<Profils de boutons utilisateurUser Buttons ProfilesSettingsDialogUtilisateurUsernameSettingsDialogDUtiliser une instance TQSL interneUsing an internal TQSL instanceSettingsDialogVFOVFOSettingsDialogVUCCVUCCSettingsDialogVCarrs VUCC (optionnel). Ex: JN18,JN19,IN989VUCC Grids (Optional parameter). Ex. EN98,FM08,EM97,FM07SettingsDialogbLa plage valide est 0 - 100 (0 = non spcifi)2Valid range value is 0° - 100° (0° Unspecified)SettingsDialogWWFFWWFFSettingsDialogWavelogWavelogSettingsDialog.Bouton de recherche WebWeb Lookup ButtonSettingsDialog WinKeyWinKeySettingsDialog4WWFF (paramtre optionnel)-World Wide Flora & Fauna (Optional parameter)SettingsDialog WSJT-XWsjtxSettingsDialogSpots CQ WSJT-XWsjtx CQ SpotsSettingsDialogeQSLeQSLSettingsDialogJex: 192.168.1.1:1234 192.168.2.1:1234%ex. 192.168.1.1:1234 192.168.2.1:1234SettingsDialogmembresmembersSettingsDialog°SettingsDialogBConflit avec un raccourci intgr!Conflict with a built-in shortcutShortcutEditorModelJConflit avec un raccourci utilisateur%Conflict with a user-defined shortcutShortcutEditorModelDescription DescriptionShortcutEditorModelRaccourciShortcutShortcutEditorModelQSO envoyerQSOs to UploadShowUploadDialogQSO slectionn Selected QSOShowUploadDialogEnvoyerUploadShowUploadDialogRechercherSearchSmartSearchBoxToutAllStatisticsWidget BandeBandStatisticsWidget*Grands carrs LocatorBig GridsquaresStatisticsWidgetConfirm  Confirmed StatisticsWidget.Confirm / Non confirmConfirmed / Not ConfirmedStatisticsWidgetConfirm par Confirmed byStatisticsWidget8Locators confirms/contactsConfirmed/Worked GridsStatisticsWidgetContinent ContinentStatisticsWidgetPays CountriesStatisticsWidgetPlage de dates Date RangeStatisticsWidget$Jour de la semaine Day in WeekStatisticsWidgetDistanceDistanceStatisticsWidgetVenFriStatisticsWidget"Type de graphique Graph TypeStatisticsWidgetHistogramme HistogramStatisticsWidget HeureHourStatisticsWidgetLoTWLoTWStatisticsWidgetModeModeStatisticsWidgetLunMonStatisticsWidgetMoisMonthStatisticsWidgetMon antenne My AntennaStatisticsWidgetMon indicatif My CallsignStatisticsWidgetMon locator My GridsquareStatisticsWidgetMa stationMy RigStatisticsWidget0Aucun filtre utilisateurNo User FilterStatisticsWidgetNon confirm Not Confirmed StatisticsWidgetNon spcifi Not specifiedStatisticsWidgetODXODXStatisticsWidgetDPlus de 50 000 QSO. Les afficher ?Over 50000 QSOs. Display them?StatisticsWidget PapierPaperStatisticsWidgetPourcentagesPercentsStatisticsWidget&Mode de propagationPropagation ModeStatisticsWidgetQSOQSOsStatisticsWidgetQSO parQSOs perStatisticsWidget*Gnration des QSO...Rendering QSOs...StatisticsWidgetSamSatStatisticsWidget*Afficher sur la carte Show on MapStatisticsWidgetStatistiques StatisticsStatisticsWidgetDimSunStatisticsWidgetJeuThuStatisticsWidget Top 10Top 10StatisticsWidgetMarTueStatisticsWidget$Filtre utilisateur User FilterStatisticsWidgetMerWedStatisticsWidget AnneYearStatisticsWidgeteQSLeQSLStatisticsWidgetautoStatisticsWidget.Une erreur est survenueError Occurred TCIRigDrvPoste 0Rig 0 TCIRigDrvPoste 1Rig 1 TCIRigDrvPoste 2Rig 2 TCIRigDrvPoste 3Rig 3 TCIRigDrv6Le poste n'est pas connectRig is not connected TCIRigDrv6Le statut du poste a changRig status changed TCIRigDrvVideBlankTimestampFormatDelegateMessageMessageToAllTableModelSpotterSpotterToAllTableModel HeureTimeToAllTableModel&Envoyer&UploadUploadQSODialogTousAnyUploadQSODialogIndicatifCallsignUploadQSODialogAnnulerCancelUploadQSODialogXImpossible de mettre jour le statut du QSOCannot update QSO StatusUploadQSODialogBImpossible d'envoyer le(s) QSO : Cannot upload the QSO(s): UploadQSODialogBVider Clublog et renvoyer les QSOClear Clublog and reupload QSOsUploadQSODialogClublogClublogUploadQSODialogCommentaireCommentUploadQSODialogFiltresFiltersUploadQSODialogLocator GridsquareUploadQSODialog HRDLogHRDLogUploadQSODialog$Masquer les QSO... Hide QSOs...UploadQSODialogIgnorerIgnoreUploadQSODialog2Inclure le statut des QSOInclude QSOs StatusUploadQSODialogLoTWLoTWUploadQSODialogLoTW / TQSL LoTW / TQSLUploadQSODialogL'indicatif de l'emplacement (%1) et le locator (%2) ne correspondent pas aux filtres slectionnsBLocation callsign (%1) and grid (%2) do not match selected filtersUploadQSODialogL'indicatif de l'emplacement (%1) ne correspond pas l'indicatif slectionn (%2) Veuillez utiliser la bote de dialogue <b>Paramtres</b> pour le configurer.</p>^Service is not configured properly.

Please, use Settings dialog to configure it.

UploadQSODialog&Afficher les QSO... Show QSOs...UploadQSODialog"Profil de stationStation ProfileUploadQSODialog.ID du profil de stationStation Profile IDUploadQSODialog<Emplacement de la station TQSLTQSL Station LocationUploadQSODialogLes valeurs ci-dessous seront utilises lorsqu'un enregistrement ne contient pas les valeurs ADIFSThe values below will be used when an input record does not contain the ADIF valuesUploadQSODialogCette option supprime tous les QSO sur Clublog<br>et, selon le filtre, renvoie tous les QSO quel que soit leur statut.sThis option deletes all QSOs in the Clublog
and based on filter, it uploads all QSOs regardless of their status.UploadQSODialog HeureTimeUploadQSODialog,En temps normal, ce statut signifie <b>"Ignorer/Invalide"</b>.<br/>Toutefois, il peut tre souhaitable d'ignorer ce rglage lors de l'envoi d'une QSL.Under normal circumstances this status means "Ignore/Invalid".
However, it may sometimes be wanted to ignore this setting when sending a QSL.UploadQSODialog(En temps normal, ce statut signifie <b>"ne pas envoyer"</b>.<br/>Toutefois, il peut tre souhaitable d'ignorer ce rglage lors de l'envoi d'une QSL.Under normal circumstances this status means "do not send".
However, it may sometimes be wanted to ignore this setting when sending a QSL.UploadQSODialogInconnuUnknownUploadQSODialogNon spcifi UnspecifiedUploadQSODialogEnvoyer les QSO Upload QSOsUploadQSODialogEnvoyer vers Upload toUploadQSODialogEnvoi vers %1Uploading to %1UploadQSODialogWavelogWavelogUploadQSODialogeQSLeQSLUploadQSODialog AzimutAzimuth UserListModelIndicatifCallsign UserListModelCommentaireComment UserListModelDistanceDistance UserListModelLocator Gridsquare UserListModelAA WCYTableModelAuAu WCYTableModelGMFGMF WCYTableModelKK WCYTableModelRR WCYTableModelSASA WCYTableModelSFISFI WCYTableModel HeureTime WCYTableModelexpKexpK WCYTableModelAA WWVTableModelInfoInfo WWVTableModelKK WWVTableModelSFISFI WWVTableModel HeureTime WWVTableModel dB dBWsjtxFilterDialogAfriqueAfricaWsjtxFilterDialogAntarctique AntarcticaWsjtxFilterDialogAsieAsiaWsjtxFilterDialogConfirm ConfirmedWsjtxFilterDialogContinent ContinentWsjtxFilterDialog*Distance suprieure Distance more thanWsjtxFilterDialog EuropeEuropeWsjtxFilterDialogFiltres tendusExtended FiltersWsjtxFilterDialog Filtres gnrauxGeneral FiltersWsjtxFilterDialogStatut du log Log StatusWsjtxFilterDialog MembreMemberWsjtxFilterDialogNouvelle bandeNew BandWsjtxFilterDialog,Nouvelle entit (DXCC) New EntityWsjtxFilterDialogNouveau modeNew ModeWsjtxFilterDialog2Nouveau slot (bande/mode)New SlotWsjtxFilterDialogDAucune liste de club n'est activeNo Club List is enabledWsjtxFilterDialog Amrique du Nord North AmericaWsjtxFilterDialogOcanieOceaniaWsjtxFilterDialog SNR meilleur queSNR better thanWsjtxFilterDialogAmrique du Sud South AmericaWsjtxFilterDialogFiltres WSJTX WSJTX FiltersWsjtxFilterDialogContactWorkedWsjtxFilterDialogIndicatifCallsignWsjtxTableModelDistanceDistanceWsjtxTableModelLocator GridsquareWsjtxTableModel"Dernire activit Last ActivityWsjtxTableModelDernier message Last MessageWsjtxTableModel MembreMemberWsjtxTableModelSNRSNRWsjtxTableModel4Visibilit des colonnes...Column Visibility... WsjtxWidget"Filtrer les spots Filter Spots WsjtxWidgetFiltrer... Filter... WsjtxWidget FiltrFiltered WsjtxWidgetFormulaireForm WsjtxWidgetNQuelles colonnes doivent tre affiches!Which columns should be displayed WsjtxWidgetzForcer la mise jour de toutes les listes (DXCC, SATs, etc.)2Force update of all value lists (DXCC, SATs, etc.)mainTraiter l'importation de base de donnes en attente (usage interne).Process pending database import (internal use)mainlExcuter avec l'espace de noms (namespace) spcifique. Run with the specific namespace.mainDfinir la langue. <code> exemple : 'en' ou 'en_US'. Ignore les paramtres d'environnement.JSet language. example: 'en' or 'en_US'. Ignore environment setting.mainFichier de traduction - chemin absolu ou relatif et nom du fichier QM.>Translation file - absolute or relative path and QM file name.mainncrit les messages de dbogage dans le fichier de debug'Writes debug messages to the debug filemaincodecodemainespace de noms namespacemain0chemin/nom-du-fichier-QMpath/QM-filenamemainfoldynl-QLog-3252ff9/i18n/qlog_fr.ts000066400000000000000000021063641517334601000171570ustar00rootroot00000000000000 ActivityEditor Activity Editor Éditeur d'activité Activity Name Nom de l'activité Layout Mise en page Window Arrangement: Agencement des fenêtres : Saved Enregistré Clear Effacer Available Fields Champs disponibles List of fields that can be used Liste des champs utilisables Row A Ligne A Move selected fields from the Available Fields List to the Row A Déplacer les champs sélectionnés vers la Ligne A Remove selected field from the Row A Retirer le champ sélectionné de la Ligne A List of fields in the first variable row Liste des champs de la première ligne variable Change the order. Move selected field up Changer l'ordre. Monter le champ sélectionné Change the order. Move selected field down Changer l'ordre. Descendre le champ sélectionné Row B Ligne B Move selected fields from the Available Fields List to the Row B Déplacer les champs sélectionnés vers la Ligne B Remove selected field from the Row B Retirer le champ sélectionné de la Ligne B List of fields in the second variable row Liste des champs de la seconde ligne variable Column A Colonne A List of fields in the first QSO Detail Column Liste des champs de la première colonne de détail QSO Column B Colonne B List of fields in the second QSO Detail Column Liste des champs de la seconde colonne de détail QSO Column C Colonne C List of fields in the third QSO Detail Column Liste des champs de la troisième colonne de détail QSO New QSO Rows Lignes du nouveau QSO New QSO Detail Columns Colonnes de détail du nouveau QSO Values Valeurs Profiles Profils If unchecked, the profile does not change Si décoché, le profil ne change pas Station Station Antenna Antenne Rig Poste/Transceiver Connect automatically Connexion automatique Connect Connecter Rotator Rotor/Pointeur Fields Champs Must not be empty Ne doit pas être vide Unsaved Non enregistré AlertRuleDetail Alert Rule Detail Détail de la règle d'alerte Rule Name Nom de la règle Enabled Activé Sources Sources DX Cluster Cluster DX WSJTX WSJT-X DX DX Log Status Statut du Log Worked Contacté New Slot Nouveau créneau (Slot) Confirmed Confirmé New Entity Nouvelle Entité (DXCC) New Mode Nouveau Mode New Band Nouvelle Bande All Tous DX Callsign Indicatif DX Use Perl-like regular expression Utiliser une expression régulière (Perl) .* .* Country Pays ITU Zone ITU CQZ Zone CQ Spot Comment Commentaire du Spot Special Programs Diplômes & Programmes IOTA IOTA SOTA SOTA POTA POTA WWFF WWFF Modes Modes FTx (FT8/FT4) FTx (FT8/FT4) Digital Numérique Phone Phonie CW CW Bands Bandes Continent Continent South America Amérique du Sud Antarctica Antarctique North America Amérique du Nord Oceania Océanie Asia Asie Europe Europe Africa Afrique Member Membre de club Spotter Spotter (celui qui annonce) Must not be empty Ne doit pas être vide No Club List is enabled Aucune liste de club n'est activée AlertSettingDialog Alerts Rules Règles d'alertes Rules Règles Add Ajouter Edit Modifier Remove Supprimer Name Nom State État AlertTableModel Rule Name Nom de la règle Callsign Indicatif Frequency Fréquence Mode Mode Updated Mis à jour Last Update Dernière MAJ Last Comment Dernier commentaire Member Membre AlertWidget Alerts Alertes Clear older than Effacer plus ancien que Never Jamais min(s) min(s) Edit Rules Modifier les règles Column Visibility... Visibilité des colonnes... Clear Effacer AwardsDialog Awards Diplômes Options Options Award Diplôme My DXCC Entity Mon entité DXCC User Filter Filtre utilisateur Confirmed by Confirmé par LoTW LoTW eQSL eQSL Paper Papier (QSL) Mode Mode CW CW Phone Phonie Digi Numérique Show Afficher Not-Worked Only Non contactés seulement Not-Confirmed Only Non confirmés seulement DXCC DXCC ITU Zones ITU WAC WAC WAZ WAZ WAS WAS WPX WPX IOTA IOTA POTA Hunter Chasseur POTA POTA Activator Activateur POTA SOTA SOTA WWFF WWFF Gridsquare 2-Chars Locator (2 car.) Gridsquare 4-Chars Locator (4 car.) Gridsquare 6-Chars Locator (6 car.) Gridsquare %1-Chars Locator (%1 car.) US Counties Comtés US Russian Districts Districts russes (RDA) Japanese Cities/Ku/Guns Villes/Ku/Guns japonais (JCC/JCG) NZ Counties Comtés NZ Spanish DMEs DME espagnols Ukrainian Districts Districts ukrainiens (URDA) No User Filter Aucun filtre utilisateur DELETED SUPPRIMÉ North America Amérique du Nord South America Amérique du Sud Europe Europe Africa Afrique Oceania Océanie Asia Asie Antarctica Antarctique AwardsTableModel Slots: Slots : Confirmed Confirmé Worked Contacté Still Waiting En attente BandmapWidget Form Formulaire Create an additional Bandmap Window Créer une fenêtre Bandmap supplémentaire Clear older Effacer plus anciens Never Jamais min(s) min(s) Clear All Tout effacer Clear the current band Effacer la bande actuelle Bandmap Bandmap Show Band Afficher la bande Center RX Centrer sur RX Show Emergency Frequencies Montrer les fréquences d'urgence SOS SOS CWCatKey No Rig is connected Aucun poste connecté Rig does not support Morse over CAT Le poste ne supporte pas la CW via CAT Cannot send Text to Rig Impossible d'envoyer du texte au poste Keyer is not connected Le manipulateur (keyer) n'est pas connecté Rig is not connected Le poste n'est pas connecté Cannot set Keyer Speed Impossible de régler la vitesse du manipulateur Cannot stop Text Sending Impossible d'arrêter l'envoi du texte CWConsoleWidget Form Formulaire CW Keyer Profile Profil de manipulateur CW Shortcuts profile Profil de raccourcis Speed Vitesse N/A N/D WPM WPM (mots/min) Sent text Texte envoyé Echoed text Texte en écho &CW &CW Text to send Texte à envoyer Switch between sending <b>words</b> individually (separated by spaces)<br> and sending the entire text as a <b>whole</b> (separated by a new line). Alterner entre l'envoi par <b>mots</b> individuels (séparés par des espaces)<br> et l'envoi du texte <b>complet</b> (séparé par un saut de ligne). F1 F1 F2 F2 F3 F3 F4 F4 F5 F5 F6 F6 F7 F7 Immediately stop CW sending Arrêt immédiat de l'émission CW Halt Stop Clear Sent and Echo Console Effacer la console d'envoi et d'écho Clear Effacer CW Console - Halt Sending Console CW - Arrêt d'émission Rig must be connected Le poste doit être connecté Word Mot Whole Complet CWDaemonKey Keyer is not connected Le manipulateur n'est pas connecté Cannot send Text Impossible d'envoyer le texte Cannot set Keyer Speed Impossible de régler la vitesse Cannot stop Text Sending Impossible d'arrêter l'émission CWFldigiKey Connected device is not FLDigi L'appareil connecté n'est pas FLDigi Keyer is not connected Le manipulateur n'est pas connecté Cannot send Text to FLDigi Impossible d'envoyer le texte à FLDigi Cannot send the Clear command to FLDigi Impossible d'envoyer la commande Clear à FLDigi Cannot send the TX command to FLDigi Impossible d'envoyer la commande TX à FLDigi Cannot send the Text command to FLDigi Impossible d'envoyer la commande Text à FLDigi Cannot send the Stop command to FLDigi Impossible d'envoyer la commande Stop à FLDigi Cannot send the Abort command to FLDigi Impossible d'envoyer la commande Abort à FLDigi Cannot receive data from FLDigi Impossible de recevoir des données de FLDigi FLDigi connection timeout Délai de connexion à FLDigi dépassé FLDigi connection error Erreur de connexion à FLDigi FLDigi command error Erreur de commande FLDigi CWKeyer No CW Keyer Profile selected Aucun profil de manipulateur CW sélectionné Initialization Error Erreur d'initialisation Internal Error Erreur interne Connection Error Erreur de connexion Cannot open the Keyer connection Impossible d'ouvrir la connexion au manipulateur CWWinKey Connected device is not WinKey L'appareil connecté n'est pas un WinKey Cannot send Text to Rig Impossible d'envoyer le texte au poste Keyer is not connected Le manipulateur n'est pas connecté Communication Error Erreur de communication Cannot set Keyer Speed Impossible de régler la vitesse Cannot stop Text Sending Impossible d'arrêter l'émission 4000 Hz 4000 Hz 2000 Hz 2000 Hz 1333 Hz 1333 Hz 1000 Hz 1000 Hz 800 Hz 800 Hz 666 Hz 666 Hz 571 Hz 571 Hz 500 Hz 500 Hz 444 Hz 444 Hz 400 Hz 400 Hz CabrilloExportDialog Cabrillo Export Exporter Cabrillo File: Fichier : Browse Parcourir Contest Concours (Contest) Format Template: Modèle de format : Manage Gérer User Filter: Filtre utilisateur : Date/Time: Date/Heure: yyyy-MM-dd HH:mm - - UTC Station & Categories Station et catégories Callsign: Indicatif: Operators: Opérateurs : Band: Bande: Mode: Mode: Power: Puissance: Operator: Opérateur: Assisted: Assisté : Station: Station: Transmitter: Émetteur: Time: Heure: Overlay: Transmitter ID: Additional Supplémentaire Name: Nom: Email: Email: Address: Adresse: Max 6 lines Max. 6 lignes Gridsquare Locator Location: Emplacement: Club: Club: Soapbox: Commentaire libre: Off-Time: yyyy-mm-dd hhmm yyyy-mm-dd hhmm &Export &Exporter Cabrillo Files (*.log);;CBR Files (*.cbr);;All Files (*) Fichiers Cabrillo (*.log);;Fichiers CBR (*.cbr);;Tous les fichiers (*) QSO(s): %1 QSO(s) : %1 QSOs: ? QSOs: ? QLog Warning Avertissement QLog Please select a contest template. Veuillez sélectionner un modèle de concours. Please select an output file. Veuillez sélectionner un fichier de sortie. No callsign available. Check your filters. Aucun indicatif disponible. Vérifiez vos filtres. QLog Error Erreur QLog Failed to prepare export query. Impossible de préparer la requête d’exportation. Failed to query QSOs for export. Impossible de récupérer les QSO pour l’exportation. Cannot open file %1 for writing. Impossible d’ouvrir le fichier %1 en écriture. Exporting Cabrillo... Exportation Cabrillo… QLog Information Information QLog Exported %n QSO(s) to Cabrillo file. %n QSO exportés dans le fichier Cabrillo. CabrilloFormat All Bands 2m (144 MHz) 2m (144 MHz) 1.25m (222 MHz) 70cm (432 MHz) 70cm (432 MHz) 33cm (902 MHz) 33cm (902 MHz) 23cm (1.2 GHz) 23cm (1.2 GHz) Light Lumière VHF 3-Band VHF 3 bandes VHF FM Only VHF FM uniquement Digital Numérique Mixed Mixte High Haut (High) Low Bas (Low) QRP Single Operator Opérateur unique Multi Operator Multi-opérateurs Check Log Vérifier le log Non-Assisted Non assisté Assisted Assisté Fixed Fixe Mobile Mobile Portable Rover Rover Limited Rover Unlimited Expedition Expédition HQ School école Distributed Distribué One Un Two Deux Limited Limité Unlimited Illimité SWL SWL 6 Hours 6 heures 12 Hours 12 heures 24 Hours 24 heures Classic Classique Rookie TB Wires Novice/Tech Novice/Technicien Over 50 Plus de 50 Text (left-aligned) Texte (aligné à gauche) Frequency (kHz) Fréquence (kHz) Time (HHMM) Heure (HHMM) Date (YYYY-MM-DD) Date (AAAA-MM-JJ) RST Short (drop last digit) RST court (sans le dernier chiffre) Uppercase Majuscules Mode (Cabrillo) Mode (Cabrillo) Zero-Padded Nr. Numéro avec zéros Transmitter ID CabrilloTemplateDialog Cabrillo Template Manager Gestionnaire de modèles Cabrillo Import template Importer un modèle Import Importation Export template Exporter un modèle Export Exporter New template Nouveau modèle New Nouveau Copy existing template Copier un modèle existant Copy Copier Delete template Supprimer le modèle Delete Supprimer Template Name: Nom du modèle: Contest Name: Nom du concours: Default Mode: Mode par défaut: QSO Line Columns: Colonnes de ligne QSO: Contest name as required by the rules. It is possible to enter a custom string if it is not included in the list. Nom du concours selon les règles. Il est possible de saisir une chaîne personnalisée si elle ne figure pas dans la liste. Seq. QSO Field Champ QSO Formatter Formateur Width Largeur Label Étiquette Add line Ajouter une ligne Add Ajouter Remove selected line Supprimer la ligne sélectionnée Remove New Template Nouveau modèle Copy - %1 Copie – %1 Delete Template Supprimer le modèle Delete template '%1'? Supprimer le modèle «%1» ? Import Template Importer un modèle QLog Cabrillo Template (*.qct) Modèle Cabrillo QLog (*.qct) Import Failed Import échoué Export Template Exporter un modèle Export Failed Export échoué Failed to write file: %1 Impossible d’écrire le fichier : %1 File not found: %1 Fichier introuvable : %1 Cannot open file: %1 Impossible d’ouvrir le fichier : %1 Invalid template file: missing name Fichier de modèle invalide : nom manquant QLog Error Erreur QLog Cannot start database transaction. Impossible de démarrer la transaction de base de données. QLog Warning Avertissement QLog Cannot save template '%1': %2 Impossible d’enregistrer le modèle «%1» : %2 CallbookManager <p>The secondary callbook will be used</p> <p>La nomenclature (callbook) secondaire sera utilisée</p> ChatWidget ON4KST Chat Chat ON4KST Chat Room Salon de discussion Connect Connecter New Nouveau QLog Warning Avertissement QLog ON4KST Chat is not configured properly.<p> Please, use <b>Settings</b> dialog to configure it.</p> Le chat ON4KST n'est pas configuré correctement.<p> Veuillez utiliser le menu <b>Paramètres</b> pour le configurer.</p> CheckBoxDelegate Enabled Activé Disabled Désactivé ClockWidget Form Formulaire Sunrise Lever soleil Sunset Coucher soleil N/A N/D CloudlogUploader Invalid API Key Clé API invalide ClubLogUploader Clublog Operation for Callsign %1 failed.<br>%2 L'opération Clublog pour l'indicatif %1 a échoué.<br>%2 ColumnSettingDialog Column Visibility Setting Réglage de visibilité des colonnes General Général My Info Mes infos QSL && Callbooks QSL && Nomenclature Members Membres Conditionals Conditionnels Contests Concours (Contests) Others Autres Done Terminé ColumnSettingGenericDialog Unselect All Tout désélectionner Select All Tout sélectionner ColumnSettingSimpleDialog Column Visibility Setting Réglage de visibilité des colonnes Done Terminé DBSchemaMigration DXCC Entities Entités DXCC Sats Info Infos Satellites SOTA Summits Sommets SOTA WWFF Records Références WWFF IOTA Records Références IOTA POTA Records Références POTA Membership Directory Records Registres des listes de membres Clublog CTY.XML Fichier Clublog CTY.XML List of Values Liste de valeurs Updating Mise à jour de Update Failed Échec de la mise à jour DBStrings PHONE Phonie CW CW DIGITAL Numérique Afghanistan Afghanistan Agalega & St. Brandon Agalega & St. Brandon Aland Islands Îles d'Åland Alaska Alaska Albania Albanie Algeria Algérie American Samoa Samoa américaines Amsterdam & St. Paul Is. Is. Amsterdam & St. Paul Andaman & Nicobar Is. Is. Andaman & Nicobar Andorra Andorre Angola Angola Anguilla Anguilla Annobon Island Île d'Annobon Antarctica Antarctique Antigua & Barbuda Antigua & Barbuda Argentina Argentine Armenia Arménie Aruba Aruba Ascension Island Île de l'Ascension Asiatic Russia Russie asiatique Asiatic Turkey Turquie asiatique Austral Islands Îles Australes Australia Australie Austria Autriche Aves Island Île d'Aves Azerbaijan Azerbaïdjan Azores Açores Bahamas Bahamas Bahrain Bahreïn Baker & Howland Islands Îles Baker & Howland Balearic Islands Îles Baléares Banaba Island Île de Banaba Bangladesh Bangladesh Barbados Barbade Belarus Biélorussie Belgium Belgique Belize Belize Benin Bénin Bermuda Bermudes Bhutan Bhoutan Bolivia Bolivie Bonaire Bonaire Bosnia-Herzegovina Bosnie-Herzégovine Botswana Botswana Bouvet Bouvet Brazil Brésil British Virgin Islands Îles Vierges britanniques Brunei Darussalam Brunei Bulgaria Bulgarie Burkina Faso Burkina Faso Burundi Burundi Cambodia Cambodge Cameroon Cameroun Canada Canada Canary Islands Îles Canaries Cape Verde Cap-Vert Cayman Islands Îles Caïmans Central African Republic République centrafricaine Central Kiribati Kiribati Central Ceuta & Melilla Ceuta & Melilla Chad Tchad Chagos Islands Archipel des Chagos Chatham Islands Îles Chatham Chesterfield Islands Îles Chesterfield Chile Chili China Chine Christmas Island Île Christmas Clipperton Island Île de Clipperton Cocos (Keeling) Islands Îles Cocos (Keeling) Cocos Island Île de Cocos Colombia Colombie Comoros Comores Conway Reef Récif Conway Corsica Corse Costa Rica Costa Rica Cote d'Ivoire Côte d'Ivoire Crete Crète Croatia Croatie Crozet Island Île Crozet Cuba Cuba Curacao Curaçao Cyprus Chypre Czech Republic République tchèque DPR of Korea Corée du Nord Dem. Rep. of the Congo Rép. dém. du Congo Denmark Danemark Desecheo Island Île Desecheo Djibouti Djibouti Dodecanese Dodécanèse Dominica Dominique Dominican Republic République dominicaine Ducie Island Île Ducie East Malaysia Malaisie orientale Easter Island Île de Pâques Eastern Kiribati Kiribati oriental Ecuador Équateur Egypt Égypte El Salvador Salvador England Angleterre Equatorial Guinea Guinée équatoriale Eritrea Érythrée Estonia Estonie Ethiopia Éthiopie European Russia Russie européenne Falkland Islands Îles Falkland (Malouines) Faroe Islands Îles Féroé Fed. Rep. of Germany Rép. féd. d'Allemagne Fernando de Noronha Fernando de Noronha Fiji Fidji Finland Finlande France France Franz Josef Land Terre de François-Joseph French Guiana Guyane française French Polynesia Polynésie française Gabon Gabon Galapagos Islands Îles Galapagos Georgia Géorgie Ghana Ghana Gibraltar Gibraltar Glorioso Islands Îles Glorieuses Greece Grèce Greenland Groenland Grenada Grenade Guadeloupe Guadeloupe Guam Guam Guantanamo Bay Guantanamo Bay Guatemala Guatemala Guernsey Guernesey Guinea Guinée Guinea-Bissau Guinée-Bissau Guyana Guyana Haiti Haïti Hawaii Hawaï Heard Island Île Heard Honduras Honduras Hong Kong Hong Kong Hungary Hongrie ITU HQ Siège de l'UIT Iceland Islande India Inde Indonesia Indonésie Iran Iran Iraq Irak Ireland Irlande Isle of Man Île de Man Israel Israël Italy Italie Jamaica Jamaïque Jan Mayen Jan Mayen Japan Japon Jersey Jersey Johnston Island Île Johnston Jordan Jordanie Juan Fernandez Islands Îles Juan Fernández Juan de Nova & Europa Juan de Nova & Europa Kaliningrad Kaliningrad Kazakhstan Kazakhstan Kenya Kenya Kerguelen Islands Îles Kerguelen Kermadec Islands Îles Kermadec Kingdom of Eswatini Royaume d'Eswatini Kure Island Île Kure Kuwait Koweït Kyrgyzstan Kirghizistan Lakshadweep Islands Îles Lakshadweep Laos Laos Latvia Lettonie Lebanon Liban Lesotho Lesotho Liberia Liberia Libya Libye Liechtenstein Liechtenstein Lithuania Lituanie Lord Howe Island Île Lord Howe Luxembourg Luxembourg Macao Macao Macquarie Island Île Macquarie Madagascar Madagascar Madeira Islands Archipel de Madère Malawi Malawi Maldives Maldives Mali Mali Malpelo Island Île de Malpelo Malta Malte Mariana Islands Îles Mariannes Market Reef Récif Market Marquesas Islands Îles Marquises Marshall Islands Îles Marshall Martinique Martinique Mauritania Mauritanie Mauritius Maurice Mayotte Mayotte Mellish Reef Récif Mellish Mexico Mexique Micronesia Micronésie Midway Island Île Midway Minami Torishima Minami Torishima Moldova Moldavie Monaco Monaco Mongolia Mongolie Montenegro Monténégro Montserrat Montserrat Morocco Maroc Mount Athos Mont Athos Mozambique Mozambique Myanmar Myanmar (Birmanie) N.Z. Subantarctic Is. Is. subantarctiques de N.Z. Namibia Namibie Nauru Nauru Navassa Island Île de la Navasse Nepal Népal Netherlands Pays-Bas New Caledonia Nouvelle-Calédonie New Zealand Nouvelle-Zélande Nicaragua Nicaragua Niger Niger Nigeria Nigeria Niue Niue Norfolk Island Île Norfolk North Cook Islands Îles Cook du Nord North Macedonia Macédoine du Nord Northern Ireland Irlande du Nord Norway Norvège Ogasawara Ogasawara Oman Oman Pakistan Pakistan Palau Palaos Palestine Palestine Palmyra & Jarvis Islands Îles Palmyra & Jarvis Panama Panama Papua New Guinea Papouasie-Nouvelle-Guinée Paraguay Paraguay Peru Pérou Peter 1 Island Île Pierre 1er Philippines Philippines Pitcairn Island Île Pitcairn Poland Pologne Portugal Portugal Pr. Edward & Marion Is. Is. du Prince-Édouard & Marion Pratas Island Île Pratas Puerto Rico Porto Rico Qatar Qatar Republic of Korea République de Corée (Sud) Republic of Kosovo République du Kosovo Republic of South Sudan République du Soudan du Sud Republic of the Congo République du Congo Reunion Island Île de la Réunion Revillagigedo Revillagigedo Rodriguez Island Île Rodrigues Romania Roumanie Rotuma Island Île Rotuma Rwanda Rwanda Saba & St. Eustatius Saba & St. Eustache Sable Island Île de Sable Samoa Samoa San Andres & Providencia San Andrés & Providencia San Felix & San Ambrosio San Félix & San Ambrosio San Marino Saint-Marin Sao Tome & Principe Sao Tomé-et-Principe Sardinia Sardaigne Saudi Arabia Arabie saoudite Scarborough Reef Récif de Scarborough Scotland Écosse Senegal Sénégal Serbia Serbie Seychelles Seychelles Sierra Leone Sierra Leone Singapore Singapour Sint Maarten Saint-Martin (partie néerlandaise) Slovak Republic Slovaquie Slovenia Slovénie Solomon Islands Îles Salomon Somalia Somalie South Africa Afrique du Sud South Cook Islands Îles Cook du Sud South Georgia Island Géorgie du Sud South Orkney Islands Orcades du Sud South Sandwich Islands Îles Sandwich du Sud South Shetland Islands Shetland du Sud Sov Mil Order of Malta Ordre souverain de Malte Spain Espagne Spratly Islands Îles Spratleys Sri Lanka Sri Lanka St. Barthelemy Saint-Barthélemy St. Helena Sainte-Hélène St. Kitts & Nevis Saint-Kitts-et-Nevis St. Lucia Sainte-Lucie St. Martin Saint-Martin (partie française) St. Paul Island Île Saint-Paul (Alaska) St. Peter & St. Paul Rochers Saint-Pierre et Saint-Paul St. Pierre & Miquelon Saint-Pierre-et-Miquelon St. Vincent Saint-Vincent-et-les-Grenadines Sudan Soudan Suriname Suriname Svalbard Svalbard Swains Island Île Swains Sweden Suède Switzerland Suisse Syria Syrie Taiwan Taïwan Tajikistan Tadjikistan Tanzania Tanzanie Temotu Province Province de Temotu Thailand Thaïlande The Gambia Gambie Timor - Leste Timor oriental Togo Togo Tokelau Islands Îles Tokelau Tonga Tonga Trindade & Martim Vaz Trindade & Martim Vaz Trinidad & Tobago Trinité-et-Tobago Tristan da Cunha & Gough Islands Tristan da Cunha & Îles Gough Tromelin Island Île Tromelin Tunisia Tunisie Turkmenistan Turkménistan Turks & Caicos Islands Îles Turques-et-Caïques Tuvalu Tuvalu UK Base Areas on Cyprus Bases souveraines UK à Chypre US Virgin Islands Îles Vierges américaines Uganda Ouganda Ukraine Ukraine United Arab Emirates Émirats arabes unis United Nations HQ Siège des Nations unies United States États-Unis Uruguay Uruguay Uzbekistan Ouzbékistan Vanuatu Vanuatu Vatican City Cité du Vatican Venezuela Venezuela Vietnam Vietnam Wake Island Île Wake Wales Pays de Galles Wallis & Futuna Islands Îles Wallis-et-Futuna West Malaysia Malaisie occidentale Western Kiribati Kiribati occidental Western Sahara Sahara occidental Willis Island Île Willis Yemen Yémen Zambia Zambie Zimbabwe Zimbabwe DXCCSubmissionDialog DXCC Submission List Liste de soumission DXCC Options Options My DXCC Entity Mon entité DXCC User Filter Filtre utilisateur Category Catégorie Mixed Mixte CW CW Phone Phonie Digital Numérique Confirmed by Confirmé par LoTW LoTW Paper Papier Show Afficher Not Yet Submitted Pas encore soumis Submitted (Not Granted) Soumis (non accordé) Already Granted Déjà accordé Band Scope Plage de bande Select 5-Band DXCC preset bands (80/40/20/15/10m) Sélectionner les bandes prédéfinies DXCC 5 bandes (80/40/20/15/10 m) 5-Band DXCC DXCC 5 bandes Select all DXCC-eligible bands Sélectionner toutes les bandes éligibles DXCC All DXCC Bands Toutes les bandes DXCC Bands Bandes Select options above and the list will update automatically. Sélectionnez les options ci-dessus et la liste se mettra à jour automatiquement. Export the contacts listed above to an ADIF file Exporter les contacts listés ci-dessus dans un fichier ADIF Export Exporter No User Filter Aucun filtre utilisateur Any Band (Entity Level) Toute bande (niveau entité) 5-Band DXCC (80/40/20/15/10m) DXCC 5 bandes (80/40/20/15/10 m) Custom Band Selection Sélection personnalisée des bandes Entity Entité Prefix Préfixe Callsign Indicatif Band Bande Mode Mode Date Date Submitted Soumis Granted Accordé Export ADIF Exporter ADIF No contacts to export. Aucun contact à exporter. Failed to retrieve contact records. Impossible de récupérer les enregistrements de contacts. Export DXCC Submission List as ADIF Exporter la liste de soumission DXCC en ADIF any band toute bande 5-band 5 bandes all bands toutes les bandes %1 selected band(s) %1 bande(s) sélectionnée(s) No contacts match the selected criteria. Aucun contact ne correspond aux critères sélectionnés. %1 %2 %3 — DXCC %4 / %5 %1 %2 %3 — DXCC %4 / %5 band-slot emplacement de bande entity entité entry entrée entries entrées Data New Entity Nouvelle entité New Band Nouvelle bande New Mode Nouveau mode New Band&Mode Nouvelle bande & mode New Slot Nouveau créneau Confirmed Confirmé Worked Contacté Hz Hz kHz kHz GHz GHz MHz MHz Yes Oui No Non Requested Demandé Queued En attente Invalid Invalide Bureau Bureau Direct Direct Electronic Électronique Blank Vide Modified Modifié Grayline Ligne de gris Other Autre Short Path Petit chemin Long Path Grand chemin Not Heard Non entendu Uncertain Incertain Straight Key Pioche (Clé droite) Sideswiper Sideswiper (Cootie) Mechanical semi-automatic keyer or Bug Manipulateur semi-automatique (Bug) Mechanical fully-automatic keyer or Bug Manipulateur entièrement automatique Single Paddle Simple levier Dual Paddle Double levier (Iambique) Computer Driven Piloté par ordinateur Confirmed (AG) Confirmé (AG) Confirmed (no AG) Confirmé (sans AG) Unknown Inconnu Aircraft Scatter Diffusion par avion Aurora-E Aurore-E Aurora Aurore Back scatter Rétrodiffusion EchoLink EchoLink Earth-Moon-Earth Terre-Lune-Terre (EME) Sporadic E E sporadique F2 Reflection Réflexion F2 Field Aligned Irregularities Irrégularités alignées sur le champ Ground Wave Onde de sol Internet-assisted Assisté par Internet Ionoscatter Diffusion ionosphérique IRLP IRLP Line of Sight Ligne de vue Meteor scatter Météor-scatter Terrestrial or atmospheric repeater or transponder Relais ou transpondeur terrestre/atmosphérique Rain scatter Diffusion par la pluie Satellite Satellite Trans-equatorial Trans-équatorial Tropospheric ducting Guidage troposphérique DateFormatDelegate Blank Vide DevToolsDialog Developer Tools Outils dev Debug Log Journal de débogage Logging Rules: Règles de journalisation: e.g. qlog.ui.*.runtime=true p. ex. qlog.ui.*.runtime=true Apply Appliquer Generate Debug File Générer un fichier de débogage Export File Exporter le fichier SQL Console Console SQL Open SQL Ouvrir SQL Save SQL Enregistrer SQL Run SQL Exécuter SQL Export As Exporter en tant que Enter SQL query here... Ctrl+Return = run Saisissez la requête SQL ici... Ctrl+Entrée = exécuter TXT CSV CSV ADI Open SQL Query Ouvrir la requête SQL SQL Files (*.sql);;All Files (*) Fichiers SQL (*.sql);;Tous les fichiers (*) Open Error Erreur d’ouverture Cannot open file: %1 Impossible d’ouvrir le fichier: %1 Save SQL Query Enregistrer la requête SQL Save Error Erreur d’enregistrement Cannot save file: %1 Impossible d’enregistrer le fichier: %1 Query saved to %1 Requête enregistrée dans %1 Error: %1 Erreur : %1 %1 row(s) shown (truncated at %2) in %3 ms %1 ligne(s) affichée(s) (tronqué à %2) en %3 ms %1 row(s) returned in %2 ms %1 ligne(s) retournée(s) en %2 ms Export Exporter No results to export. Aucun résultat à exporter. Export Error Erreur d’exportation Cannot open file for writing: %1 Impossible d’ouvrir le fichier en écriture: %1 Exported %1 row(s) to %2 %1 ligne(s) exportée(s) vers %2 Text Files (*.txt);;All Files (*) Fichiers texte (*.txt);;Tous les fichiers (*) CSV Files (*.csv);;All Files (*) Fichiers CSV (*.csv);;Tous les fichiers (*) ADIF Export Exporter ADIF ADIF export requires the query to include the contacts 'id' column. Example: SELECT id, callsign FROM contacts WHERE ... No valid contact IDs found in the result set. Aucun identifiant de contact valide trouvé dans le jeu de résultats. Failed to retrieve contact records: %1 Impossible de récupérer les enregistrements de contacts: %1 No matching contacts found in the database. Aucun contact correspondant trouvé dans la base de données. Logging rules cleared (defaults) Règles de journalisation réinitialisées (par défaut) Logging rules applied Règles de journalisation appliquées Save Debug Log Enregistrer le journal de débogage No debug log file is currently being written Aucun fichier de journal de débogage n’est actuellement en cours d’écriture Log Files (*.log);;All Files (*) Fichiers journaux (*.log);;Tous les fichiers (*) Debug log saved to %1 Journal de débogage enregistré dans %1 Failed to copy the debug log file. Impossible de copier le fichier de journal de débogage. File logging is disabled La journalisation dans un fichier est désactivée Log file: %1 Fichier de journal : %1 DownloadQSLDialog Download QSLs Télécharger les QSL eQSL eQSL eQSL QTH Profile Profil QTH eQSL QSLs Since QSL depuis le QSOs Since QSO depuis le LoTW LoTW My Callsign Mon indicatif &Download &Télécharger LoTW is not configured properly.<p> Please, use <b>Settings</b> dialog to configure it.</p> LoTW n'est pas configuré correctement.<p> Veuillez utiliser la fenêtre des <b>Paramètres</b> pour le configurer.</p> eQSL is not configured properly.<p> Please, use <b>Settings</b> dialog to configure it.</p> eQSL n'est pas configuré correctement.<p> Veuillez utiliser la fenêtre des <b>Paramètres</b> pour le configurer.</p> Cancel Annuler Downloading from %1 Téléchargement depuis %1 Processing %1 QSLs Traitement de %1 QSL QLog Error Erreur QLog %1 update failed: La mise à jour de %1 a échoué : QLog Information Information QLog No service selected Aucun service sélectionné DxFilterDialog DX Cluster Filters Filtres DX Cluster General Filters Filtres généraux Bands Bandes Modes Modes Phone Phonie CW CW Digital Numérique FTx (FT8/FT4) FTx (FT8/FT4) Continent Continent North America Amérique du Nord South America Amérique du Sud Oceania Océanie Antarctica Antarctique Europe Europe Africa Afrique Asia Asie Log Status Statut du log New Mode Nouveau mode New Entity Nouvelle entité New Band Nouvelle bande New Slot Nouveau créneau Worked Contacté Confirmed Confirmé Extended Filters Filtres étendus Spotter Continent Continent du spotteur Do not show the following spots when they have the same Callsign and their time difference is lower than Time Diff and their frequency difference is lower than Freq Diff Ne pas afficher les spots suivants s'ils ont le même indicatif et que leur différence de temps est inférieure à Time Diff et leur différence de fréquence inférieure à Freq Diff Spots Dedup Déduplication des spots Time difference Différence de temps s s Frequency difference Différence de fréquence kHz kHz Member Membre No Club List is enabled Aucune liste de club n'est activée DxTableModel Time Heure Callsign Indicatif Frequency Fréquence Mode Mode Spotter Spotteur Comment Commentaire Continent Continent Spotter Continent Continent du spotteur Band Bande Member Membre Country Pays DxWidget Insert a <b>hostname:port</b> of DXC Server. Entrez un <b>hôte:port</b> de serveur DXC. Connect Connecter Filtered Filtré Spots Spots WCY WCY WWV WWV To All À tous Console Console 15-min Trend Tendance 15 min Full-text search Recherche plein texte Search Rechercher Close Search Fermer la recherche Send DX Cluster Command Envoyer une commande DX Cluster Filter... Filtrer... Filter DXC Filtrer DXC Spot Last QSO Spotter le dernier QSO Send last QSO spot Envoyer le spot du dernier QSO Show HF Stats Afficher stats HF Show VHF Stats Afficher stats VHF Show WCY Afficher WCY Show WWV Afficher WWV Column Visibility... Visibilité des colonnes... Which columns should be displayed Quelles colonnes doivent être affichées Connect on startup Connecter au démarrage Automatic connection after start Connexion automatique après le démarrage Delete Server Supprimer le serveur DXC - Delete Server DXC - Supprimer le serveur Clear Password Effacer le mot de passe Keep Spots Garder les spots Spots are not cleared when connecting to a new DX Cluster. Les spots ne sont pas effacés lors de la connexion à un nouveau DX Cluster. Clear Effacer Clear all data Effacer toutes les données Search... Rechercher... DXC - Search DXC - Rechercher My Continent Mon continent Auto Auto Connecting... Connexion... DX Cluster is temporarily unavailable Le DX Cluster est temporairement indisponible DXC Server Error Erreur serveur DXC An invalid callsign Un indicatif invalide DX Cluster Password Mot de passe DX Cluster Security Notice Avis de sécurité The password can be sent via an unsecured channel Le mot de passe peut être envoyé via un canal non sécurisé Server Serveur Username Utilisateur Disconnect Déconnecter DX Cluster Command Commande DX Cluster DxccTableModel Worked Contacté eQSL eQSL LoTW LoTW Paper Papier DxccTableWidget Mode Mode EQSLQSLDownloader Incorrect Password or QTHProfile Id Mot de passe ou ID de profil QTH incorrect ADIF file not found in eQSL response Fichier ADIF non trouvé dans la réponse eQSL Incorrect Username or password Identifiant ou mot de passe incorrect Unknown Error Erreur inconnue Cannot opet temporary file Impossible d'ouvrir le fichier temporaire Cannot save the image to file Impossible de sauvegarder l'image dans le fichier EQSLUploader Unknown Reply from eQSL Réponse inconnue de eQSL EditActivitiesDialog Edit Activities Modifier les activités Activities Activités Add Ajouter Edit Modifier Remove Supprimer ExportDialog Export Selected QSOs Exporter les QSO sélectionnés File Fichier Browse Parcourir ADX ADX CSV CSV JSON JSON POTA POTA Export Type Type d'exportation Column set Jeu de colonnes Select one of the pre-defined sets of columns or define your own set of columns Sélectionnez un des jeux de colonnes prédéfinis ou définissez le vôtre Edit current set of columns Modifier le jeu de colonnes actuel Edit Modifier Mark exported QSOs As Sent Marquer les QSO exportés comme envoyés Export only QSOs that match the active filters Exporter uniquement les QSO correspondant aux filtres actifs Filters Filtres Export only QSOs that match the selected date range Exporter uniquement les QSO de la période sélectionnée Date Range Plage de dates Export only QSOs that match the selected My Callsign Exporter uniquement les QSO correspondant à "Mon Indicatif" My Callsign Mon indicatif Export only QSOs that match the selected My Gridsquare Exporter uniquement les QSO correspondant à mon Locator (Gridsquare) My Gridsquare Mon Locator Export only QSOs that match the selected QSL Send Via value Exporter uniquement les QSO avec ce mode d'envoi de QSL QSL Send via Envoyer QSL via Include unusual QSO Sent statuses Inclure les statuts d'envoi de QSO inhabituels Include Sent Status Inclure le statut d'envoi Under normal circumstances this status means <b>"Ignore/Invalid"</b>.<br/>However, it may sometimes be wanted to ignore this setting when sending a QSL. En temps normal, ce statut signifie <b>"Ignorer/Invalide"</b>.<br/>Cependant, il peut être souhaitable d'ignorer ce paramètre lors de l'envoi d'une QSL. "Ignore" "Ignorer" Under normal circumstances this status means <b>"do not send"</b>.<br/>However, it may sometimes be wanted to ignore this setting when sending a QSL. En temps normal, ce statut signifie <b>"ne pas envoyer"</b>.<br/>Cependant, il peut être souhaitable d'ignorer ce paramètre lors de l'envoi d'une QSL. "No" "Non" Resend already sent QSOs Renvoyer les QSO déjà envoyés Already Sent Déjà envoyé User Filter Filtre utilisateur Export QSOs that match the selected user QSO Filter Exporter les QSO correspondant au filtre utilisateur sélectionné Station Profile Profil de station Export QSOs Exporter les QSO &Export &Exporter Export only QSOs matching this station profile Exporter uniquement les QSO correspondant à ce profil de station Exporting... Exportation en cours… Cancel Annuler QLog Error Erreur QLog Cannot mark exported QSOs as Sent Impossible de marquer les QSO exportés comme Envoyés Generic Générique QSLs QSL All Tous Minimal Minimal QSL-specific Spécifique aux QSL Custom 1 Personnalisé 1 Custom 2 Personnalisé 2 Custom 3 Personnalisé 3 ExportPasswordDialog Pack Data & Settings Archiver les données et paramètres Enter a password to encrypt stored credentials. The password will be needed to restore them later. Entrez un mot de passe pour chiffrer vos identifiants enregistrés. Ce mot de passe sera nécessaire pour les restaurer ultérieurement. Password Mot de passe Random Aléatoire Confirm Password Confirmer le mot de passe Delete passwords from Credential Store after export Supprimer les mots de passe du gestionnaire d'identifiants après export FlrigRigDrv Timeout Délai expiré FLRig response timeout Délai de réponse de FLRig expiré Network Error Erreur réseau HRDLogUploader Response message malformed Message de réponse mal formé HamQTHCallbook HamQTH HamQTH HamlibRigDrv None Aucun CAT CAT DTR DTR RTS RTS Initialization Error Erreur d'initialisation Cannot set PTT Type Impossible de définir le type de PTT Cannot set PTT Share Impossible de définir le partage du PTT Cannot set CIV Addr Impossible de définir l'adresse CI-V Unsupported Rig Driver Pilote de transceiver non supporté Cannot set auto_power_on Impossible de définir auto_power_on Cannot set no_xchg to 1 Impossible de définir no_xchg à 1 Rig Open Error Erreur d'ouverture du transceiver Set TX Frequency Error Erreur lors du réglage de la fréquence TX Set Frequency Error Erreur lors du réglage de la fréquence Set Split Error Erreur lors du réglage du split Set Mode Error Erreur lors du réglage du mode Set Split Mode Error Erreur lors du réglage du mode split Set PTT Error Erreur lors du réglage du PTT Cannot sent Morse Impossible d'envoyer du Morse Cannot stop Morse Impossible d'arrêter le Morse Get PTT Error Erreur lors de la lecture du PTT Get Frequency Error Erreur lors de la lecture de la fréquence Get Mode Error Erreur lors de la lecture du mode Get VFO Error Erreur lors de la lecture du VFO Get PWR Error Erreur lors de la lecture de la puissance Get PWR (power2mw) Error Erreur lors de la lecture de puissance (mW) Get RIT Function Error Erreur lors de la lecture de la fonction RIT Get RIT Error Erreur lors de la lecture du RIT Get XIT Function Error Erreur lors de la lecture de la fonction XIT Get XIT Error Erreur lors de la lecture du XIT Get Split Error Get TX Frequency Error Get KeySpeed Error Erreur lors de la lecture de la vitesse de manipulation Set KeySpeed Error Erreur lors du réglage de la vitesse de manipulation HamlibRotDrv Initialization Error Erreur d'initialisation Unsupported Rotator Driver Pilote de rotor non supporté Rot Open Error Erreur d'ouverture du rotor Set Possition Error Erreur lors du réglage de la position Get Possition Error Erreur lors de la lecture de la position ImportDialog Import Importation Date Range Plage de dates Import all or only QSOs from the given period Importer tous les QSO ou seulement ceux d'une période donnée All Tous File Fichier ADX ADX Browse Parcourir Options Options The value is used when an input record does not contain the ADIF value La valeur est utilisée lorsqu'un enregistrement d'entrée ne contient pas la valeur ADIF Defaults Par défaut My Profile Mon profil My Rig Mon transceiver Comment Commentaire If DXCC is missing in the imported record, it will be resolved from the callsign. Si le DXCC manque dans l’enregistrement importé, il sera déterminé à partir de l’indicatif. Fill missing DXCC Entity Information Compléter les informations d’entité DXCC manquantes &Import &Importer Select File Sélectionner un fichier The values below will be used when an input record does not contain the ADIF values Les valeurs ci-dessous seront utilisées lorsqu'un enregistrement d'entrée ne contient pas les valeurs ADIF <p><b>In-Log QSO:</b></p><p> <p><b>QSO dans le log :</b></p><p> <p><b>Importing:</b></p><p> <p><b>Importation :</b></p><p> Duplicate QSO QSO en double <p>Do you want to import duplicate QSO?</p>%1 %2 <p>Voulez-vous importer le QSO en double ?</p>%1 %2 Save to File Sauvegarder dans un fichier QLog Import Summary Résumé de l'importation QLog Import date Date d'importation Imported file Fichier importé Imported: %n contact(s) Importé : %n contact Importés : %n contacts Warning(s): %n Avertissement : %n Avertissements : %n Error(s): %n Erreur : %n Erreurs : %n Details Détails Import Result Résultat de l'importation Save Details... Enregistrer les détails... InputPasswordDialog Dialog Fenêtre The password will be stored in the Credential Store. Le mot de passe sera enregistré dans le gestionnaire d'identifiants. Remember Password Retenir le mot de passe KSTChat Unknown User Utilisateur inconnu Invalid password Mot de passe invalide KSTChatWidget Chat messages Messages de discussion Valuable messages Messages importants Clear selected Callsign and Chat message entry. Effacer l'indicatif sélectionné et le message de discussion saisi. Send chat message Envoyer le message Column Visibility Visibilité des colonnes Which columns should be displayed Quelles colonnes doivent être affichées Prepare QSO Préparer le QSO Transfer Callsign and Gridsquare Information to the New QSO dialog Transférer l'indicatif et le Locator vers la fenêtre de nouveau QSO Show About Me Only M'afficher uniquement Show only messages where my callsign is present Afficher uniquement les messages mentionnant mon indicatif Suppress User To User Supprimer "Utilisateur à Utilisateur" Suppress private messages between two callsigns Supprimer les messages privés entre deux indicatifs Highlight Mise en évidence Highlight messages based on the setting Mettre en évidence les messages selon les réglages Highlight Rules Règles de mise en évidence Beam Azimut (Beam) Clear Messages Effacer les messages Clear all messages in the window Effacer tous les messages de la fenêtre You Vous KSTHighlightRuleDetail Edit Rule Modifier la règle Rule Name Nom de la règle Chat Room Salon de discussion Enabled Activé Highlight message which match Mettre en évidence les messages correspondant à All the following conditions Toutes les conditions suivantes Any of the following conditions L'une des conditions suivantes Add Condition Ajouter une condition All Tous Sender Expéditeur Message Message Gridsquare Locator Contains Contient Starts with Commence par Remove Supprimer Must not be empty Ne doit pas être vide KSTHighlighterSettingDialog Highlight Rules Règles de mise en évidence Rules Règles Add Ajouter Edit Modifier Remove Supprimer Name Nom State État KeySequenceEdit Clear Effacer LoadDatabaseDialog Unpack Data & Settings Déballer les données et les paramètres Warning Avertissement <html><head/><body><p>⚠ <span style=" font-weight:700;">Current database will be DELETED!</span><br/>⚠ <span style=" font-weight:700;">All stored passwords will be DELETED!</span><br/>⚠ <span style=" font-weight:700;">The application will restart after loading</span>.</p><p>To preserve data, use Pack Data &amp; Settings or Export QSOs first.</p></body></html> <html><head/><body><p>⚠ <span style=" font-weight:700;">La base de données actuelle sera SUPPRIMÉE !</span><br/>⚠ <span style=" font-weight:700;">Tous les mots de passe enregistrés seront SUPPRIMÉS !</span><br/>⚠ <span style=" font-weight:700;">L'application redémarrera après le chargement</span>.</p><p>Pour préserver les données, utilisez d'abord Pack Data &amp; Settings ou Export QSOs.</p></body></html> Select Database Sélectionner la base de données File: Fichier : Browse Parcourir Status: No file selected Statut : Aucun fichier sélectionné Decrypt Credentials Déchiffrer les identifiants Enter password to decrypt credentials Entrez le mot de passe pour déchiffrer les identifiants Password: Mot de passe : Load && Restart Charger && Redémarrer Invalid password Mot de passe invalide Select Database File Sélectionner le fichier de base de données QLog Database Export (*.dbe);;All Files (*) Export de base de données QLog (*.dbe);;Tous les fichiers (*) Cannot create temporary file Impossible de créer le fichier temporaire Decompressing database... Décompression de la base de données... Cannot decompress database file Impossible de décompresser le fichier de base de données Cannot open database Impossible d'ouvrir la base de données Valid database Base de données valide Different platform Plateforme différente Password required to import credentials Mot de passe requis pour importer les identifiants No encrypted credentials in database Aucun identifiant chiffré dans la base de données LogFormat Cannot find My DXCC Entity Info Impossible de trouver mes informations d'entité DXCC A minimal set of fields not present (start_time, call, band, mode, station_callsign) Un ensemble minimal de champs est manquant (start_time, call, band, mode, station_callsign) Outside the selected Date Range En dehors de la plage de dates sélectionnée Duplicate Doublon DXCC Info is missing Les informations DXCC sont manquantes no Station Callsign present aucun indicatif de station présent Cannot insert to database Impossible d'insérer dans la base de données Imported Importé DXCC State: État DXCC : Error Erreur Warning Avertissement LogbookModel Country Pays Band Bande Mode Mode RST Sent RST Envoyé RST Rcvd RST Reçu Gridsquare Locator QSL Message Message QSL Comment Commentaire Notes Notes Paper Papier LoTW LoTW eQSL eQSL QSL Received QSL Reçue QSL Sent QSL Envoyée QSO ID ID QSO Time on Heure début Time off Heure fin Call Indicatif RSTs RSTe RSTr RSTr Frequency Fréquence Submode Sous-mode Name (ASCII) Nom (ASCII) QTH (ASCII) QTH (ASCII) DXCC DXCC Country (ASCII) Pays (ASCII) Continent Continent CQZ CQZ ITU ITU Prefix Préfixe State État County Comté County Alt Comté Alt IOTA IOTA QSLr QSLr QSLr Date Date QSLr QSLs QSLs QSLs Date Date QSLs LoTWr LoTWr LoTWr Date Date LoTWr LoTWs LoTWs LoTWs Date Date LoTWs TX PWR TX PWR Additional Fields Champs additionnels Address (ASCII) Adresse (ASCII) Address Adresse Age Âge Altitude Altitude A-Index Indice A Antenna Az Azimut Antenne Antenna El Élévation Antenne Signal Path Chemin du Signal ARRL Section Section ARRL Award Submitted Récompense soumise Award Granted Récompense accordée Band RX Bande RX Gridsquare Extended Locator étendu Contest Check Vérification Concours Class Classe ClubLog Upload Date Date d'envoi ClubLog ClubLog Upload State État d'envoi ClubLog Comment (ASCII) Commentaire (ASCII) Contacted Operator Opérateur contacté Contest ID ID Concours Credit Submitted Crédit soumis Credit Granted Crédit accordé DOK DOK DCLr Date Date DCLr DCLs Date Date DCLs DCLr DCLr DCLs DCLs Distance Distance Email Email Owner Callsign Indicatif du propriétaire eQSL AG eQSL AG eQSLr Date Date eQSLr eQSLs Date Date eQSLs eQSLr eQSLr eQSLs eQSLs FISTS Number Numéro FISTS FISTS CC FISTS CC EME Init Init EME Frequency RX Fréquence RX Guest Operator Opérateur invité HamlogEU Upload Date Date d'envoi HamlogEU HamlogEU Upload Status Statut d'envoi HamlogEU HamQTH Upload Date Date d'envoi HamQTH HamQTH Upload Status Statut d'envoi HamQTH HRDLog Upload Date Date d'envoi HRDLog HRDLog Upload Status Statut d'envoi HRDLog IOTA Island ID ID Île IOTA K-Index Indice K Latitude Latitude Longitude Longitude Max Bursts Rafales max (Bursts) CW Key Info Infos clé CW CW Key Type Type de clé CW MS Shower Name Essaim MS (Météor Scatter) My Altitude Mon altitude My Antenna (ASCII) Mon antenne (ASCII) My Antenna Mon antenne My City (ASCII) Ma ville (ASCII) My City Ma ville My County Mon département/comté My County Alt Mon département (Alt) My Country (ASCII) Mon pays (ASCII) My Country Mon pays My CQZ Ma zone CQ My DARC DOK Mon DOK (DARC) My DXCC Mon DXCC My FISTS Mon n° FISTS My Gridsquare Mon Locator My Gridsquare Extended Mon Locator (étendu) My IOTA Mon IOTA My IOTA Island ID Mon ID d'île IOTA My ITU Ma zone ITU My Latitude Ma latitude My Longitude Ma longitude My CW Key Info Infos sur ma clé CW My CW Key Type Mon type de clé CW My Name (ASCII) Mon nom (ASCII) My Name Mon nom My Postal Code (ASCII) Mon code postal (ASCII) My Postal Code Mon code postal My POTA Ref Ma réf. POTA My Rig (ASCII) Ma station/TRX (ASCII) My Rig Ma station/TRX My Special Interest Activity (ASCII) Mon activité spéciale (ASCII) My Special Interest Activity Mon activité spéciale My Spec. Interes Activity Info (ASCII) Infos activité spéc. (ASCII) My Spec. Interest Activity Info Infos activité spéc. My SOTA Mon SOTA My State Mon État/Province My Street Ma rue My USA-CA Counties Mes comtés USA-CA My VUCC Grids Mes locators VUCC Name Nom Notes (ASCII) Notes (ASCII) #MS Bursts Nb rafales MS #MS Pings Nb pings MS Operator Callsign Indicatif de l'opérateur POTA POTA Contest Precedence Precedence (Contest) Propagation Mode Mode de propagation Public Encryption Key Clé de chiffrement publique QRZ Download Date Date de téléchargement QRZ QRZ Download Status Statut téléchargement QRZ QRZ Upload Date Date d'envoi vers QRZ QRZ Upload Status Statut envoi vers QRZ QSLs Message (ASCII) Message QSL envoyée (ASCII) QSLs Message Message QSL envoyée QSLr Message Message QSL reçue QSLr Via QSL reçue via QSLs Via QSL envoyée via QSL Via QSL via QSO Completed QSO terminé QSO Random QSO aléatoire QTH QTH Region Région Rig (ASCII) TRX (ASCII) Rig TRX RcvPWR Puissance reçue SAT Mode Mode Satellite SAT Name Nom du Satellite Solar Flux Flux solaire SIG (ASCII) SIG (ASCII) SIG SIG SIG Info (ASCII) Infos SIG (ASCII) SIG Info Infos SIG Silent Key Silent Key (SK) SKCC Member Membre SKCC SOTA SOTA RcvNr N° reçu RcvExch Échange reçu Logging Station Callsign Indicatif de la station de saisie SentNr N° envoyé SentExch Échange envoyé SWL SWL Ten-Ten Number Numéro Ten-Ten UKSMG Member Membre UKSMG USA-CA Counties Comtés USA-CA VE Prov Province VE VUCC VUCC Web Web My ARRL Section Ma section ARRL My WWFF Mon WWFF WWFF WWFF LogbookWidget Delete Supprimer Logbook - Delete QSO Carnet de trafic - Supprimer QSO Upload to Clublog Envoyer vers Clublog Lookup on Web Rechercher sur le Web Update from Callbook Mise à jour via Callbook Add Missing Info Ajouter les infos manquantes Mark QSL RCVD Marquer QSL comme reçue Mark QSL Requested Marquer QSL demandée Filter Callsign Filtrer par indicatif Edit Value Modifier la valeur Logbook - Edit Value Carnet de trafic - Modifier la valeur Column Visibility Visibilité des colonnes Which columns should be displayed Quelles colonnes afficher Export Selected Exporter la sélection Export selected QSOs Exporter les QSO sélectionnés Send DX Spot Envoyer un Spot DX Logbook - Send DX Spot Carnet de trafic - Envoyer Spot DX Callsign Indicatif Gridsquare Locator POTA POTA SOTA SOTA WWFF WWFF SIG SIG IOTA IOTA All Bands Toutes les bandes All Modes Tous les modes All Countries Tous les pays No User Filter Aucun filtre utilisateur QLog Warning Avertissement QLog Each batch supports up to 100 QSOs. Chaque lot supporte jusqu'à 100 QSO. QSOs Update Progress Progression de la mise à jour des QSO Cancel Annuler QLog Error Erreur QLog Callbook login failed Échec de connexion au Callbook Callbook error: Erreur Callbook : All Clubs Tous les clubs Delete the selected contacts? Supprimer les contacts sélectionnés ? Clublog's <b>Immediately Send</b> supports only one-by-one deletion<br><br>Do you want to continue despite the fact<br>that the DELETE operation will not be sent to Clublog? L'option <b>Envoi immédiat</b> de Clublog ne supporte que la suppression unitaire.<br><br>Voulez-vous continuer sachant que l'opération de SUPPRESSION ne sera pas transmise à Clublog ? Deleting QSOs Suppression des QSO en cours Update Mettre à jour By updating, all selected rows will be affected.<br>The value currently edited in the column will be applied to all selected rows.<br><br>Do you want to edit them? La mise à jour affectera toutes les lignes sélectionnées.<br>La valeur éditée dans la colonne sera appliquée à toute la sélection.<br><br>Voulez-vous valider la modification ? Count: %n Nombre : %n Nombre : %n Downloading eQSL Image Téléchargement de l'image eQSL eQSL Download Image failed: Échec du téléchargement de l'image eQSL : LotwQSLDownloader Cannot open temporary file Impossible d'ouvrir le fichier temporaire Incorrect login or password Identifiant ou mot de passe incorrect LotwUploader Upload cancelled by user Envoi annulé par l'utilisateur Upload rejected by LoTW Envoi rejeté par LoTW Unexpected response from TQSL server Réponse inattendue du serveur TQSL TQSL utility error Erreur de l'utilitaire TQSL TQSLlib error Erreur TQSLlib Unable to open input file Impossible d'ouvrir le fichier d'entrée Unable to open output file Impossible d'ouvrir le fichier de sortie All QSOs were duplicates or out of date range Tous les QSO étaient des doublons ou hors plage de dates Some QSOs were duplicates or out of date range Certains QSO étaient des doublons ou hors plage de dates Command syntax error Erreur de syntaxe de commande LoTW Connection error (no network or LoTW is unreachable) Erreur de connexion LoTW (pas de réseau ou LoTW injoignable) Unexpected Error from TQSL Erreur inattendue de TQSL TQSL not found TQSL introuvable TQSL crashed TQSL a planté MainWindow &File &Fichier &Logbook &Carnet de trafic &Equipment &Équipement &Help &Aide &Window &Fenêtre Se&rvice Se&rvices Contest Concours (Contest) Dupe Check Vérif. Doublons Sequence Séquence Linking Exchange With Lier l'échange avec Toolbar Barre d'outils Clock Horloge Map Carte DX Cluster DX Cluster WSJTX WSJTX Rotator Rotor Bandmap Carte des bandes Rig TRX Online Map Carte en ligne CW Console Console CW Chat Chat Profile Image Image de profil Alerts Alertes Quit Quitter Application - Quit Quitter l'application &Settings &Réglages Pack Data && Settings Sauvegarder données && réglages Unpack Data && Settings Restaurer données && réglages New QSO - Clear Nouveau QSO - Effacer &Import &Importer &Export &Exporter Connect R&ig Connecter le T&RX &About À &propos New QSO - Save Nouveau QSO - Enregistrer S&tatistics S&tatistiques QSL &Gallery &Galerie QSL Developer Tools Outils dev Run custom read-only SQL queries against the logbook database Exécuter des requêtes SQL personnalisées en lecture seule sur la base de données du logbook Print QSL &Labels &Imprimer les étiquettes QSL Wsjtx WSJTX Connect R&otator Connecter le r&otor QSO &Filters &Filtres de QSO &Awards &Diplômes DXCC &Submission List &Liste de soumission DXCC Generate a list of contacts to submit for ARRL DXCC award credit Générer une liste de contacts à soumettre pour le crédit ARRL DXCC Edit Rules Modifier les règles Beep Bip Connect &CW Keyer Connecter le manipulateur &CW &Wiki &Wiki Report &Bug... Signaler un &bug... &Manual Entry Saisie &manuelle Switch New Contact dialog to the manually entry mode<br/>(time, freq, profiles etc. are not taken from their common sources) Passer la saisie de contact en mode manuel<br/>(l'heure, la fréquence et les profils ne sont plus synchronisés) Mailing List... Liste de diffusion... Edit Modifier Save Arrangement Enregistrer la disposition Keep Options Conserver les options Restore connection options after application restart Restaurer les options de connexion au redémarrage Logbook - Search Callsign Carnet de trafic - Chercher indicatif New QSO - Add text from Callsign field to Bandmap Nouveau QSO - Ajouter l'indicatif à la carte des bandes Rig - Band Down TRX - Bande inférieure Rig - Band Up TRX - Bande supérieure New QSO - Use Callsign from the Whisperer Nouveau QSO - Utiliser l'indicatif du Whisperer CW Console - Key Speed Up Console CW - Augmenter la vitesse CW Console - Key Speed Down Console CW - Diminuer la vitesse CW Console - Profile Up Console CW - Profil suivant CW Console - Profile Down Console CW - Profil précédent Rig - PTT On/Off TRX - PTT On/Off Clear Effacer Show Alerts Afficher les alertes All Bands Toutes bandes Each Band Par bande Each Band && Mode Par bande && mode No Check Pas de vérif. Single Simple Per Band Par bande Stop Arrêt Reset Réinitialiser None Aucun Upload Envoyer Service - Upload QSOs Service - Envoi des QSO Download QSLs Récupérer QSL Service - Download QSLs Service - Récupération des QSL Theme: Native Thème : Natif Theme: QLog Light Thème : QLog Clair Theme: QLog Dark Thème : QLog Sombre What's New Nouveautés Export Cabrillo Exporter Cabrillo Color Theme Thème de couleur Not enabled for non-Fusion style Non activé pour le style hors-Fusion Press to tune the alert Appuyez pour régler l'alerte Clublog Immediately Upload Error Erreur d'envoi immédiat Clublog <b>Error Detail:</b> <b>Détail de l'erreur :</b> op: op : A New Version Nouvelle version disponible A new version %1 is available. Une nouvelle version %1 est disponible. Remind Me Later Me le rappeler plus tard Download Télécharger Failed to encrypt credentials. Échec du chiffrement des identifiants. Database files (*.dbe);;All files (*) Fichiers base de données (*.dbe);;Tous les fichiers (*) Failed to create temporary file. Échec de création du fichier temporaire. Failed to dump the database. Échec de l'exportation de la base de données. Compressing database... Compression de la base... Database successfully dumped to %1 Base de données exportée avec succès vers %1 Failed to compress the database. Échec de la compression de la base de données. Failed to prepare database for import. Échec de la préparation de la base pour l'importation. Classic Classique Do you want to remove the Contest filter %1? Voulez-vous supprimer le filtre de concours %1 ? Contest: Concours : <h1>QLog %1</h1><p>&copy; 2019 Thomas Gatzweiler DL2IC<br/>&copy; 2021-2026 Ladislav Foldyna OK1MLG<br/>&copy; 2025-2026 Michael Morgan AA5SH<br/>&copy; 2025-2026 Kyle Boyle VE9KZ</p><p>Based on Qt %2<br/>%3<br/>%4<br/>%5</p><p>Icon by <a href='http://www.iconshock.com'>Icon Shock</a><br />Satellite images by <a href='http://www.nasa.gov'>NASA</a><br />ZoneDetect by <a href='https://github.com/BertoldVdb/ZoneDetect'>Bertold Van den Bergh</a><br />TimeZone Database by <a href='https://github.com/evansiroky/timezone-boundary-builder'>Evan Siroky</a> <h1>QLog %1</h1><p>&copy; 2019 Thomas Gatzweiler DL2IC<br/>&copy; 2021-2026 Ladislav Foldyna OK1MLG<br/>&copy; 2025-2026 Michael Morgan AA5SH<br/>&copy; 2025-2026 Kyle Boyle VE9KZ</p><p>Basé sur Qt %2<br/>%3<br/>%4<br/>%5</p><p>Icônes par <a href='http://www.iconshock.com'>Icon Shock</a><br />Images satellites par <a href='http://www.nasa.gov'>NASA</a><br />ZoneDetect par <a href='https://github.com/BertoldVdb/ZoneDetect'>Bertold Van den Bergh</a><br />Base de données TimeZone par <a href='https://github.com/evansiroky/timezone-boundary-builder'>Evan Siroky</a> About À propos N/A N/D MapWebChannelHandler Grid Grille/Locator Gray-Line Ligne de gris (Gray-Line) Beam Rayon (Beam) Aurora Aurore MUF MUF IBP IBP Chat Chat WSJTX - CQ WSJTX - Appels CQ Path Chemin/Trajet NewContactWidget Frequency Fréquence Callsign Indicatif <b>DUPE !!!</b> <b>DOUBLON !!!</b> RX: RX : TX: TX : MHz MHz 80m 80m RSTs RST envoyé RSTr RST reçu 59 59 Mode Mode Save Enregistrer Lookup the call on the web. The query URL can be changed in Settings -> Callbook Rechercher l'indicatif sur le web. L'URL peut être modifiée dans Réglages -> Callbook Web Web Time On Heure début Reset Réinit Date Date Duration Durée Info Infos &Details &Détails QSL Send Status Statut envoi QSL Paper Papier <b>Yes</b> - an outgoing QSL card has been sent; the QSO has been uploaded to, and accepted by, the online service<br/><b>No</b> - do not send an outgoing QSL card; do not upload the QSO to the online service<br/><b>Requested</b> - the contacted station has requested a QSL card; the contacted station has requested the QSO be uploaded to the online service<br/><b>Queued</b> - an outgoing QSL card has been selected to be sent; a QSO has been selected to be uploaded to the online service<br/> <b>Oui</b> - une carte QSL a été envoyée ; le QSO a été transmis et accepté par le service en ligne<br/><b>Non</b> - ne pas envoyer de QSL ; ne pas transmettre le QSO au service en ligne<br/><b>Demandé</b> - le correspondant a demandé une QSL ou un envoi vers un service en ligne<br/><b>En file d'attente</b> - la QSL ou l'envoi vers le service est programmé<br/> LoTW LoTW eQSL eQSL QSL Send via QSL envoyée via QSL via QSL via Propagation Mode Mode de propagation D&X Stats Stats D&X <b>DXCC Statistics</b> <b>Statistiques DXCC</b> <b>Station Statistics</b> <b>Statistiques de la station</b> M&y Station M&a Station Station Station Rig TRX Antenna Antenne My &Notes Mes &Notes Member: Membre : Expand/Collapse Développer/Réduire No Non Yes Oui Requested Demandé Queued En file d'attente Ignored Ignoré Bureau Bureau Direct Direct Electronic Électronique QLog Error Erreur QLog Callbook login failed Échec de connexion au Callbook LP LP (Long Path) New Entity! Nouvelle Entité ! New Band! Nouvelle Bande ! New Mode! Nouveau Mode ! New Band & Mode! Nouveau Bande & Mode ! New Slot! Nouveau Slot ! Worked Contacté (Worked) Confirmed Confirmé GE GE (Good Evening) GM GM (Good Morning) GA GA (Good Afternoon) m m Callbook search is inactive Recherche Callbook inactive Callbook search is active Recherche Callbook active Contest ID must be filled in to activate L'ID du Concours doit être renseigné pour l'activation two or four adjacent Maidenhead grid locators, each four characters long, (ex. EN98,FM08,EM97,FM07) deux ou quatre locators adjacents (Maidenhead), chacun de quatre caractères (ex. JN18,JN19...) the contacted station's DARC DOK (District Location Code) (ex. A01) le DOK (District Location Code) DARC de la station contactée (ex. A01) World Wide Flora & Fauna World Wide Flora & Fauna (WWFF) Special Activity Group Groupe d'Activité Spéciale Special Activity Group Information Informations du Groupe d'Activité Spéciale It is not the name of the contest but it is an assigned<br>Contest ID (ex. CQ-WW-CW for CQ WW DX Contest (CW)) Ce n'est pas le nom complet du concours mais l'ID attribué<br>(ex. CQ-WW-CW pour le CQ WW DX Contest CW) Blank Vide W W Description of the contacted station's equipment Description de l'équipement de la station contactée OmnirigRigDrv Rig 1 Transceiver 1 Rig 2 Transceiver 2 Initialization Error Erreur d'initialisation Rig status changed Le statut du poste a changé Rig is not connected Le transceiver n'est pas connecté OmnirigV2RigDrv Rig 1 Transceiver 1 Rig 2 Transceiver 2 Rig 3 Transceiver 3 Rig 4 Transceiver 4 Initialization Error Erreur d'initialisation Rig status changed Le statut du poste a changé Rig is not connected Le transceiver n'est pas connecté PSTRotDrv Rot 1 Rotor 1 Cannot bind a port Impossible de lier un port Cannot get IP Address for Impossible d'obtenir l'adresse IP pour No IPv4 Address for Pas d'adresse IPv4 pour Error Occurred Une erreur est survenue Operation Timeout Délai d'attente dépassé PaperQSLDialog Manage QSL Card Gérer la carte QSL Available QSLs QSL disponibles Copy the input file from the source folder to the QLog Internal QSL Storage folder.<br/>The original file remains unchanged in the source folder Copie le fichier d'entrée du dossier source vers le stockage QSL interne de QLog.<br/>Le fichier original reste inchangé dans le dossier source Import QSL Importer QSL Add File Ajouter un fichier Remove Retirer Delete Supprimer Delete QSL? Supprimer la QSL ? Open Ouvrir Toggle Favorite Ajouter/Retirer des favoris PlatformSettingsDialog Platform-specific Settings Paramètres spécifiques à la plateforme The database was exported from a different platform. Please verify or update the following settings. You can leave fields empty and configure them later in Settings. La base de données a été exportée depuis une plateforme différente. Veuillez vérifier ou mettre à jour les paramètres suivants. Vous pouvez laisser les champs vides et les configurer plus tard dans les Paramètres. Setting Paramètre Value Valeur Continue Continuer Select File Sélectionner le fichier All Files (*) Tous les fichiers (*) ProfileImageWidget Profile Image Image de profil QCoreApplication QLog Help Aide de QLog QMessageBox QLog Critical QLog Critique Cannot save a password for %1 to the Credential Store Impossible de sauvegarder un mot de passe pour %1 dans le gestionnaire d'identifiants Cannot get a password for %1 from the Credential Store Impossible de récupérer un mot de passe pour %1 depuis le gestionnaire d'identifiants QLog Warning Avertissement QLog Club List Update failed. Cannot remove old records Mise à jour de la liste des clubs échouée. Impossible de supprimer les anciens enregistrements Club List Update failed. Cannot plan new downloads Mise à jour de la liste des clubs échouée. Impossible de planifier les nouveaux téléchargements Unexpected Club List download. Canceling next downloads Téléchargement inattendu de la liste des clubs. Annulation des téléchargements suivants Unexpected Club List content for Contenu inattendu de la liste des clubs pour Network error. Cannot download Club List for Erreur réseau. Impossible de télécharger la liste des clubs pour QLog Error Erreur QLog QLog is already running QLog est déjà en cours d'exécution Failed to process pending database import. Échec du traitement de l'importation de la base de données en attente. The database was imported successfully, but the stored passwords could not be restored (decryption failed or the data is corrupted). All service passwords have been cleared and must be re-entered in Settings. La base de données a été importée avec succès, mais les mots de passe stockés n'ont pas pu être restaurés (échec du déchiffrement ou données corrompues). Tous les mots de passe des services ont été effacés et doivent être saisis à nouveau dans les Paramètres. Could not connect to database. Impossible de se connecter à la base de données. Could not export a QLog database to ADIF as a backup.<p>Try to export your log to ADIF manually Impossible d'exporter la base QLog vers ADIF pour sauvegarde.<p>Essayez d'exporter votre carnet de trafic en ADIF manuellement Database migration failed. La migration de la base de données a échoué. QLog Info Info QLog Activity name is already exists. Ce nom d'activité existe déjà. Rule name is already exists. Ce nom de règle existe déjà. Callsign Regular Expression is incorrect. L'expression régulière de l'indicatif est incorrecte. Comment Regular Expression is incorrect. L'expression régulière du commentaire est incorrecte. Cannot Update Alert Rules Impossible de mettre à jour les règles d'alerte DXC Server Name Error Erreur de nom de serveur DXC DXC Server address must be in format<p><b>[username@]hostname:port</b> (ex. hamqth.com:7300)</p> L'adresse du serveur DXC doit être au format<p><b>[utilisateur@]hôte:port</b> (ex. hamqth.com:7300)</p> DX Cluster Password Mot de passe DX Cluster Invalid Password Mot de passe invalide DXC Server Connection Error Erreur de connexion au serveur DXC Filename is empty Le nom de fichier est vide Cannot write to the file Impossible d'écrire dans le fichier QLog Information Information QLog Exported. Exporté. Exported %n contact(s). %n contact exporté. %n contacts exportés. Chat Error: Erreur de Chat : Filter name is already exists. Ce nom de filtre existe déjà. <b>Rig Error:</b> <b>Erreur Transceiver :</b> <b>Rotator Error:</b> <b>Erreur Rotor :</b> <b>CW Keyer Error:</b> <b>Erreur Keyer CW :</b> The fields <b>%0</b> will not be saved because the <b>%1</b> is not filled. Les champs <b>%0</b> ne seront pas sauvegardés car <b>%1</b> n'est pas renseigné. Your callsign is empty. Please, set your Station Profile Votre indicatif est vide. Veuillez configurer votre profil de station Cannot update QSO Filter Conditions Impossible de mettre à jour les conditions du filtre QSO Please, define at least one Station Locations Profile Veuillez définir au moins un profil d'emplacement de station WSJTX Multicast is enabled but the Address is not a multicast address. Le multicast WSJT-X est activé mais l'adresse n'est pas une adresse multicast. Loop detected. Raw UDP forward uses the same port as the WSJT-X receiving port. Boucle détectée. Le transfert UDP brut utilise le même port que le port de réception WSJT-X. Rig port must be a valid COM port.<br>For Windows use COMxx, for unix-like OS use a path to device Le port du transceiver doit être un port COM valide.<br>Pour Windows, utilisez COMxx, pour les OS de type Unix, utilisez un chemin vers le périphérique Rig PTT port must be a valid COM port.<br>For Windows use COMxx, for unix-like OS use a path to device Le port PTT doit être un port COM valide.<br>Pour Windows, utilisez COMxx, pour les OS de type Unix, utilisez un chemin vers le périphérique <b>TX Range</b>: Max Frequency must not be 0. <b>Plage TX</b> : La fréquence max ne doit pas être 0. <b>TX Range</b>: Max Frequency must not be under Min Frequency. <b>Plage TX</b> : La fréquence max ne doit pas être inférieure à la fréquence min. Rotator port must be a valid COM port.<br>For Windows use COMxx, for unix-like OS use a path to device Le port du rotor doit être un port COM valide.<br>Pour Windows, utilisez COMxx, pour les OS de type Unix, utilisez un chemin vers le périphérique CW Keyer port must be a valid COM port.<br>For Windows use COMxx, for unix-like OS use a path to device Le port du keyer CW doit être un port COM valide.<br>Pour Windows, utilisez COMxx, pour les OS de type Unix, utilisez un chemin vers le périphérique Cannot change the CW Keyer Model to <b>Morse over CAT</b><br>No Morse over CAT support for Rig(s) <b>%1</b> Impossible de changer le modèle de keyer CW en <b>Morse via CAT</b><br>Pas de support Morse via CAT pour le(s) poste(s) <b>%1</b> Cannot delete the CW Keyer Profile<br>The CW Key Profile is used by Rig(s): <b>%1</b> Impossible de supprimer le profil de keyer CW<br>Ce profil est utilisé par le(s) poste(s) : <b>%1</b> Callsign has an invalid format Le format de l'indicatif est invalide Operator Callsign has an invalid format L'indicatif de l'opérateur a un format invalide Gridsquare has an invalid format Le format du Locator est invalide VUCC Grids have an invalid format (must be 2 or 4 Gridsquares separated by ',') Les carrés VUCC ont un format invalide (doit être 2 ou 4 Locators séparés par des virgules) Country must not be empty Le pays ne doit pas être vide CQZ must not be empty La zone CQ ne doit pas être vide ITU must not be empty La zone ITU ne doit pas être vide QObject Importing Database Importation de la base de données Opening Database Ouverture de la base de données Backuping Database Sauvegarde de la base de données Migrating Database Migration de la base de données Starting Application Démarrage de l'application km km miles milles My Rig Mon transceiver Logging Station Callsign Indicatif de la station de log My Gridsquare Mon Locator Operator Name Nom de l'opérateur Operator Callsign Indicatif de l'opérateur My City Ma ville My Country Mon pays My County Mon département/comté My IOTA Mon IOTA My SOTA Mon SOTA My Special Interest Activity Mon activité spéciale My Spec. Interes Activity Info Info activité spéciale My VUCC Grids Mes carrés VUCC My WWFF Mon WWFF My POTA Ref Ma réf. POTA My DARC DOK Mon DOK (DARC) My ITU Ma zone ITU My CQZ Ma zone CQ My DXCC Mon DXCC Connection Refused Connexion refusée Host closed the connection L'hôte a fermé la connexion Host not found Hôte introuvable Timeout Délai d'attente dépassé Network Error Erreur Réseau Internal Error Erreur Interne Cannot connect to DXC Server <p>Reason <b>: Impossible de se connecter au serveur DXC <p>Raison <b> : <b>Imported</b>: %n contact(s) <b>Importé</b> : %n contact <b>Importés</b> : %n contacts <b>Warning(s)</b>: %n <b>Avertissement</b> : %n <b>Avertissements</b> : %n <b>Error(s)</b>: %n <b>Erreur</b> : %n <b>Erreurs</b> : %n Not a valid QLog database Base de données QLog invalide Database version too new (requires newer QLog version) Version de la base trop récente (nécessite une version plus récente de QLog) Database is not QLog Export file Le fichier n'est pas un export QLog TQSL Path Chemin TQSL (Flatpak internal path) (chemin interne Flatpak) Rig Poste Rig PTT PTT Poste Rig rigctld rigctld Poste Rotator Rotor CW Keyer Keyer CW TOTAL Worked TOTAL contactés TOTAL Confirmed TOTAL confirmés Confirmed Confirmé Worked QRZCallbook QRZ.com QRZ.com QRZUploader General Error Erreur générale QSLGalleryDialog QSL Card Gallery Galerie de cartes QSL Search by callsign... Chercher par indicatif... Sort by: Trier par : Export Filtered Exporter filtrés Date (Newest) Date (plus récent) Date (Oldest) Date (plus ancien) Callsign (A-Z) Indicatif (A-Z) Callsign (Z-A) Indicatif (Z-A) %n QSL card(s) %n carte QSL %n cartes QSL All QSL Cards Toutes les cartes QSL Favorites Favoris By Country Par Pays By Date Par Date By Band Par Bande By Mode Par Mode By Continent Par Continent Remove from Favorites Retirer des favoris Add to Favorites Ajouter aux favoris Open Ouvrir Save... Enregistrer... Save QSL Card Enregistrer la carte QSL Export QSL Cards Exporter les cartes QSL Exported %1 of %2 cards %1 cartes sur %2 exportées QSLImportStatDialog QSL Import Summary Résumé de l'importation QSL Summary Résumé Downloaded: Téléchargées : Updated: Mises à jour : Unmatched: Non appariées : Errors: Erreurs : Details Détails New QSLs: Nouvelles QSL : Updated QSOs: QSO mis à jour : Unmatched QSLs: QSL non appariées : QSLPrintLabelDialog Print QSL Labels Imprimer les étiquettes QSL Filter Filtrer Date Range Plage de dates My Callsign Mon indicatif Station Profile Profil de station QSL Sent QSL Envoyée User Filter Filtre utilisateur Label Template Modèle d’étiquette Page Size: Taille de page: Columns: Colonne: Rows: Ligne: Label Width: Largeur de l’étiquette : Label Height: Hauteur de l’étiquette: Left Margin: Marge gauche: Top Margin: Marge supérieure: H Spacing: Espacement horizontal: V Spacing: Espacement vertical: Label Appearance Apparence de l’étiquette Print Label Borders Imprimer les bordures des étiquettes QSOs per Label: QSO par étiquette: Footer Left Text: Texte de pied de page gauche: Footer Right Text: Texte de pied de page droit: Skip Label: Ignorer l’étiquette: Sans Font: Police sans-serif: Mono Font: Police monospace: Callsign Size: Taille de l’indicatif: "To Radio" Size: Taille « To Radio » : "To Radio" Text: Texte « To Radio » : Header Size: Taille de l’en-tête: Data Size: Taille des données: Date Header Text: Texte d’en-tête de date: Date Format: Format de date: Time Header Text: Texte d’en-tête de l’heure: Band Header Text: Texte d’en-tête de bande: Mode Header Text: Texte d’en-tête du mode: QSL Header Text: Texte d’en-tête QSL: Extra Column: Colonne supplémentaire: Extra Column Text Texte de la colonne supplémentaire (DB column name) (nom de colonne BD) No matching QSOs found Aucun QSO correspondant trouvé Page 0 of 0 Page 0 sur 0 Labels: 0 (0 pages) Étiquettes : 0 (0 pages) Print Imprimer Export as PDF Exporter en PDF Custom Personnalisé Empty Vide QSOs matching this station profile QSO correspondant à ce profil de station Labels: %1 (%2 pages) Étiquettes : %1 (%2 pages) Page %1 of %2 Page %1 sur %2 Export PDF Exporter en PDF PDF Files (*.pdf) Fichiers PDF (*.pdf) Mark as Sent Marquer comme envoyé Mark printed/exported QSOs as sent? Marquer les QSO imprimés/exportés comme envoyés ? QSODetailDialog dd/MM/yyyy HH:mm:ss dd/MM/yyyy HH:mm:ss RSTs RSTs RSTr RSTr Mode Mode Time On Heure début Time Off Heure fin Callsign Indicatif TX: TX : Blank Vide MHz MHz RX: RX : Frequency Fréquence Band Bande QTH QTH Name Nom Gridsquare Locator Comment Commentaire My Notes Mes notes about:blank about:blank &Details &Détails Country Pays Cont Cont. ITU ITU CQ CQ State État County Comté Age Âge AF AF AN AN AS AS EU EU NA NA OC OC SA SA VUCC VUCC two or four adjacent Gridsquares, each four characters long, (ex. EN98,FM08,EM97,FM07) deux ou quatre locators adjacents, de quatre caractères chacun (ex. JN18,JN19,JN28,JN29) IOTA IOTA POTA POTA SOTA SOTA WWFF WWFF SIG SIG SIG Info Info SIG FISTS FISTS SKCC SKCC Ten-Ten Ten-Ten UKSMG UKSMG DOK DOK the contacted station's DARC DOK (District Location Code) (ex. A01) le DOK (District Location Code) DARC de la station contactée (ex. A01) FISTS CC FISTS CC E-Mail E-mail URL URL Propagation Mode Mode de propagation Satellite Name Nom du satellite Satellite Mode Mode satellite D&X Stats Stats D&X <b>DXCC Statistics</b> <b>Statistiques DXCC</b> <b>Station Statistics</b> <b>Statistiques de la station</b> M&y Station M&a station Operator Name Nom de l'opérateur Operator Callsign Indicatif de l'opérateur Sig Info Info Sig Rig Équipement Antenna Antenne Power Puissance W W &QSL &QSL Show QSL Card Afficher la carte QSL <b>Yes</b> - an incoming QSL card has been received; the QSO has been confirmed by the online service<br/><b>No</b> - an incoming QSL card has not been received; the QSO has not been confirmed by the online service<br/><b>Requested</b> - the logging station has requested a QSL card; the logging station has requested the QSO be uploaded to the online service<br/> <b>Oui</b> - une carte QSL entrante a été reçue ; le QSO a été confirmé par le service en ligne<br/><b>Non</b> - aucune carte QSL n'a été reçue ; le QSO n'a pas été confirmé par le service en ligne<br/><b>Demandée</b> - la station a demandé une carte QSL ou le téléchargement du QSO vers le service en ligne<br/> - - QSL Sent via QSL envoyée via QSL via QSL via <b>Yes</b> - an outgoing QSL card has been sent; the QSO has been uploaded to, and accepted by, the online service<br/><b>No</b> - do not send an outgoing QSL card; do not upload the QSO to the online service<br/><b>Requested</b> - the contacted station has requested a QSL card; the contacted station has requested the QSO be uploaded to the online service<br/><b>Queued</b> - an outgoing QSL card has been selected to be sent; a QSO has been selected to be uploaded to the online service<br/> <b>Oui</b> - une carte QSL sortante a été envoyée ; le QSO a été accepté par le service en ligne<br/><b>Non</b> - ne pas envoyer de carte QSL ; ne pas envoyer le QSO au service en ligne<br/><b>Demandée</b> - la station contactée a demandé une carte QSL ou l'envoi vers le service en ligne<br/><b>En attente</b> - une carte QSL ou un envoi vers le service en ligne a été mis en file d'attente<br/> Received Reçue eQSL eQSL Manage QSL Card Gérer la carte QSL Paper Papier Sent Envoyée QSLr Message Message QSLr LoTW LoTW QSLs Message Message QSLs &Contest &Concours Contest ID ID du concours RcvNr N° Reçu RcvExch Échange Reçu SendNr N° Envoyé SendExch Échange Envoyé Member: Membre : &Reset &Réinitialiser &Lookup &Recherche No Non Yes Oui Requested Demandée Queued En attente Ignored Ignorée Bureau Bureau Direct Direct Electronic Électronique Submit changes Soumettre les modifications Really submit all changes? Voulez-vous vraiment soumettre toutes les modifications ? QLog Error Erreur QLog Cannot save all changes - internal error Impossible de sauvegarder les modifications - erreur interne Cannot save all changes - try to reset all changes Impossible de sauvegarder - essayez de réinitialiser les modifications QSO Detail Détail du QSO Edit QSO Modifier le QSO Downloading eQSL Image Téléchargement de l'image eQSL Cancel Annuler eQSL Download Image failed: Échec du téléchargement de l'image eQSL : DX Callsign must not be empty L'indicatif DX ne doit pas être vide DX callsign has an incorrect format Le format de l'indicatif DX est incorrect TX Frequency or Band must be filled La fréquence TX ou la bande doit être renseignée TX Band should be La bande TX devrait être RX Band should be La bande RX devrait être DX Grid has an incorrect format Le format du locator DX est incorrect Based on callsign, DXCC Country is different from the entered value - expecting D'après l'indicatif, le pays DXCC diffère de la valeur saisie - attendu : Based on callsign, DXCC Continent is different from the entered value - expecting D'après l'indicatif, le continent DXCC diffère de la valeur saisie - attendu : Based on callsign, DXCC ITU is different from the entered value - expecting D'après l'indicatif, la zone ITU diffère de la valeur saisie - attendu : Based on callsign, DXCC CQZ is different from the entered value - expecting D'après l'indicatif, la zone CQ diffère de la valeur saisie - attendu : VUCC has an incorrect format Le format VUCC est incorrect Based on Frequencies, Sat Mode should be D'après les fréquences, le mode Sat devrait être blank vide Sat name must not be empty Le nom du satellite ne doit pas être vide Own Callsign must not be empty Votre indicatif ne doit pas être vide Own callsign has an incorrect format Le format de votre indicatif est incorrect Own VUCC Grids have an incorrect format Le format de vos locators VUCC est incorrect Based on own callsign, own DXCC ITU is different from the entered value - expecting D'après votre indicatif, votre zone ITU diffère de la valeur saisie - attendu : Based on own callsign, own DXCC CQZ is different from the entered value - expecting D'après votre indicatif, votre zone CQ diffère de la valeur saisie - attendu : Based on own callsign, own DXCC Country is different from the entered value - expecting D'après votre indicatif, votre pays DXCC diffère de la valeur saisie - attendu : Based on SOTA Summit, QTH does not match SOTA Summit Name - expecting D'après le sommet SOTA, le QTH ne correspond pas au nom du sommet - attendu : Based on SOTA Summit, Grid does not match SOTA Grid - expecting D'après le sommet SOTA, le locator ne correspond pas au locator SOTA - attendu : Based on POTA record, QTH does not match POTA Name - expecting D'après la référence POTA, le QTH ne correspond pas au nom POTA - attendu : Based on POTA record, Grid does not match POTA Grid - expecting D'après la référence POTA, le locator ne correspond pas au locator POTA - attendu : Based on SOTA Summit, my QTH does not match SOTA Summit Name - expecting D'après le sommet SOTA, mon QTH ne correspond pas au nom du sommet - attendu : Based on SOTA Summit, my Grid does not match SOTA Grid - expecting D'après le sommet SOTA, mon locator ne correspond pas au locator SOTA - attendu : Based on POTA record, my QTH does not match POTA Name - expecting D'après la référence POTA, mon QTH ne correspond pas au nom POTA - attendu : Based on POTA record, my Grid does not match POTA Grid - expecting D'après la référence POTA, mon locator ne correspond pas au locator POTA - attendu : LoTW Sent Status to <b>No</b> does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blank Le statut d'envoi LoTW sur <b>Non</b> est incohérent si une date d'envoi QSL est définie. Mettez la date au 01/01/1900 pour laisser le champ vide Date should be present for LoTW Sent Status <b>Yes</b> Une date doit être renseignée si le statut d'envoi LoTW est <b>Oui</b> eQSL Sent Status to <b>No</b> does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blank Le statut d'envoi eQSL sur <b>Non</b> est incohérent si une date d'envoi QSL est définie. Mettez la date au 01/01/1900 pour laisser le champ vide Date should be present for eQSL Sent Status <b>Yes</b> Une date doit être renseignée si le statut d'envoi eQSL est <b>Oui</b> Paper Sent Status to <b>No</b> does not make any sense if QSL Sent Date is set. Set Date to 1.1.1900 to leave the date field blank Le statut d'envoi Papier sur <b>Non</b> est incohérent si une date d'envoi QSL est définie. Mettez la date au 01/01/1900 pour laisser le champ vide Date should be present for Paper Sent Status <b>Yes</b> Une date doit être renseignée si le statut d'envoi Papier est <b>Oui</b> Callbook error: Erreur du callbook : <b>Warning: </b> <b>Attention : </b> Validation Validation Yellow marked fields are invalid.<p>Nevertheless, save the changes?</p> Les champs marqués en jaune sont invalides.<p>Sauvegarder tout de même les modifications ?</p> &Save &Sauvegarder &Edit &Modifier QSOFilterDetail QSO Filter Detail Détail du filtre QSO Filter Name: Nom du filtre : Find QSO which match Trouver les QSO correspondant à All the following conditions Toutes les conditions suivantes Any of the following conditions L'une des conditions suivantes Add Condition Ajouter une condition Equal Égal à Not Equal Différent de Contains Contient Not Contains Ne contient pas Greater Than Supérieur à Less Than Inférieur à Starts with Commence par RegExp Exp. Régulière Remove Supprimer Must not be empty Ne doit pas être vide QSOFilterDialog QSO Filters Filtres de QSO Filters Filtres Add Ajouter Edit Modifier Remove Supprimer Rig No Rig Profile selected Aucun profil de déca (Rig) sélectionné Rigctld Error Erreur Rigctld Initialization Error Erreur d'initialisation Internal Error Erreur interne Cannot open Rig Impossible d'ouvrir le poste RigWidget Form Formulaire RX RX Disconnected Déconnecté MHz MHz Disable Split Désactiver le split RIT: 0.00000 MHz RIT : 0.00000 MHz XIT: 0.00000 MHz XIT : 0.00000 MHz PWR: %1W PWR : %1W RigctldAdvancedDialog Rigctld Advanced Settings Paramètres avancés Rigctld Rigctld Path: Chemin Rigctld : Leave empty for auto-detection Laisser vide pour une auto-détection Browse Parcourir Auto-detect Rigctld path Auto-détecter le chemin de Rigctld Auto-Detect Auto-détection Rigctld Version: Version de Rigctld : Additional Arguments: Arguments supplémentaires : e.g. -v -v for verbose logging ex: -v -v pour un log verbeux Cannot be changed Ne peut pas être modifié Auto Detect Auto-détection rigctld was not found on this system. Please install Hamlib or specify the path manually. rigctld n'a pas été trouvé sur ce système. Veuillez installer Hamlib ou spécifier le chemin manuellement. Executable (*.exe);;All files (*.*) Exécutable (*.exe);;Tous les fichiers (*.*) All files (*) Tous les fichiers (*) Select rigctld executable Sélectionner l'exécutable rigctld Not found Non trouvé RigctldManager rigctld executable not found in /app/bin/. This should not happen in Flatpak build. L'exécutable rigctld est introuvable dans /app/bin/. Cela ne devrait pas arriver avec un build Flatpak. rigctld executable not found. Please install Hamlib or specify the path in Advanced settings. L'exécutable rigctld est introuvable. Veuillez installer Hamlib ou spécifier le chemin dans les paramètres avancés. Hamlib major version mismatch: QLog was compiled with Hamlib %1 but rigctld reports version %2.%3.%4. Rig model IDs are incompatible between major versions. Discordance de version majeure de Hamlib : QLog a été compilé avec Hamlib %1 mais rigctld indique la version %2.%3.%4. Les ID de modèles de postes sont incompatibles entre versions majeures. Port %1 is already in use. Another rigctld or application may be running on this port. Le port %1 est déjà utilisé. Une autre instance de rigctld ou une autre application utilise probablement ce port. rigctld started but not responding on port %1. rigctld est démarré mais ne répond pas sur le port %1. Failed to start rigctld: %1 %2 Échec du démarrage de rigctld : %1 %2 rigctld crashed. rigctld a planté. rigctld timed out. Délai d'attente dépassé pour rigctld. Write error with rigctld. Erreur d'écriture avec rigctld. Read error with rigctld. Erreur de lecture avec rigctld. Unknown rigctld error. Erreur rigctld inconnue. Rotator No Rotator Profile selected Aucun profil de rotor sélectionné Initialization Error Erreur d'initialisation Internal Error Erreur interne Cannot open Rotator Impossible d'ouvrir le rotor RotatorWidget Form Formulaire Az: Az : ° ° Goto Aller à Previous Button Profile Profil de boutons précédent Next Button Profile Profil de boutons suivant QSO LP QSO LP QSO Long Path QSO Grand Chemin (LP) QSO SP QSO SP QSO Short Path QSO Petit Chemin (SP) SettingsDialog Settings Paramètres Station Station Profiles Profils SOTA SOTA IOTA IOTA SOTA (Optional parameter) SOTA (paramètre optionnel) SIG (Optional parameter). SIG (paramètre optionnel). ITU Zone ITU CQZ Zone CQ County Comté IOTA (Optional parameter) IOTA (paramètre optionnel) QTH Name (Optional parameter) Nom du QTH (paramètre optionnel) World Wide Flora & Fauna (Optional parameter) WWFF (paramètre optionnel) Operator name (Optional parameter) Nom de l'opérateur (paramètre optionnel) POTA POTA VUCC Grids (Optional parameter). Ex. EN98,FM08,EM97,FM07 Carrés VUCC (optionnel). Ex: JN18,JN19,IN98 Country Pays Station County Location (Optional parameter) Localisation du comté (paramètre optionnel) SIG Info Info SIG Station Gridsquare (Mandatory parameter) Localisateur de la station (obligatoire) QTH QTH Profile Name Nom du profil WWFF WWFF List of all available Station Profiles Liste de tous les profils de station disponibles SIG Information (Optional parameter) Information SIG (paramètre optionnel) Profile name that is used as the alias for the Callsign, Gridsquare, Operator name, and QTH (required parameter) Nom du profil utilisé comme alias pour l'indicatif, le localisateur, l'opérateur et le QTH (obligatoire) Callsign (Mandatory parameter) Indicatif (paramètre obligatoire) Callsign of operator (Optional parameter, if different from station callsign) Indicatif de l'opérateur (optionnel, si différent de celui de la station) Operator Name Nom de l'opérateur VUCC VUCC Station Callsign Indicatif de la station Gridsquare Locator SIG SIG Operator Callsign Indicatif de l'opérateur Add Ajouter Delete Supprimer DOK DOK Equipment Équipement Antennas Antennes Profiles Profils Description Description Azimuth Beamwidth Largeur de faisceau azimutal Azimuth Offset Offset azimutal Valid range value is 0° - 100° (0° Unspecified) La plage valide est 0° - 100° (0° = non spécifié) Unspecified Non spécifié ° ° List of all available Antennas Liste de toutes les antennes disponibles CW Keyers Clés télégraphiques (CW) Keyer Profiles Profils de manipulateur List of all available CW Keyers Liste de tous les manipulateurs CW disponibles Danger Zone Zone dangereuse <b>⚠ This is a danger zone. Proceed with caution, as actions performed here cannot be undone and may have a significant impact on your log.</b> <b>⚠ Ceci est une zone dangereuse. Procédez avec prudence, car les actions effectuées ne peuvent pas être annulées et peuvent avoir un impact important sur votre journal.</b> Delete All QSOs Supprimer tous les QSOs Delete All Passwords from the Secure Store Supprimer tous les mots de passe du coffre sécurisé Model Modèle Keyer Mode Mode du manipulateur Swap Paddles Inverser les palettes Paddle Only Sidetone Sidetone (palettes uniquement) Sidetone Freq: Fréq. sidetone : Default Speed Vitesse par défaut N/A N/D WPM MPM (WPM) Port Port Use COMxx for Window or path to COM port under Unix-like OS Utiliser COMxx pour Windows ou le chemin vers le port sous Linux/Unix Baudrate Vitesse (Bauds) 115200 115200 57600 57600 38400 38400 19200 19200 9600 9600 4800 4800 2400 2400 1200 1200 Host Name Nom d'hôte HamLib does not support to change a destination port. HamLib ne permet pas de changer le port de destination. CW Shortcut Profiles Profils de raccourcis CW List of all available CW Shortcuts Profiles Liste de tous les profils de raccourcis CW disponibles F1 F1 Short Desciption of the Button (up to 7 chars) Description courte du bouton (7 car. max) F2 F2 F3 F3 F4 F4 F5 F5 F6 F6 F7 F7 Rigs Transceivers Interface Interface Minimum and maximum TX frequencies. Specific ranges are derived from allowed Band in the Setting. Fréquences TX mini et maxi. Les plages spécifiques sont dérivées des bandes autorisées dans les paramètres. TX Range Plage TX - - Offsets Offsets Enter manually RIT or Transverter Offset Entrer manuellement l'offset RIT ou Transverter MHz MHz Enter manually XIT or Transverter offset Entrer manuellement l'offset XIT ou Transverter TX: TX : Default PWR Puissance par déf. Enter default PWR (ex. when Rig is disconnected) Entrer la puissance par défaut (ex: si poste déconnecté) Blank Vide W W Assigned CW Keyer Manipulateur CW assigné Rig Features Fonctionnalités du poste Mode Mode VFO VFO Freq Fréq. QSY Wiping Effacement sur QSY Power Puissance PTT State État du PTT TX Offset (XIT) Offset TX (XIT) RX Offset (RIT) Offset RX (RIT) Split CW Keyer Speed Vitesse manipulateur CW CW Speed Sync Synchro vitesse CW DX Spots to Rig Spots DX vers le poste Start rigctld daemon to share rig with other applications (e.g. WSJT-X) Lancer le démon rigctld pour partager le poste avec d'autres applis (ex: WSJT-X) Share Rig via port Partager le poste via le port Advanced... Avancé... Rig Port Port du poste CIV Addr Adresse CI-V Auto Auto Flow Control Contrôle de flux Parity Parité PTT Type Type de PTT PTT Port Port PTT RTS RTS DTR DTR Data Bits Bits de données 8 8 7 7 6 6 5 5 Stop Bits Bits d'arrêt 1 1 2 2 Port Type Type de port Poll Interval Intervalle d'interrogation ms ms List of all available Rigs Liste de tous les transceivers disponibles Rotators Rotors Serial Série Network Réseau User Buttons Profiles Profils de boutons utilisateur Button 1 Bouton 1 Button 2 Bouton 2 Button 3 Bouton 3 Button 4 Bouton 4 Callbook Nomenclature (Callbook) Query Order Ordre de requête Primary Primaire Secondary Secondaire HamQTH HamQTH Username Utilisateur Password Mot de passe QRZ.com QRZ.com <b>Notice:</b> At least a QRZ XML Subscription is recommended to access detailed information. Without a subscription, you will obtain limited data from QRZ, such as missing grid and other fields. <b>Note :</b> Un abonnement QRZ XML est recommandé pour accéder aux informations détaillées. Sans abonnement, les données seront limitées (localisateur ou autres champs manquants). Web Lookup Button Bouton de recherche Web URL URL Specify the URL to use for quick search. The <DXCALL> macro will be replaced by the current callsign Spécifier l'URL pour la recherche rapide. La macro <DXCALL> sera remplacée par l'indicatif courant Test URL with your Callsign Tester l'URL avec votre indicatif Test Test Clubs Clubs Active Lists Listes actives Sync && QSL Sync && QSL ClubLog ClubLog E-Mail E-Mail QSOs are uploaded immediately Les QSOs sont envoyés immédiatement Immediately Upload Envoi immédiat eQSL eQSL HRDLog HRDLog Callsign Indicatif It is not a password. It is the upload code received via email after the registration to HRDLOG..net Ce n'est pas un mot de passe. C'est le code d'envoi reçu par email après l'inscription sur HRDLOG.net Upload Code Code d'envoi If it is enabled and Rig is connected then QLog periodically sends On-Air messages to HRDLog Si activé et le poste connecté, QLog envoie périodiquement des messages "On-Air" à HRDLog Send On-Air Envoyer "On-Air" LoTW LoTW TQSL Path Chemin TQSL Browse Parcourir Using an internal TQSL instance Utiliser une instance TQSL interne Default API Key Clé API par défaut Callsign-specific API Keys Clés API par indicatif Wavelog Wavelog API Key Clé API Endpoint Point d'accès (Endpoint) Others Autres DXCC DXCC Status Confirmed By Statut confirmé par Paper Papier Chat Chat <b>Security Notice:</b> QLog stores all passwords in the Secure Storage. Unfortunately, ON4KST uses a protocol where this password is sent over an unsecured channel as plaintext.</p><p>Please exercise caution when choosing your password for this service, as your password is sent over an unsecured channel in plaintext form.</p> <b>Note de sécurité :</b> QLog stocke les mots de passe de manière sécurisée. Hélas, ON4KST utilise un protocole où le mot de passe transite en clair sur un canal non sécurisé.</p><p>Soyez prudent lors du choix de votre mot de passe pour ce service.</p> Bands Bandes Modes Modes The '>' character is interpreted as a marker for the initial cursor position in the Report column. <br/>Ex.: '5>9' means the cursor will be positioned on the second character Le caractère '>' sert de marqueur pour la position initiale du curseur dans la colonne Report. <br/>Ex: '5>9' positionnera le curseur sur le second caractère. Wsjtx WSJT-X Raw UDP Forward Redirection UDP brute <p>List of IP addresses to which QLog forwards raw UDP WSJT-X packets.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste des adresses IP vers lesquelles QLog redirige les paquets UDP bruts de WSJT-X.</p>Les adresses sont séparées par des espaces (format IP:PORT). ex. 192.168.1.1:1234 192.168.2.1:1234 ex: 192.168.1.1:1234 192.168.2.1:1234 Port Port Port where QLog listens an incoming traffic from WSJT-X Port sur lequel QLog écoute le trafic provenant de WSJT-X Join Multicast Rejoindre le Multicast Enable/Disable Multicast option for WSJTX Activer/Désactiver l'option Multicast pour WSJT-X Multicast Address Adresse Multicast <DXCALL> = DX Callsign <NAME> = DX Operator Name <RST> = Report 599 <RSTN> = Report 5NN <GREETING> = Greenting GM/GA/GE <QTH> = QTH <MYCALL> = My Callsign <MYNAME> = My Name <MYQTH> = My QTH <MYLOCATOR> = My Gridsquare <MYGRID> = My Gridsquare <MYSIG> = My SIG <MYSIGINFO> = My SIG Information <MYIOTA> = My IOTA <MYSOTA> = MY SOTA <MYWWFT> = My WWFT <MYVUCC> = MY VUCC <MYPWR> = My Power in W <EXCHSTR> = Contest Exchange Message <EXCHNR> = Contest Exchange Serial Number <EXCHNRN> = Contest Exchange Serial Number (9→N, 0→T) <+> = Speed +5 WPM (<++> = +10 WPM, etc.) <-> = Speed -5 WPM (<--> = -10 WPM, etc.) <DXCALL> = Indicatif du correspondant <NAME> = Prénom du correspondant <RST> = Report 599 <RSTN> = Report 5NN <GREETING> = Salutations (GM/GA/GE) <QTH> = QTH distant <MYCALL> = Mon indicatif <MYNAME> = Mon prénom <MYQTH> = Mon QTH <MYLOCATOR> = Mon localisateur (Grid) <MYGRID> = Mon localisateur (Grid) <MYSIG> = Mon SIG <MYSIGINFO> = Mes infos SIG <MYIOTA> = Mon IOTA <MYSOTA> = Mon SOTA <MYWWFT> = Mon WWFF <MYVUCC> = Mon VUCC <MYPWR> = Ma puissance (W) <EXCHSTR> = Message d'échange concours <EXCHNR> = Numéro de série concours <EXCHNRN> = Numéro de série concours (9→N, 0→T) <+> = Vitesse +5 MPM (<++> = +10 MPM, etc.) <-> = Vitesse -5 MPM (<--> = -10 MPM, etc.) RX: RX : Leave empty for auto-detection Laisser vide pour l'auto-détection Auto-detect TQSL path Auto-détection du chemin TQSL Auto-Detect Auto-détection TQSL Version Version de TQSL Specify Multicast Address. <br>On some Linux systems it may be necessary to enable multicast on the loop-back network interface. Spécifier l'adresse Multicast. <br>Sur certains systèmes Linux, il peut être nécessaire d'activer le multicast sur l'interface de boucle locale (loop-back). TTL TTL Time-To-Live determines the range<br> over which a multicast packet is propagated in your intranet. Le TTL (Time-To-Live) détermine la portée de propagation<br> d'un paquet multicast sur votre intranet. Color CQ Spots Colorer les spots CQ Enable/Disable sending color-coded status indicators back to WSJT-X for each callsign calling CQ Activer/Désactiver l'envoi d'indicateurs d'état colorés à WSJT-X pour chaque indicatif appelant CQ Notifications Notifications LogID LogID <p>Assigned LogID to the current log.</p>The LogID is sent in the Network Nofitication messages as a unique instance identified.<p> The ID is generated automatically and cannot be changed</> <p>LogID assigné au carnet actuel.</p>Le LogID est envoyé dans les notifications réseau comme identifiant unique d'instance.<p>L'ID est généré automatiquement et ne peut être modifié.</p> DX Spots Spots DX <p> List of IP addresses to which QLog sends UDP notification packets with DX Cluster Spots.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP des spots du cluster DX.</p>Les adresses sont séparées par des espaces (format IP:PORT). Spot Alerts Alertes de spots <p> List of IP addresses to which QLog sends UDP notification packets about user Spot Alerts.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP pour les alertes de spots utilisateur.</p>Les adresses sont séparées par des espaces (format IP:PORT). QSO Changes Modifications de QSO <p> List of IP addresses to which QLog sends UDP notification packets about a new/updated/deleted QSO in the log.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP lors de l'ajout/modification/suppression d'un QSO.</p>Les adresses sont séparées par des espaces (format IP:PORT). Wsjtx CQ Spots Spots CQ WSJT-X <p> List of IP addresses to which QLog sends UDP notification packets with WSJTX CQ Spots.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP des spots CQ de WSJT-X.</p>Les adresses sont séparées par des espaces (format IP:PORT). Rig Status État du poste <p> List of IP addresses to which QLog sends UDP notification packets when Rig State changes.</p>The IP addresses are separated by a space and have the form IP:PORT <p>Liste des adresses IP vers lesquelles QLog envoie les notifications UDP lors d'un changement d'état du poste.</p>Les adresses sont séparées par des espaces (format IP:PORT). GUI Interface (GUI) Date Format Format de date System Système Custom Personnalisé <a href="https://doc.qt.io/qt-6/qdate.html#fromString-1">Time Format Documentation</a> <a href="https://doc.qt.io/qt-6/qdate.html#fromString-1">Documentation du format d'heure</a> Time Format Format d'heure 24-hour 24 heures AM/PM AM/PM Unit System Système d'unités Metric Métrique Imperial Impérial Special - Omnirig Spécial - Omnirig Cannot be changed Ne peut pas être modifié Name Nom Report Report State État / Province Start (MHz) Début (MHz) End (MHz) Fin (MHz) SAT Mode Mode SAT Disabled Désactivé None Aucun Hardware Matériel (Hard) Software Logiciel (Soft) No Non Even Pair Odd Impair Mark Mark Space Space Dummy Dummy (fictif) Morse Over CAT Morse via CAT WinKey WinKey CWDaemon CWDaemon FLDigi FLDigi Single Paddle Simple palette IAMBIC A IAMBIC A IAMBIC B IAMBIC B Ultimate Ultimatice High Haut (High) Low Bas (Low) Press <b>Modify</b> to confirm the profile changes or <b>Cancel</b>. Appuyez sur <b>Modifier</b> pour confirmer les changements de profil ou sur <b>Annuler</b>. Modify Modifier Must not be empty Ne doit pas être vide Select File Sélectionner un fichier Auto Detect Auto-détection TQSL was not found on this system. Please install TQSL or specify the path manually. TQSL n'a pas été trouvé sur ce système. Veuillez installer TQSL ou spécifier le chemin manuellement. Not found Non trouvé Rig sharing is only available for Hamlib driver Le partage du poste n'est disponible qu'avec le pilote Hamlib Rig sharing is not available for network connection Le partage du poste n'est pas disponible pour les connexions réseau Delete Passwords Supprimer les mots de passe All passwords have been deleted Tous les mots de passe ont été supprimés Deleting all QSOs... Suppression de tous les QSOs... Error Erreur Failed to delete all QSOs. Impossible de supprimer tous les QSOs. members membres Required internet connection during application start Connexion internet requise au démarrage de l'application ShortcutEditorModel Description Description Shortcut Raccourci Conflict with a built-in shortcut Conflit avec un raccourci intégré Conflict with a user-defined shortcut Conflit avec un raccourci utilisateur ShowUploadDialog QSOs to Upload QSO à envoyer Selected QSO QSO sélectionné Upload Envoyer SmartSearchBox Search Rechercher StatisticsWidget Statistics Statistiques Date Range Plage de dates to au Band Bande User Filter Filtre utilisateur Confirmed by Confirmé par LoTW LoTW eQSL eQSL Paper Papier Graph Type Type de graphique QSOs per QSO par Percents Pourcentages Top 10 Top 10 Histogram Histogramme Show on Map Afficher sur la carte My Callsign Mon indicatif My Gridsquare Mon locator My Rig Ma station My Antenna Mon antenne Sun Dim Mon Lun Tue Mar Wed Mer Thu Jeu Fri Ven Sat Sam Not specified Non spécifié Confirmed Confirmé Not Confirmed Non confirmé No User Filter Aucun filtre utilisateur Over 50000 QSOs. Display them? Plus de 50 000 QSO. Les afficher ? Rendering QSOs... Génération des QSO... Year Année Month Mois Day in Week Jour de la semaine Hour Heure Mode Mode Continent Continent Propagation Mode Mode de propagation Confirmed / Not Confirmed Confirmé / Non confirmé Countries Pays Big Gridsquares Grands carrés Locator Distance Distance QSOs QSO Confirmed/Worked Grids Locators confirmés/contactés ODX ODX All Tout TCIRigDrv Rig 0 Poste 0 Rig 1 Poste 1 Rig 2 Poste 2 Rig 3 Poste 3 Error Occurred Une erreur est survenue Rig status changed Le statut du poste a changé Rig is not connected Le poste n'est pas connecté TimestampFormatDelegate Blank Vide ToAllTableModel Time Heure Spotter Spotter Message Message UploadQSODialog Upload QSOs Envoyer les QSO eQSL eQSL LoTW LoTW QRZ.com QRZ.com Clublog Clublog HRDLog HRDLog Wavelog Wavelog Filters Filtres Station Profile Profil de station My Callsign Mon indicatif Gridsquare Locator Include QSOs Status Inclure le statut des QSO Under normal circumstances this status means <b>"do not send"</b>.<br/>However, it may sometimes be wanted to ignore this setting when sending a QSL. En temps normal, ce statut signifie <b>"ne pas envoyer"</b>.<br/>Toutefois, il peut être souhaitable d'ignorer ce réglage lors de l'envoi d'une QSL. No Non Under normal circumstances this status means <b>"Ignore/Invalid"</b>.<br/>However, it may sometimes be wanted to ignore this setting when sending a QSL. En temps normal, ce statut signifie <b>"Ignorer/Invalide"</b>.<br/>Toutefois, il peut être souhaitable d'ignorer ce réglage lors de l'envoi d'une QSL. Ignore Ignorer None Aucun QSLs Message Message des QSL Comment Commentaire QSL Message Field Champ de message QSL QTH Profile Profil QTH This option deletes all QSOs in the Clublog<br>and based on filter, it uploads all QSOs regardless of their status. Cette option supprime tous les QSO sur Clublog<br>et, selon le filtre, renvoie tous les QSO quel que soit leur statut. Clear Clublog and reupload QSOs Vider Clublog et renvoyer les QSO LoTW / TQSL LoTW / TQSL TQSL Station Location Emplacement de la station TQSL Station Profile ID ID du profil de station Reupload All Tout renvoyer Show QSOs... Afficher les QSO... &Upload &Envoyer Unspecified Non spécifié Hide QSOs... Masquer les QSO... Uploading to %1 Envoi vers %1 Cancel Annuler QLog Warning - %1 Avertissement QLog - %1 Cannot update QSO Status Impossible de mettre à jour le statut du QSO Cannot upload the QSO(s): Impossible d'envoyer le(s) QSO : QLog Information Information QLog No QSO found to upload. Aucun QSO trouvé pour l'envoi. QSO(s) were uploaded to the selected services Le(s) QSO a/ont été envoyé(s) aux services sélectionnés Time Heure Callsign Indicatif Mode Mode Upload to Envoyer vers The values below will be used when an input record does not contain the ADIF values Les valeurs ci-dessous seront utilisées lorsqu'un enregistrement ne contient pas les valeurs ADIF Any Tous Location callsign (%1) and grid (%2) do not match selected filters L'indicatif de l'emplacement (%1) et le locator (%2) ne correspondent pas aux filtres sélectionnés Location callsign (%1) does not match selected callsign (%2) L'indicatif de l'emplacement (%1) ne correspond pas à l'indicatif sélectionné (%2) Location grid (%1) does not match selected grid (%2) Le locator de l'emplacement (%1) ne correspond pas au locator sélectionné (%2) Unknown Inconnu Service is not configured properly.<p> Please, use <b>Settings</b> dialog to configure it.</p> Le service n'est pas configuré correctement.<p> Veuillez utiliser la boîte de dialogue <b>Paramètres</b> pour le configurer.</p> UserListModel Callsign Indicatif Gridsquare Locator Distance Distance Azimuth Azimut Comment Commentaire WCYTableModel Time Heure K K expK expK A A R R SFI SFI SA SA GMF GMF Au Au WWVTableModel Time Heure SFI SFI A A K K Info Info WsjtxFilterDialog WSJTX Filters Filtres WSJTX General Filters Filtres généraux Log Status Statut du log New Band Nouvelle bande New Mode Nouveau mode New Entity Nouvelle entité (DXCC) New Slot Nouveau slot (bande/mode) Worked Contacté Confirmed Confirmé Continent Continent North America Amérique du Nord Europe Europe South America Amérique du Sud Africa Afrique Antarctica Antarctique Asia Asie Oceania Océanie Distance more than Distance supérieure à SNR better than SNR meilleur que dB dB Extended Filters Filtres étendus Member Membre No Club List is enabled Aucune liste de club n'est activée WsjtxTableModel Callsign Indicatif Gridsquare Locator Distance Distance SNR SNR Last Activity Dernière activité Last Message Dernier message Member Membre WsjtxWidget Form Formulaire Filtered Filtré Column Visibility... Visibilité des colonnes... Which columns should be displayed Quelles colonnes doivent être affichées Filter... Filtrer... Filter Spots Filtrer les spots main Run with the specific namespace. Exécuter avec l'espace de noms (namespace) spécifique. namespace espace de noms Translation file - absolute or relative path and QM file name. Fichier de traduction - chemin absolu ou relatif et nom du fichier QM. path/QM-filename chemin/nom-du-fichier-QM Set language. <code> example: 'en' or 'en_US'. Ignore environment setting. Définir la langue. <code> exemple : 'en' ou 'en_US'. Ignore les paramètres d'environnement. code code Writes debug messages to the debug file Écrit les messages de débogage dans le fichier de debug Process pending database import (internal use) Traiter l'importation de base de données en attente (usage interne) Force update of all value lists (DXCC, SATs, etc.) Forcer la mise à jour de toutes les listes (DXCC, SATs, etc.) foldynl-QLog-3252ff9/i18n/qlog_it.qm000066400000000000000000007725351517334601000171620ustar00rootroot00000000000000WuWWȡWLX2lX`=XX X{XXFXmXFYvY\ZlxZlaZe$ZwvZw[S)[c)[j*[*+[x [a\X*-\*Q]]!`]x__"6_`er.oQQuQQ \M2\Mo1u1|E0`W0 {0X072(3DDDDDm :!04}i_}%~},%s"ns$st"jT%ygڨ"EyE|`04{xo̾)4 d%=~(cc4#4 4 o4+4q4\4464q4t8)87#E+E#EލEE+EE8EE8EqEH5H5xH5H5H5:P`TT?_T;T͛TT=VESyVEVE;dVEc~(f.jfuh20h3@ih3hcuhl5v?xx?xŷxFxpx{{ƅ{Gbsy'$MKKnx q\>r-T$g'gO`N\55{5^5x5cs|sΥseP˦˦*W˦˦]˦ϗ˦g(:xyT|*| D|+||"b|Ѣ|i3|x|+Kc p 8>" r$ r&բU [" %nb'8()5m)5_)5<*I*%ڔ*0+.B+.N+!+..*/Z!05{405,Jc6007Pv7pvL8ԗ80:d":d|:$):$y:<@̇eB6HFMrF-KG>Hw9iHzJtHjHHHHH[H؄!]I(KI(KI(KGI(KI(KjI(K{I%9IAfI\J(^J+J+PJ+3J+5J+yJ+J5;J;ZLJ;J3J^JY FJYiJYv>JYxJY:PKI#KtIL7LG~L|Lb Lb)MPBMUM\oMy^MANQ?"NOPpPJ9P~.P9Q>RTnRxnRVR] SISI S[6SySeS>ST]TUTZQTZ9 TZ8TZTZ9@TerTR!TbT|T T."T%RTUjUWVV&VBV+4VhVMVV>VuVRVEVE'4VEVEWWi`?WmWmA/W~WTXRXRXXX0yX1%mX1'X1yX2%X2'<X2yX3'sX3z+X4'Yf1*YiA?YiBsYnjYQ/YYcYy*ZEZgQ:Zg|Zk7VZv'ZZykZhZZVZ~ȸ[W_[[dK\q\\.\b\34]Ҋ]%9]r^^h^A_þ:eѕti(K8iuqjh2cjh3l[toz>9}wc~vL+$h$$LT+Rlss# c(Y`}Ȅv1#W6XHLJIt<YJ3 Z"%Q%pc% %>ICkJ 0AZn9Mf˹.RYss"^L5Is/b3p7Z $4$u!Owyo1Z|1|.h?~-`7jDX7t%pM:7h!_  . JBNbANIf3&2yK/*ļ023@54r78-~8 ;oGQI?J#*LpRDCVCW [M0\T_ )m`pq^qUQuup vr~w 2lW`sk z&# BN.<#&gO 4") yƨ4O$7oAԙ!E1ۋsaJk{z{zg$``W*CT20w30u66kc\R t0 CN(>N;z^dAd&A lnE *[%S&Hb$' *`+y,N:kX<CiGK!^[K~T%wRAGV1XGX"VYu:=\Hb\hSvc]I_s$2_̆g6snU;sn rsnQjsnOtNt4u^u*u[uvwôA8҉a`}R43O٪^Ń+ 3R5*>si?xcS< Z> 3 jx?|Ζw3'$}=>$R,Y5ـ>^^*n=nZ5gȡ# ]PVa 0l| DD~rW~b*x7" .<#n$o*bY,C.6Sͤ9L:1 `:2 S:~”~~JU D3KC ', J$XE+N/*9/.Ur3$D 8T;?#@B,BHB[0F;GOoXQ\/T@VˑV^YG0\թ]PbdS3fTDNiYil|0Mmlp-qdQu #uCv:}$} }`}}}}?}u~YO l7v7#DWp&ɳɳ~/!*.J0y_#1+|[\a!~h)i8Flx7;k'jG'IIII| nJn2n\n~nno /"{ŹŹŹ E hN,B,-X,!]}C]_&Wgy5l*f##iJha#izHHeyktjll.E\&V˱ >fIX8) )R))MŰ?C(ȟ^6; ̖e̖e"̖e̖eLvj2vVv³ 3:Q.*`Ycfm.twѽA"ӖU֓W,֓W]jL؄c`9`&K&,軕7t4YBCAeAurBSȡ-V3vlv_ e [ mhp:j~~v[bN`T&{B((R)*L|,,3$D45.4ۂ[638(8GQ`<8<8<8_<8<8q<86<7T<=O(==;?0\(AiBLE%]E9pFGJ*KHj2KHjh)KNKNiKWb]KXbKXKXj^KXs'M9dU4KVVY˹\ \ \4a`wbKs}c>A!czPxeB5veg46hhhhhH1h? jzj=jUol6&mϒknԺst_v(D1vZTxx{T|Le}X{#'d#MbVfK]J&b(˴z˴˴^FF(FqF0FvFxF.FڽF!vG]#kcx~,."$CsdQ/3\`iU](&}$lIRJw9YRM|N&8cN:N%£2F ~2it ,P1Yw0ɖSIgSSS'24;4434V4o64}GZH,)s?K#@wEl5S*ϨK\;ƨb5t5tlv;W` ͜%P1gME摴摴+o摴Q摴0摴+l摴!摴o摴 }ui8g K? b "M9N0Nё-ђ-qRey!3$T{ b!g5y$Y+)RX*xK-S&.0 0DG111i 3^W6S[/l] M]0].%&^%2`ܴ`aQe@e@KeCE(gރqzm?$wm?$;nbst-Cu-*v slv 1w$CwYU>{&;{{b| }J p#}J D}J }a ~\~|~|3'loV(ZM#R -ߴ.Oljwc75c aYhpĸl JzKGmcTd#A5`T[]<ŰobC_XJ=ِ3ܗ{\IG\51t&1t(=tzP1 ]iVkc$gc(r0T&5Bk 2BvN`#*bW/e3$E3&8b93>  ?<@y@y+A2B^)IK)HVK^LT$MWNN.POQc8RjTVXPY3[\u4,\u\\u~\uo]@B]wZawN;bbըi(siE/iE:iEG iJ.s/>SuXyzFQ{ι|M|g#.g^Wh8BhubJJIe7\0Ii >IC־6g)W4&fM#ЂG++x ݮ"Fu1o:1ZK切/切F44v9!Pz  @svo25Z2+qA5d8 ~g.>2:`~#jisqs %@<&9`(?(U)%ũ+ ,$-ȱr/=/&0Ex0t70jq23N3N3N3N3N3N3N3N|q3N3N4Y5Y.9^a:<>Oc@BcA)Au#AQFouKiKKLRNk*MoOlYPtX ZZ Zi[a]9S``rN`Qʞesvee$eݽseݽtfSehfSgC9hPxhP{k|m6)mZ2pܿp wvz;Nztcz{~~R%*d 4pe8#+J+N +N>+N+Nr+N+Xc~4 $кq!aeH*e-'*1*1 *1*1*1SV,kıW9Q33"4|#jfsƵEݣI?A +.Jzz|R~B4[T4wDX-g%/tttb‰Ŷr]Dǒ)YKBʸПɰCm%՛#&jytۗX:yb=PV=>#5rSWUpuQMd04$jf@  D 22\ \1 L[ t d*w dq dЋ d ' "U (9E (ۓ )W6 )52 +@ -4IG /) /J 1h_ 6a 8li :$oG =&Qӭ @ Ah H0 It I2T I2p= I2 & I2? I2 I2 I2P I2Û JhW Jb Mg# MgkE QBb Stp T U Z \3 ] n ]Dc _y _Z `L aQ c cNB c d es> e} e5> e@ f  g? iR i>j j2 j2 j2n$ rSm J la Ia *A h. wr } JQ QN ^w 4 d{  S  o 4m i i Sf b_ 3q 3   q r Er щ >N > ??- AQi_ B5i Ge J. : J. J-e P  TnS UM= U9 XE\ Zr# ZN Z ]5D9 a-e a4"A bB c c¤q d< d<\N d<m d< d<~ d< di# dU* d)M e U- eK~ eKs eK ee eM1 e e g,5ce g7- iu i k# l[| l[q l[ l[ l[ l o oh pr] r=k uy6F v vC v{ . ?%d ٴn  W #@ if i  Z` ` b 4Z 4 #   V ϴ / > yb  }q J1 I E C Cc C C vU "~ *͡ y É% ' 8ys 8 Őw M9  LJ y? ȗ0 wf ~ ~ ʀs]" ʀsw „ „U vIb v1> v^ 7iY n9 䓳 U!L u u 5`= C] F  f / 瘟 b1 Nf 9B^u 7 <f <[ < <7 0% u!( u w} ƔK Ɣoq I vY v R D 8wz 8 n #w1 ] nr` X5| c I?P  TA !LQn !ak "; )RU )P\ ,33 ,D . .6RF 6b 8j ; B3? GCqF JI N:VA P.f> R? RR =9 Te2o TOH Uo ZL ] ^ǥQ _u# df f(5 fF y h7؃ lQ mps q5 r k uD>P ~`$g C"  ,U ,  Rq βP Q $.@ 56 T] .cn 4 Z @d  @dFi {'  l1 xK {" PuP Puu# Pu Puʉ Pu Pu+ Pu! PuC Pu[ Zè x ]=2 U Ky a>\. k ÕbY Õ jg 5T{ \ bT ]) e;) ۿX CF g!   KG# l  d >E@ h= l y/ E9= $ . % (h # x( 5# 5# ewV P C  6  >x . Ku\ #fQ $u %z. 'K ( ) ) *97 +3n ,G{P -a 0 1je 1W 6 7@ҷ 9$ ;{N ;Ae >PgO ? @_S B9U2l D:M D$ D3 G Gvv Gt Hʔ IH^ٽ J% K{I% N( P P* RV RV S# S,d, S W X X YrnS Y [ [ţox \-7 ^} d! gLaq iҧ j wv wxuf w}O { |;, |B w % m $ j ]4  :S uI ÒR/  ) ) )u ) ) C 9 C3 J     @P @ @J @5 $ $ $ $w i*x~ r u b [3Q [3 [3 dl n EE - Vd6A s۳ sN d d dM d y 3e 7% aj  P <#q ; / S  ~ c ~{ .N s\ U1 q - 5u 0d D!  < ۧ ~ ր ( % 8 m T t8 h ' &fC ) *7 / /kϞ 0j 0k) 0EmT 0Em 21W ;3| @d B KN U| Ugg Wgl W+- W>i \"5 \p;* _: _*J ar@n cXq iFCu m4 m s w0>Bm w0> 6 P P P P '^ P gW  `4 tRJ    L +! +n +nz l> oi k zm PS6F Ps )/ Sb - Œ4 <y ȳ< )9  ƍP L7 y %$ LA diZ ݖ ݩ.Ȫ P /A; LZ rF { ~ y- k 4T7\I^orֹ3D   b nS&#~P%?P%P%i}P%rՑs=e!a?!a!#s$&$O *}l',w&1a2 2 y33mY33<6$16,:T?mP@EBEElHY%H~Id/LP>P YU]9d^V!cIcIPiYV'Ki^'iTkji#lQ?.U} ΢Um-#ɒ&qHD_˟N2_e_(WNi,d%%UT3nsih~SGr#PUOO5́RѢϘ#DQuֻ4^־yQ"ShZhj0)Mz]@] N^!")i*Editor delle attivitActivity EditorActivityEditor$Nome dell'attivit Activity NameActivityEditorAntennaAntennaActivityEditor"Campi disponibiliAvailable FieldsActivityEditor^Cambia ordine. Muovi campo sesezionato in basso*Change the order. Move selected field downActivityEditor\Cambia ordine. Muovi campo sesezionato in alto(Change the order. Move selected field upActivityEditorCancellaClearActivityEditorColonna AColumn AActivityEditorColonna BColumn BActivityEditorColonna CColumn CActivityEditorConnetteConnectActivityEditor0Connetti automaticamenteConnect automaticallyActivityEditor CampiFieldsActivityEditorRSe non selezionato, il profilo non cambia)If unchecked, the profile does not changeActivityEditor LayoutLayoutActivityEditorrElenco dei campi nella prima colonna dei dettagli del QSO-List of fields in the first QSO Detail ColumnActivityEditor\Elenco dei campi nella prima riga modificabile(List of fields in the first variable rowActivityEditorvElenco dei campi nella seconda colonna dei dettagli del QSO.List of fields in the second QSO Detail ColumnActivityEditor`Elenco dei campi nella seconda riga modificabile)List of fields in the second variable rowActivityEditorrElenco dei campi nella terza colonna dei dettagli del QSO-List of fields in the third QSO Detail ColumnActivityEditorZElenco di campi che possono essere utilizzatiList of fields that can be usedActivityEditorSposta i campi selezionati dall'elenco dei campi disponibili alla riga A@Move selected fields from the Available Fields List to the Row AActivityEditorSposta i campi selezionati dall'elenco dei campi disponibili alla riga B@Move selected fields from the Available Fields List to the Row BActivityEditor*Non deve essere vuotoMust not be emptyActivityEditor<Colonne Dettagli del Nuovo QSONew QSO Detail ColumnsActivityEditor&Righe del Nuovo QSO New QSO RowsActivityEditorProfiliProfilesActivityEditorRElimina il campo selezionato dalla riga A$Remove selected field from the Row AActivityEditorRElimina il campo selezionato dalla riga B$Remove selected field from the Row BActivityEditor RadioRigActivityEditor RotoreRotatorActivityEditor Riga ARow AActivityEditor Riga BRow BActivityEditorSalvatoSavedActivityEditorStazioneStationActivityEditorNon SalvatoUnsavedActivityEditor ValoriValuesActivityEditor8Disposizione delle finestre:Window Arrangement:ActivityEditor.*.*AlertRuleDetail AfricaAfricaAlertRuleDetail:Dettaglio Regola dell'AllarmeAlert Rule DetailAlertRuleDetail TuttiAllAlertRuleDetailAntartide AntarcticaAlertRuleDetailAsiaAsiaAlertRuleDetail BandaBandsAlertRuleDetail CQZoneCQZAlertRuleDetailCWCWAlertRuleDetailConfermato ConfirmedAlertRuleDetailContinente ContinentAlertRuleDetailNazioneCountryAlertRuleDetailDXDXAlertRuleDetailDX Callsign DX CallsignAlertRuleDetailDX Cluster DX ClusterAlertRuleDetailDigitalDigitalAlertRuleDetailAbilitatoEnabledAlertRuleDetail EuropaEuropeAlertRuleDetailFTx (FT8/FT4) FTx (FT8/FT4)AlertRuleDetailIOTAIOTAAlertRuleDetailITUITUAlertRuleDetailStato del Log Log StatusAlertRuleDetail MembroMemberAlertRuleDetailModiModesAlertRuleDetail*Non deve essere vuotoMust not be emptyAlertRuleDetailNuova BandaNew BandAlertRuleDetailNuova Entit New EntityAlertRuleDetailNuovo ModoNew ModeAlertRuleDetailNuovo SlotNew SlotAlertRuleDetail:Nessuna Club List abilitataNo Club List is enabledAlertRuleDetailNord America North AmericaAlertRuleDetailOceanaOceaniaAlertRuleDetailPOTAPOTAAlertRuleDetail FoniaPhoneAlertRuleDetail"Nome della Regola Rule NameAlertRuleDetailSOTASOTAAlertRuleDetailSorgenteSourcesAlertRuleDetailSud America South AmericaAlertRuleDetailSpecialeSpecial ProgramsAlertRuleDetailSpot Comment Spot CommentAlertRuleDetailSpotterSpotterAlertRuleDetailVUtilizza espressioni regolari simili a Perl Use Perl-like regular expressionAlertRuleDetail WSJTXWSJTXAlertRuleDetailWWFFWWFFAlertRuleDetailLavoratoWorkedAlertRuleDetailAggiungiAddAlertSettingDialog&Regole sugli avvisi Alerts RulesAlertSettingDialogModificaEditAlertSettingDialogNomeNameAlertSettingDialogRimuoviRemoveAlertSettingDialog RegoleRulesAlertSettingDialog StatoStateAlertSettingDialogIndicativoCallsignAlertTableModelFrequenza FrequencyAlertTableModelltimo Commento Last CommentAlertTableModel(ltimo Aggiornamento Last UpdateAlertTableModel MembroMemberAlertTableModelModoModeAlertTableModel"Nome della Regola Rule NameAlertTableModelAggiornatoUpdatedAlertTableModel min(s) min(s) AlertWidget AvvisiAlerts AlertWidgetCancellaClear AlertWidget.Cancella pi vecchio diClear older than AlertWidget6Visibilit della colonna...Column Visibility... AlertWidgetModifica Regole Edit Rules AlertWidgetMaiNever AlertWidget AfricaAfrica AwardsDialogAntartide Antarctica AwardsDialogAsiaAsia AwardsDialogDiplomaAward AwardsDialogDiplomiAwards AwardsDialogCWCW AwardsDialogConfermato da Confirmed by AwardsDialogEliminatoDELETED AwardsDialogDXCCDXCC AwardsDialogDigiDigi AwardsDialog EuropaEurope AwardsDialogIOTAIOTA AwardsDialogITUITU AwardsDialog6Citt giapponesi / Ku / GunJapanese Cities/Ku/Guns AwardsDialogLoTWLoTW AwardsDialogModoMode AwardsDialogMia Entit DXCCMy DXCC Entity AwardsDialog4Contee della Nuova Zelanda NZ Counties AwardsDialog(Nessun filtro utenteNo User Filter AwardsDialogNord America North America AwardsDialogNon confermatoNot-Confirmed Only AwardsDialog"Solo non lavoratoNot-Worked Only AwardsDialogOceanaOceania AwardsDialogOpzioniOptions AwardsDialogPOTA ActivatorPOTA Activator AwardsDialogPOTA Hunter POTA Hunter AwardsDialogCartaceoPaper AwardsDialog FoniaPhone AwardsDialog,Distretti della RussiaRussian Districts AwardsDialogSOTASOTA AwardsDialog MostraShow AwardsDialogSouth America South America AwardsDialogDME spagnoli Spanish DMEs AwardsDialog0Contee degli Stati Uniti US Counties AwardsDialog,Distretti dell UcrainaUkrainian Districts AwardsDialogFiltro Utente User Filter AwardsDialogWACWAC AwardsDialogWASWAS AwardsDialogWAZWAZ AwardsDialogWPXWPX AwardsDialogWWFFWWFF AwardsDialogeQSLeQSL AwardsDialogConfermato ConfirmedAwardsTableModel Slot: Slots: AwardsTableModelIn attesa Still WaitingAwardsTableModelLavoratoWorkedAwardsTableModel min(s) min(s) BandmapWidgetBandmapBandmap BandmapWidgetCentra RX Center RX BandmapWidgetCancella Tutto Clear All BandmapWidget.Cancella pi vecchio di Clear older BandmapWidget6Cancellare la banda attualeClear the current band BandmapWidgetRCreare una finestra aggiuntiva di Bandmap#Create an additional Bandmap Window BandmapWidgetForm BandmapWidgetMaiNever BandmapWidgetMostra Banda Show Band BandmapWidget:Mostra frequenze di emergenzaShow Emergency Frequencies BandmapWidgetHImpossibile inviare Testo alla RadioCannot send Text to RigCWCatKeyHImpossibile impostare velocit KeyerCannot set Keyer SpeedCWCatKey>Impossibile fermare invio TestoCannot stop Text SendingCWCatKey$Keyer non connessoKeyer is not connectedCWCatKey,Nessuna Radio connessaNo Rig is connectedCWCatKeyHLa radio non supporta Morse over CAT#Rig does not support Morse over CATCWCatKey$Radio non connessaRig is not connectedCWCatKey WPM WPMCWConsoleWidget&CW&CWCWConsoleWidget"Console CW: FermaCW Console - Halt SendingCWConsoleWidget Profili Keyer CWCW Keyer ProfileCWConsoleWidgetCancellaClearCWConsoleWidget@Cancella Inviati ed Echo ConsoleClear Sent and Echo ConsoleCWConsoleWidgetTesto ripetuto Echoed textCWConsoleWidgetF1CWConsoleWidgetF2CWConsoleWidgetF3CWConsoleWidgetF4CWConsoleWidgetF5CWConsoleWidgetF6CWConsoleWidgetF7CWConsoleWidgetFormCWConsoleWidget FermaHaltCWConsoleWidget\Interrompere immediatamente la trasmissione CWImmediately stop CW sendingCWConsoleWidgetN/AN/ACWConsoleWidget:La radio deve essere connessaRig must be connectedCWConsoleWidgetTesto inviato Sent textCWConsoleWidget&Profilo ScorciatoieShortcuts profileCWConsoleWidgetVelocitSpeedCWConsoleWidget:Passa dall'invio di <b>parole</b> singolarmente (separate da spazi)<br> all'invio dell'intero testo come un'unica <b>parola</b> (separata da una nuova riga).Switch between sending words individually (separated by spaces)
and sending the entire text as a whole (separated by a new line).CWConsoleWidget Testo da inviare Text to sendCWConsoleWidget TuttoWholeCWConsoleWidget ParolaWordCWConsoleWidget8Impossibile inviare il TestoCannot send Text CWDaemonKeyHImpossibile impostare velocit KeyerCannot set Keyer Speed CWDaemonKey>Impossibile fermare invio TestoCannot stop Text Sending CWDaemonKey$Keyer non connessoKeyer is not connected CWDaemonKeyFImpossibile ricevere dati da FLDigiCannot receive data from FLDigi CWFldigiKeyDImpossibile inviare Testo a FLDigiCannot send Text to FLDigi CWFldigiKeyTImpossibile inviare comando Abort a FLDigi'Cannot send the Abort command to FLDigi CWFldigiKeyTImpossibile inviare comando Clear a FLDigi'Cannot send the Clear command to FLDigi CWFldigiKeyRImpossibile inviare comando Stop a FLDigi&Cannot send the Stop command to FLDigi CWFldigiKeyNImpossibile inviare comando TX a FLDigi$Cannot send the TX command to FLDigi CWFldigiKeyRImpossibile inviare comando Text a FLDigi&Cannot send the Text command to FLDigi CWFldigiKeyHIl dispositivo connesso non FLDigiConnected device is not FLDigi CWFldigiKey*Errore comando FLDigiFLDigi command error CWFldigiKey8Errore di connessione FLDigiFLDigi connection error CWFldigiKey4Timeout connessione FLDigiFLDigi connection timeout CWFldigiKey$Keyer non connessoKeyer is not connected CWFldigiKeyNImpossibile aprire la connessione Keyer Cannot open the Keyer connectionCWKeyer*Errore di connessioneConnection ErrorCWKeyer4Errore di inizializzazioneInitialization ErrorCWKeyerErrore InternoInternal ErrorCWKeyerFNessun Profilo Keyer CW selezionatoNo CW Keyer Profile selectedCWKeyer 4000 Hz {1000 ?}1000 HzCWWinKey 4000 Hz {1333 ?}1333 HzCWWinKey 4000 Hz {2000 ?}2000 HzCWWinKey4000 Hz {400 ?}400 HzCWWinKey4000 Hz4000 HzCWWinKey4000 Hz {444 ?}444 HzCWWinKey4000 Hz {500 ?}500 HzCWWinKey4000 Hz {571 ?}571 HzCWWinKey4000 Hz {666 ?}666 HzCWWinKey4000 Hz {800 ?}800 HzCWWinKeyHImpossibile inviare Testo alla RadioCannot send Text to RigCWWinKeyHImpossibile impostare velocit KeyerCannot set Keyer SpeedCWWinKey>Impossibile fermare invio TestoCannot stop Text SendingCWWinKey.Errore di comunicazioneCommunication ErrorCWWinKeyHIl dispositivo connesso non WinkeyConnected device is not WinKeyCWWinKey$Keyer non connessoKeyer is not connectedCWWinKey -  - CabrilloExportDialog&Esporta&ExportCabrilloExportDialogAggiuntivo AdditionalCabrilloExportDialogIndirizzo:Address:CabrilloExportDialogAssistito: Assisted:CabrilloExportDialog Banda:Band:CabrilloExportDialog CercaBrowseCabrilloExportDialog Esporta CabrilloCabrillo ExportCabrilloExportDialogrFile Cabrillo (*.log);;File CBR (*.cbr);;Tutti i file (*)8Cabrillo Files (*.log);;CBR Files (*.cbr);;All Files (*)CabrilloExportDialogIndicativo: Callsign:CabrilloExportDialogVImpossibile aprire il file %1 in scrittura. Cannot open file %1 for writing.CabrilloExportDialog Club:Club:CabrilloExportDialogContestContestCabrilloExportDialogData/Ora: Date/Time:CabrilloExportDialog Email:Email:CabrilloExportDialogFEsportati %n QSO nel file Cabrillo.$Exported %n QSO(s) to Cabrillo file.CabrilloExportDialog,Esportazione Cabrillo &Exporting Cabrillo...CabrilloExportDialog^Impossibile preparare la query di esportazione.Failed to prepare export query.CabrilloExportDialogbImpossibile interrogare i QSO per l esportazione. Failed to query QSOs for export.CabrilloExportDialog File:File:CabrilloExportDialog&Modello di formato:Format Template:CabrilloExportDialogGriglia GridsquareCabrilloExportDialogPosizione: Location:CabrilloExportDialogGestisciManageCabrilloExportDialogMax 6 righe Max 6 linesCabrilloExportDialog Modo:Mode:CabrilloExportDialog Nome:Name:CabrilloExportDialogdNessun nominativo disponibile. Controlla i filtri.*No callsign available. Check your filters.CabrilloExportDialogOperatore: Operator:CabrilloExportDialogOperatori: Operators:CabrilloExportDialogDSelezionare un modello di contest.!Please select a contest template.CabrilloExportDialog<Selezionare un file di output.Please select an output file.CabrilloExportDialogPotenza:Power:CabrilloExportDialogErrore di QLog QLog ErrorCabrilloExportDialog"Informazioni QLogQLog InformationCabrilloExportDialogAvviso QLog QLog WarningCabrilloExportDialogQSO(s): %1 QSO(s): %1CabrilloExportDialogQSOs: ?QSOs: ?CabrilloExportDialog Commento libero:Soapbox:CabrilloExportDialog(Stazione e categorieStation & CategoriesCabrilloExportDialogStazione:Station:CabrilloExportDialogOra:Time:CabrilloExportDialogTrasmettitore: Transmitter:CabrilloExportDialogFiltro utente: User Filter:CabrilloExportDialog1.25m (222 MHz)1.25m (222 MHz)CabrilloFormat 12 ore12 HoursCabrilloFormat23cm (1.2 GHz)23cm (1.2 GHz)CabrilloFormat 24 ore24 HoursCabrilloFormat2m (144 MHz) 2m (144 MHz)CabrilloFormat33cm (902 MHz)33cm (902 MHz)CabrilloFormat 6 ore6 HoursCabrilloFormat70cm (432 MHz)70cm (432 MHz)CabrilloFormatTutte le Bande All BandsCabrilloFormatAssistitoAssistedCabrilloFormatControlla log Check LogCabrilloFormatClassicoClassicCabrilloFormat"Data (AAAA-MM-GG)Date (YYYY-MM-DD)CabrilloFormatDigitalDigitalCabrilloFormatDistribuito DistributedCabrilloFormatSpedizione ExpeditionCabrilloFormat FissoFixedCabrilloFormatFrequenza (kHz)Frequency (kHz)CabrilloFormatHighHighCabrilloFormatLuceLightCabrilloFormatLimitatoLimitedCabrilloFormatLowLowCabrilloFormat MistoMixedCabrilloFormat MobileMobileCabrilloFormat&Modalit (Cabrillo)Mode (Cabrillo)CabrilloFormatMulti operatoreMulti OperatorCabrilloFormatNon assistito Non-AssistedCabrilloFormatNovizio/Tecnico Novice/TechCabrilloFormatUnoOneCabrilloFormatOltre 50Over 50CabrilloFormat@RST breve (senza l ultima cifra)RST Short (drop last digit)CabrilloFormatSWLSWLCabrilloFormat ScuolaSchoolCabrilloFormat"Operatore singoloSingle OperatorCabrilloFormat8Testo (allineato a sinistra)Text (left-aligned)CabrilloFormatOra (HHMM) Time (HHMM)CabrilloFormatDueTwoCabrilloFormatIllimitato UnlimitedCabrilloFormatMaiuscolo UppercaseCabrilloFormatVHF a 3 bande VHF 3-BandCabrilloFormatSolo VHF FM VHF FM OnlyCabrilloFormatNumero con zeriZero-Padded Nr.CabrilloFormatAggiungiAddCabrilloTemplateDialogAggiungi rigaAdd lineCabrilloTemplateDialog0Gestore modelli CabrilloCabrillo Template ManagerCabrilloTemplateDialog<Impossibile aprire il file: %1Cannot open file: %1CabrilloTemplateDialogNImpossibile salvare il modello %1: %2Cannot save template '%1': %2CabrilloTemplateDialog`Impossibile avviare la transazione del database."Cannot start database transaction.CabrilloTemplateDialog"Nome del contest: Contest Name:CabrilloTemplateDialogNome del contest secondo le regole. possibile inserire una stringa personalizzata se non inclusa nell elenco.qContest name as required by the rules. It is possible to enter a custom string if it is not included in the list.CabrilloTemplateDialog CopiaCopyCabrilloTemplateDialogCopia  %1 Copy - %1CabrilloTemplateDialog.Copia modello esistenteCopy existing templateCabrilloTemplateDialog*Modalit predefinita: Default Mode:CabrilloTemplateDialogElimina modelloDelete TemplateCabrilloTemplateDialogElimina modelloDelete templateCabrilloTemplateDialog4Eliminare il modello %1?Delete template '%1'?CabrilloTemplateDialogEsportaExportCabrilloTemplateDialog(Esportazione fallita Export FailedCabrilloTemplateDialogEsporta modelloExport TemplateCabrilloTemplateDialogEsporta modelloExport templateCabrilloTemplateDialog@Impossibile scrivere il file: %1Failed to write file: %1CabrilloTemplateDialog(File non trovato: %1File not found: %1CabrilloTemplateDialogFormattatore FormatterCabrilloTemplateDialogImportaImportCabrilloTemplateDialog(Importazione fallita Import FailedCabrilloTemplateDialogImporta modelloImport TemplateCabrilloTemplateDialogImporta modelloImport templateCabrilloTemplateDialogLFile modello non valido: nome mancante#Invalid template file: missing nameCabrilloTemplateDialogEtichettaLabelCabrilloTemplateDialog NuovoNewCabrilloTemplateDialogNuovo modello New TemplateCabrilloTemplateDialogNuovo modello New templateCabrilloTemplateDialog:Modello Cabrillo QLog (*.qct)QLog Cabrillo Template (*.qct)CabrilloTemplateDialogErrore di QLog QLog ErrorCabrilloTemplateDialogAvviso QLog QLog WarningCabrilloTemplateDialogCampo QSO QSO FieldCabrilloTemplateDialog"Colonne riga QSO:QSO Line Columns:CabrilloTemplateDialogRimuoviRemoveCabrilloTemplateDialog0Rimuovi riga selezionataRemove selected lineCabrilloTemplateDialogN.Seq.CabrilloTemplateDialog"Nome del modello:Template Name:CabrilloTemplateDialogLarghezzaWidthCabrilloTemplateDialogP<p>Sar usato il callbook secondario</p>*

The secondary callbook will be used

CallbookManagerChat Room Chat Room ChatWidgetConnetteConnect ChatWidget NuovoNew ChatWidgetON4KST Chat ON4KST Chat ChatWidgetLa chat ON4KST non configurata correttamente.<p> Utilizza la finestra di dialogo <b>Impostazioni</b> per configurarla.</p>bON4KST Chat is not configured properly.

Please, use Settings dialog to configure it.

 ChatWidgetAvviso QLog QLog Warning ChatWidgetDisabilitatoDisabledCheckBoxDelegateAbilitatoEnabledCheckBoxDelegateForm ClockWidgetN/AN/A ClockWidgetAlbaSunrise ClockWidgetTramontoSunset ClockWidget*Chiave API non validaInvalid API KeyCloudlogUploadervOperazione Clublog per il nominativo %1 non riuscita.<br>%2/Clublog Operation for Callsign %1 failed.
%2ClubLogUploader>Impostazione visibilit colonnaColumn Visibility SettingColumnSettingDialogCondizionali ConditionalsColumnSettingDialogContestsContestsColumnSettingDialog FattoDoneColumnSettingDialogGeneraleGeneralColumnSettingDialog MembriMembersColumnSettingDialog Mie informazioniMy InfoColumnSettingDialog AltriOthersColumnSettingDialog QSL && CallbooksQSL && CallbooksColumnSettingDialogSeleziona tutto Select AllColumnSettingGenericDialog"Deseleziona tutto Unselect AllColumnSettingGenericDialog>Impostazione visibilit colonnaColumn Visibility SettingColumnSettingSimpleDialog FattoDoneColumnSettingSimpleDialog, Aggiornamento fallito Update FailedDBSchemaMigrationClublog CTY.XMLClublog CTY.XMLDBSchemaMigrationEntit DXCC DXCC EntitiesDBSchemaMigrationIOTA Records IOTA RecordsDBSchemaMigrationLista di valoriList of ValuesDBSchemaMigration>Registro dell'elenco dei membriMembership Directory RecordsDBSchemaMigrationPOTA Records POTA RecordsDBSchemaMigrationSOTA Summits SOTA SummitsDBSchemaMigrationInfo Satelliti Sats InfoDBSchemaMigration"In aggiornamento  Updating DBSchemaMigrationWWFF Records WWFF RecordsDBSchemaMigrationAfghanistan Afghanistan DBStrings*Agalega & St. BrandonAgalega & St. Brandon DBStringsAland Islands Aland Islands DBStrings AlaskaAlaska DBStringsAlbaniaAlbania DBStringsAlgeriaAlgeria DBStringsAmerican SamoaAmerican Samoa DBStrings0Amsterdam & St. Paul Is.Amsterdam & St. Paul Is. DBStrings*Andaman & Nicobar Is.Andaman & Nicobar Is. DBStringsAndorraAndorra DBStrings AngolaAngola DBStringsAnguillaAnguilla DBStringsAnnobon IslandAnnobon Island DBStringsAntarctica Antarctica DBStrings"Antigua y BarbudaAntigua & Barbuda DBStringsArgentina Argentina DBStringsArmeniaArmenia DBStrings ArubaAruba DBStrings Ascension IslandAscension Island DBStringsAsiatic RussiaAsiatic Russia DBStringsAsiatic TurkeyAsiatic Turkey DBStringsAustral IslandsAustral Islands DBStringsAustralia Australia DBStringsAustriaAustria DBStringsAves Island Aves Island DBStringsAzerbaiyn Azerbaijan DBStrings AzoresAzores DBStringsBahamasBahamas DBStringsBahrainBahrain DBStrings.Baker & Howland IslandsBaker & Howland Islands DBStrings Balearic IslandsBalearic Islands DBStringsBanaba Island Banaba Island DBStringsBangladesh Bangladesh DBStringsBarbadosBarbados DBStringsBelarusBelarus DBStringsBelgiumBelgium DBStrings BeliceBelize DBStrings BennBenin DBStringsBermudaBermuda DBStrings BhutanBhutan DBStringsBoliviaBolivia DBStringsBonaireBonaire DBStrings$Bosnia-HerzegovinaBosnia-Herzegovina DBStringsBotswanaBotswana DBStrings BouvetBouvet DBStrings BrazilBrazil DBStrings,British Virgin IslandsBritish Virgin Islands DBStrings"Brunei DarussalamBrunei Darussalam DBStringsBulgariaBulgaria DBStringsBurkina Faso Burkina Faso DBStringsBurundiBurundi DBStringsCWCW DBStringsCambodiaCambodia DBStringsCameroonCameroon DBStrings CanadaCanada DBStringsCanary IslandsCanary Islands DBStringsCape Verde Cape Verde DBStringsCayman IslandsCayman Islands DBStrings0Central African RepublicCentral African Republic DBStrings Central KiribatiCentral Kiribati DBStringsCeuta & MelillaCeuta & Melilla DBStringsChadChad DBStringsChagos IslandsChagos Islands DBStringsChatham IslandsChatham Islands DBStrings(Chesterfield IslandsChesterfield Islands DBStrings ChileChile DBStrings ChinaChina DBStrings Christmas IslandChristmas Island DBStrings"Clipperton IslandClipperton Island DBStrings.Cocos (Keeling) IslandsCocos (Keeling) Islands DBStringsCocos Island Cocos Island DBStringsColombiaColombia DBStringsComorosComoros DBStringsConway Reef Conway Reef DBStringsCorsicaCorsica DBStringsCosta Rica Costa Rica DBStringsCote d'Ivoire Cote d'Ivoire DBStrings CreteCrete DBStringsCroatiaCroatia DBStringsCrozet Island Crozet Island DBStringsCubaCuba DBStringsCuracaoCuracao DBStrings CyprusCyprus DBStringsCzech RepublicCzech Republic DBStringsDigitalDIGITAL DBStringsDPR of Korea DPR of Korea DBStrings,Dem. Rep. of the CongoDem. Rep. of the Congo DBStringsDenmarkDenmark DBStringsDesecheo IslandDesecheo Island DBStringsDjiboutiDjibouti DBStringsDodecanese Dodecanese DBStringsDominicaDominica DBStrings$Dominican RepublicDominican Republic DBStringsDucie Island Ducie Island DBStringsEast Malaysia East Malaysia DBStringsEaster Island Easter Island DBStrings Eastern KiribatiEastern Kiribati DBStringsEcuadorEcuador DBStrings EgyptEgypt DBStringsEl Salvador El Salvador DBStringsEnglandEngland DBStrings"Equatorial GuineaEquatorial Guinea DBStringsEritreaEritrea DBStringsEstoniaEstonia DBStringsEthiopiaEthiopia DBStringsEuropean RussiaEuropean Russia DBStrings Falkland IslandsFalkland Islands DBStringsFaroe Islands Faroe Islands DBStrings(Fed. Rep. of GermanyFed. Rep. of Germany DBStrings&Fernando de NoronhaFernando de Noronha DBStringsFijiFiji DBStringsFinlandFinland DBStrings FranceFrance DBStrings Franz Josef LandFranz Josef Land DBStringsFrench Guiana French Guiana DBStrings French PolynesiaFrench Polynesia DBStrings GabonGabon DBStrings"Galapagos IslandsGalapagos Islands DBStringsGeorgiaGeorgia DBStrings GhanaGhana DBStringsGibraltar Gibraltar DBStrings Glorioso IslandsGlorioso Islands DBStrings GreeceGreece DBStringsGreenland Greenland DBStringsGrenadaGrenada DBStringsGuadeloupe Guadeloupe DBStringsGuamGuam DBStringsGuantanamo BayGuantanamo Bay DBStringsGuatemala Guatemala DBStringsGuernseyGuernsey DBStrings GuineaGuinea DBStringsGuinea-Bissau Guinea-Bissau DBStrings GuyanaGuyana DBStrings HaitiHaiti DBStrings HawaiiHawaii DBStringsHeard Island Heard Island DBStringsHondurasHonduras DBStringsHong Kong Hong Kong DBStringsHungaryHungary DBStrings ITU HQITU HQ DBStringsIcelandIceland DBStrings IndiaIndia DBStringsIndonesia Indonesia DBStringsIrnIran DBStringsIraqIraq DBStringsIrelandIreland DBStringsIsle of Man Isle of Man DBStrings IsraelIsrael DBStrings ItalyItaly DBStringsJamaicaJamaica DBStringsJan Mayen Jan Mayen DBStrings JapanJapan DBStrings JerseyJersey DBStringsJohnston IslandJohnston Island DBStrings JordanJordan DBStrings,Juan Fernandez IslandsJuan Fernandez Islands DBStrings*Juan de Nova & EuropaJuan de Nova & Europa DBStringsKaliningrad Kaliningrad DBStringsKazakhstan Kazakhstan DBStrings KenyaKenya DBStrings"Kerguelen IslandsKerguelen Islands DBStrings Kermadec IslandsKermadec Islands DBStrings&Kingdom of EswatiniKingdom of Eswatini DBStringsKure Island Kure Island DBStrings KuwaitKuwait DBStringsKyrgyzstan Kyrgyzstan DBStrings&Lakshadweep IslandsLakshadweep Islands DBStringsLaosLaos DBStrings LatviaLatvia DBStringsLebanonLebanon DBStringsLesothoLesotho DBStringsLiberiaLiberia DBStrings LibyaLibya DBStringsLiechtenstein Liechtenstein DBStringsLithuania Lithuania DBStrings Lord Howe IslandLord Howe Island DBStringsLuxembourg Luxembourg DBStrings MacaoMacao DBStrings Macquarie IslandMacquarie Island DBStringsMadagascar Madagascar DBStringsMadeira IslandsMadeira Islands DBStrings MalawiMalawi DBStringsMaldivasMaldives DBStringsMalMali DBStringsMalpelo IslandMalpelo Island DBStrings MaltaMalta DBStringsMariana IslandsMariana Islands DBStringsMarket Reef Market Reef DBStrings"Marquesas IslandsMarquesas Islands DBStrings Marshall IslandsMarshall Islands DBStringsMartinique Martinique DBStringsMauritania Mauritania DBStringsMauritius Mauritius DBStringsMayotteMayotte DBStringsMellish Reef Mellish Reef DBStrings MexicoMexico DBStringsMicronesia Micronesia DBStringsMidway Island Midway Island DBStrings Minami TorishimaMinami Torishima DBStringsMoldovaMoldova DBStrings MonacoMonaco DBStringsMongoliaMongolia DBStringsMontenegro Montenegro DBStringsMontserrat Montserrat DBStringsMoroccoMorocco DBStringsMount Athos Mount Athos DBStringsMozambique Mozambique DBStringsMyanmarMyanmar DBStrings*N.Z. Subantarctic Is.N.Z. Subantarctic Is. DBStringsNamibiaNamibia DBStrings NauruNauru DBStringsNavassa IslandNavassa Island DBStrings NepalNepal DBStringsNetherlands Netherlands DBStringsNew Caledonia New Caledonia DBStringsNew Zealand New Zealand DBStringsNicaragua Nicaragua DBStrings NigerNiger DBStringsNigeriaNigeria DBStringsNiueNiue DBStringsNorfolk IslandNorfolk Island DBStrings$North Cook IslandsNorth Cook Islands DBStringsNorth MacedoniaNorth Macedonia DBStrings Northern IrelandNorthern Ireland DBStrings NorwayNorway DBStringsOgasawara Ogasawara DBStringsOmanOman DBStrings FoniaPHONE DBStringsPakistanPakistan DBStrings PalauPalau DBStringsPalestine Palestine DBStrings0Palmyra & Jarvis IslandsPalmyra & Jarvis Islands DBStrings PanamaPanama DBStrings Papua New GuineaPapua New Guinea DBStringsParaguayParaguay DBStringsPeruPeru DBStringsPeter 1 IslandPeter 1 Island DBStringsPhilippines Philippines DBStringsPitcairn IslandPitcairn Island DBStrings PolandPoland DBStringsPortugalPortugal DBStrings.Pr. Edward & Marion Is.Pr. Edward & Marion Is. DBStringsPratas Island Pratas Island DBStringsPuerto Rico Puerto Rico DBStrings QatarQatar DBStrings"Republic of KoreaRepublic of Korea DBStrings$Republic of KosovoRepublic of Kosovo DBStrings.Republic of South SudanRepublic of South Sudan DBStrings*Republic of the CongoRepublic of the Congo DBStringsReunion IslandReunion Island DBStringsRevillagigedo Revillagigedo DBStrings Rodriguez IslandRodriguez Island DBStringsRomaniaRomania DBStringsRotuma Island Rotuma Island DBStrings RwandaRwanda DBStrings(Saba & St. EustatiusSaba & St. Eustatius DBStringsSable Island Sable Island DBStrings SamoaSamoa DBStrings0San Andres & ProvidenciaSan Andres & Providencia DBStrings0San Felix & San AmbrosioSan Felix & San Ambrosio DBStringsSan Marino San Marino DBStrings&Sao Tome & PrincipeSao Tome & Principe DBStringsSardiniaSardinia DBStringsSaudi Arabia Saudi Arabia DBStrings Scarborough ReefScarborough Reef DBStringsScotlandScotland DBStringsSenegalSenegal DBStrings SerbiaSerbia DBStringsSeychelles Seychelles DBStringsSierra Leona Sierra Leone DBStringsSingapore Singapore DBStringsSint Maarten Sint Maarten DBStringsSlovak RepublicSlovak Republic DBStringsSloveniaSlovenia DBStringsSolomon IslandsSolomon Islands DBStringsSomaliaSomalia DBStringsSouth Africa South Africa DBStrings$South Cook IslandsSouth Cook Islands DBStrings(South Georgia IslandSouth Georgia Island DBStrings(South Orkney IslandsSouth Orkney Islands DBStrings,South Sandwich IslandsSouth Sandwich Islands DBStrings,South Shetland IslandsSouth Shetland Islands DBStrings,Sov Mil Order of MaltaSov Mil Order of Malta DBStrings SpainSpain DBStringsSpratly IslandsSpratly Islands DBStringsSri Lanka Sri Lanka DBStringsSt. BarthelemySt. Barthelemy DBStringsSt. Helena St. Helena DBStrings"St. Kitts & NevisSt. Kitts & Nevis DBStringsSt. Lucia St. Lucia DBStringsSt. Martin St. Martin DBStringsSt. Paul IslandSt. Paul Island DBStrings(St. Peter & St. PaulSt. Peter & St. Paul DBStrings*St. Pierre & MiquelonSt. Pierre & Miquelon DBStringsSt. Vincent St. Vincent DBStrings SudnSudan DBStringsSurinameSuriname DBStringsSvalbardSvalbard DBStringsSwains Island Swains Island DBStrings SwedenSweden DBStringsSwitzerland Switzerland DBStrings SyriaSyria DBStrings TaiwanTaiwan DBStringsTajikistan Tajikistan DBStringsTanzaniaTanzania DBStringsTemotu ProvinceTemotu Province DBStringsThailandThailand DBStringsThe Gambia The Gambia DBStringsTimor - Leste Timor - Leste DBStringsTogoTogo DBStringsTokelau IslandsTokelau Islands DBStrings TongaTonga DBStrings*Trindade & Martim VazTrindade & Martim Vaz DBStrings"Trinidad y TobagoTrinidad & Tobago DBStrings@Tristan da Cunha & Gough Islands Tristan da Cunha & Gough Islands DBStringsTromelin IslandTromelin Island DBStringsTunisiaTunisia DBStringsTurkmenistan Turkmenistan DBStrings,Turks & Caicos IslandsTurks & Caicos Islands DBStrings TuvaluTuvalu DBStrings.UK Base Areas on CyprusUK Base Areas on Cyprus DBStrings"US Virgin IslandsUS Virgin Islands DBStrings UgandaUganda DBStringsUkraineUkraine DBStrings(United Arab EmiratesUnited Arab Emirates DBStrings"United Nations HQUnited Nations HQ DBStringsUnited States United States DBStringsUruguayUruguay DBStringsUzbekistan Uzbekistan DBStringsVanuatuVanuatu DBStringsVatican City Vatican City DBStringsVenezuela Venezuela DBStringsVietnamVietnam DBStringsWake Island Wake Island DBStrings WalesWales DBStrings.Wallis & Futuna IslandsWallis & Futuna Islands DBStringsWest Malaysia West Malaysia DBStrings Western KiribatiWestern Kiribati DBStringsWestern SaharaWestern Sahara DBStringsWillis Island Willis Island DBStrings YemenYemen DBStrings ZambiaZambia DBStringsZimbabweZimbabwe DBStrings.%1 %2 %3  DXCC %4 / %5%1 %2 %3 — DXCC %4 / %5DXCCSubmissionDialog0%1 banda/e selezionata/e%1 selected band(s)DXCCSubmissionDialogDXCC a 5 bande 5-Band DXCCDXCCSubmissionDialogBDXCC a 5 bande (80/40/20/15/10 m)5-Band DXCC (80/40/20/15/10m)DXCCSubmissionDialog5 bande5-bandDXCCSubmissionDialog&Tutte le bande DXCCAll DXCC BandsDXCCSubmissionDialogGi confermatoAlready GrantedDXCCSubmissionDialog@Qualsiasi banda (livello entit)Any Band (Entity Level)DXCCSubmissionDialog BandaBandDXCCSubmissionDialog&Intervallo di banda Band ScopeDXCCSubmissionDialog BandaBandsDXCCSubmissionDialogCWCWDXCCSubmissionDialogIndicativoCallsignDXCCSubmissionDialogCategoriaCategoryDXCCSubmissionDialogConfermato da Confirmed byDXCCSubmissionDialogHSelezione personalizzata delle bandeCustom Band SelectionDXCCSubmissionDialog(Elenco di invio DXCCDXCC Submission ListDXCCSubmissionDialogDataDateDXCCSubmissionDialogDigitalDigitalDXCCSubmissionDialog EntitEntityDXCCSubmissionDialogEsportaExportDXCCSubmissionDialogEsporta ADIF Export ADIFDXCCSubmissionDialogPEsporta l elenco di invio DXCC come ADIF#Export DXCC Submission List as ADIFDXCCSubmissionDialogbEsporta i contatti elencati sopra in un file ADIF0Export the contacts listed above to an ADIF fileDXCCSubmissionDialogZImpossibile recuperare i record dei contatti.#Failed to retrieve contact records.DXCCSubmissionDialogConfermatoGrantedDXCCSubmissionDialogLoTWLoTWDXCCSubmissionDialog MistoMixedDXCCSubmissionDialogModoModeDXCCSubmissionDialogMia Entit DXCCMy DXCC EntityDXCCSubmissionDialog(Nessun filtro utenteNo User FilterDXCCSubmissionDialogfNessun contatto corrisponde ai criteri selezionati.(No contacts match the selected criteria.DXCCSubmissionDialog:Nessun contatto da esportare.No contacts to export.DXCCSubmissionDialog$Non ancora inviatoNot Yet SubmittedDXCCSubmissionDialogOpzioniOptionsDXCCSubmissionDialogCartaceoPaperDXCCSubmissionDialog FoniaPhoneDXCCSubmissionDialogPrefissoPrefixDXCCSubmissionDialogzSeleziona bande predefinite DXCC a 5 bande (80/40/20/15/10 m)1Select 5-Band DXCC preset bands (80/40/20/15/10m)DXCCSubmissionDialogPSeleziona tutte le bande idonee per DXCCSelect all DXCC-eligible bandsDXCCSubmissionDialogSeleziona le opzioni sopra e l elenco si aggiorner automaticamente.

Icon by Icon Shock
Satellite images by NASA
ZoneDetect by Bertold Van den Bergh
TimeZone Database by Evan Siroky MainWindow"Eine neue Version A New Version MainWindowFEine neue Version %1 ist verfgbar.A new version %1 is available. MainWindowberAbout MainWindow AlertsAlerts MainWindowAlle Bnder All Bands MainWindowApp - BeendenApplication - Quit MainWindowBandmap MainWindowBeep MainWindow CW Console MainWindow@CW Console - Geschwindigkeit (-)CW Console - Key Speed Down MainWindow@CW Console - Geschwindigkeit (+)CW Console - Key Speed Up MainWindow@CW Console - CW-Keyer Profil (-)CW Console - Profile Down MainWindow@CW Console - CW-Keyer Profil (+)CW Console - Profile Up MainWindowChat MainWindowKlassischClassic MainWindowLschenClear MainWindowUhrClock MainWindow8Clublog-Sofort-Upload-Fehler Clublog Immediately Upload Error MainWindowFarbschema Color Theme MainWindow6Datenbank wird komprimiert &Compressing database... MainWindow$Verbinde &CW KeyerConnect &CW Keyer MainWindowVerbinde R&ig Connect R&ig MainWindowVerbinde R&otorConnect R&otator MainWindowContestContest MainWindowContest:  Contest:  MainWindow DX Cluster MainWindow.DXCC-&EinreichungslisteDXCC &Submission List MainWindowTDatenbankdateien (*.dbe);;Alle Dateien (*)%Database files (*.dbe);;All files (*) MainWindowPDatenbank erfolgreich exportiert nach %1"Database successfully dumped to %1 MainWindow Entwickler-ToolsDeveloper Tools MainWindowXMchten Sie den Contest-Filter %1 entfernen?,Do you want to remove the Contest filter %1? MainWindowHerunterladenDownload MainWindow$QSLs herunterladen Download QSLs MainWindowDupe-Prfung Dupe Check MainWindowJedes Band Each Band MainWindow"Jedes Band & ModeEach Band && Mode MainWindowBearbeitenEdit MainWindow"Regeln bearbeiten Edit Rules MainWindow(Cabrillo exportierenExport Cabrillo MainWindowTDatenbank konnte nicht komprimiert werden. Failed to compress the database. MainWindowZTemporre Datei konnte nicht erstellt werden. Failed to create temporary file. MainWindow<Datenbank-Dump fehlgeschlagen.Failed to dump the database. MainWindow\Verschlsseln der Zugangsdaten fehlgeschlagen.Failed to encrypt credentials. MainWindowrDatenbank konnte nicht fr den Import vorbereitet werden.&Failed to prepare database for import. MainWindowListe von Verbindungen zur Einreichung fr ARRL DXCC-Anerkennung erstellen@Generate a list of contacts to submit for ARRL DXCC award credit MainWindow"Optionen behalten Keep Options MainWindow.Exchange mit verknpfenLinking Exchange With MainWindowLogbuch - SucheLogbook - Search Callsign MainWindowMailing List... MainWindow KarteMap MainWindowN/A MainWindowNeuer Kontakt - bertragen Sie den Text vom Rufzeichenfeld in die Bandmap1New QSO - Add text from Callsign field to Bandmap MainWindow.Neuer Kontakt  LschenNew QSO - Clear MainWindow2Neuer Kontakt  SpeichernNew QSO - Save MainWindowbNeuer Kontakt - Verwende Rufzeichen vom Whisperer)New QSO - Use Callsign from the Whisperer MainWindowKeine KontrolleNo Check MainWindow KeineNone MainWindowVFr keinen anderen Stil als Fusion zulssig Not enabled for non-Fusion style MainWindowOnline Karte Online Map MainWindow<Daten und Einstellungen packenPack Data && Settings MainWindowBandPer Band MainWindowBDrcken zum Einstellen des AlarmsPress to tune the alert MainWindow,QSL-Etiketten &druckenPrint QSL &Labels MainWindowProfilfoto Profile Image MainWindowQSL &Galerie QSL &Gallery MainWindowQSO &Filter QSO &Filters MainWindowBeendenQuit MainWindowSpter erinnernRemind Me Later MainWindow"Fehler &melden...Report &Bug... MainWindowZurcksetzenReset MainWindowVerbindungsoptionen nach dem Neustart der Anwendung wiederherstellen4Restore connection options after application restart MainWindowRig MainWindowRig - Band (-)Rig - Band Down MainWindowRig - Band (+) Rig - Band Up MainWindow Rig - PTT On/OffRig - PTT On/Off MainWindow RotorRotator MainWindowBenutzerdefinierte SQL-Abfragen (nur lesen) fr die Logbuchdatenbank ausfhren=Run custom read-only SQL queries against the logbook database MainWindowS&tatistik S&tatistics MainWindow*Arrangement speichernSave Arrangement MainWindowSe&rvice MainWindowSequenzSequence MainWindow8Service - QSLs herunterladenService - Download QSLs MainWindow.Service  QSO hochladenService - Upload QSOs MainWindowAlerts anzeigen Show Alerts MainWindowEine fr allesSingle MainWindowStoppenStop MainWindow2Schalte den Dialog "Neuer Kontakt" in den manuellen Eingabemodus<br/>(Zeit, Frequenz, Profile etc. werden nicht aus ihren gemeinsamen Quellen bernommen)|Switch New Contact dialog to the manually entry mode
(time, freq, profiles etc. are not taken from their common sources) MainWindowThema: Native Theme: Native MainWindow Thema: QLog DarkTheme: QLog Dark MainWindow"Thema: QLog LightTheme: QLog Light MainWindowWerkzeugleisteToolbar MainWindowBDaten und Einstellungen entpackenUnpack Data && Settings MainWindowHochladenUpload MainWindow WSJTXWSJTX MainWindowWas ist neu What's New MainWindow WsjtxWsjtx MainWindowop: op:  MainWindowAuroraMapWebChannelHandlerBeamMapWebChannelHandlerChatMapWebChannelHandler Gray-LineMapWebChannelHandlerGitterfeldGridMapWebChannelHandlerIBPMapWebChannelHandlerMUFMapWebChannelHandlerWegPathMapWebChannelHandlerWSJTX - CQ WSJTX - CQMapWebChannelHandler MHzNewContactWidget WNewContactWidget mNewContactWidget&Details&DetailsNewContactWidget59NewContactWidget80mNewContactWidget<b>DUPE !!!</b>DUPE !!!NewContactWidget*<b>DXCC-Statistik</b>DXCC StatisticsNewContactWidget0<b>Stationsstatistik</b>Station StatisticsNewContactWidget@<b>Ja</b> - eine ausgehende QSL-Karte wurde gesendet; das QSO wurde in den Online-Dienst hochgeladen und von diesem akzeptiert.<br/><b>Nein</b> - keine ausgehende QSL-Karte senden; das QSO nicht in den Online-Dienst hochladen.<br/><b>Angefordert</b> - die kontaktierte Station hat eine QSL-Karte angefordert; die kontaktierte Station hat angefordert, dass das QSO in den Online-Dienst hochgeladen wird.<br/><b>Wartend</b> - eine ausgehende QSL-Karte wurde zum Senden ausgewhlt; ein QSO wurde zum Hochladen in den Online-Dienst ausgewhlt.<br/>Yes - an outgoing QSL card has been sent; the QSO has been uploaded to, and accepted by, the online service
No - do not send an outgoing QSL card; do not upload the QSO to the online service
Requested - the contacted station has requested a QSL card; the contacted station has requested the QSO be uploaded to the online service
Queued - an outgoing QSL card has been selected to be sent; a QSO has been selected to be uploaded to the online service
NewContactWidgetAntenneAntennaNewContactWidgetLeerBlankNewContactWidgetBroBureauNewContactWidgetBCallbook-Anmeldung fehlgeschlagenCallbook login failedNewContactWidget0Callbook-Suche ist aktivCallbook search is activeNewContactWidget4Callbook-Suche ist inaktivCallbook search is inactiveNewContactWidgetRufzeichenCallsignNewContactWidgetBesttigt ConfirmedNewContactWidgetjZur Aktivierung muss die Contest-ID ausgefllt werden(Contest ID must be filled in to activateNewContactWidgetD&X Stats D&X StatsNewContactWidget DatumDateNewContactWidgetjBeschreibung der Ausrstung der kontaktierten Station0Description of the contacted station's equipmentNewContactWidget DirektDirectNewContactWidget DauerDurationNewContactWidgetElektronisch ElectronicNewContactWidget2Erweitern/ZusammenklappenExpand/CollapseNewContactWidgetFrequenz FrequencyNewContactWidgetGTGANewContactWidgetGAGENewContactWidgetGMGMNewContactWidgetIgnoriertIgnoredNewContactWidgetInfoNewContactWidgetLPLPNewContactWidgetLoTWNewContactWidgetSuchen Sie das Rufzeichen im Internet. Die Abfrage-URL kann unter Einstellungen -> Callbook gendert werdenPLookup the call on the web. The query URL can be changed in Settings -> CallbookNewContactWidget&Eigene Station M&y StationNewContactWidgetMitglied:Member:NewContactWidgetBetriebsartModeNewContactWidget&Eigene &Anmerkungen My &NotesNewContactWidget2Neues Band & Betriebsart!New Band & Mode!NewContactWidgetNeues Band! New Band!NewContactWidgetNeuer Eintrag! New Entity!NewContactWidget"Neue Betriebsart! New Mode!NewContactWidgetNeuer Slot! New Slot!NewContactWidgetNeinNoNewContactWidget PapierPaperNewContactWidget"AusbreitungsmodusPropagation ModeNewContactWidgetQLog Fehler QLog ErrorNewContactWidget$QSL AusgangsstatusQSL Send StatusNewContactWidgetQSL Ausgang via QSL Send viaNewContactWidgetQSL viaQSL viaNewContactWidgetWartendQueuedNewContactWidgetRSTeRSTrNewContactWidgetRSTaRSTsNewContactWidgetRX: NewContactWidgetAngefordert RequestedNewContactWidgetZurcksetzenResetNewContactWidgetRigNewContactWidgetSpeichernSaveNewContactWidget4Spezielle AktivittsgruppeSpecial Activity GroupNewContactWidget"Special Activity Group InformationNewContactWidgetStationStationNewContactWidgetTX: NewContactWidgetStartzeitTime OnNewContactWidgetWebNewContactWidgetGearbeitetWorkedNewContactWidgetWorld Wide Flora & FaunaNewContactWidgetJaYesNewContactWidgeteQSLNewContactWidgetDARC-DOK (Ortsverbandkenner) der kontaktierten Station (z.B. A01)Cthe contacted station's DARC DOK (District Location Code) (ex. A01)NewContactWidgetzwei oder vier nebeneinander liegende, jeweils vier Zeichen lange Gitterfelder (z. B. EN98,FM08,EM97,FM07)ctwo or four adjacent Maidenhead grid locators, each four characters long, (ex. EN98,FM08,EM97,FM07)NewContactWidget,InitialisierungsfehlerInitialization Error OmnirigRigDrv Rig 1Rig 1 OmnirigRigDrv Rig 2Rig 2 OmnirigRigDrv&Rig nicht verbundenRig is not connected OmnirigRigDrv&Rig-Status gendertRig status changed OmnirigRigDrv,InitialisierungsfehlerInitialization ErrorOmnirigV2RigDrv Rig 1Rig 1OmnirigV2RigDrv Rig 2Rig 2OmnirigV2RigDrv Rig 3Rig 3OmnirigV2RigDrv Rig 4Rig 4OmnirigV2RigDrv&Rig nicht verbundenRig is not connectedOmnirigV2RigDrv&Rig-Status gendertRig status changedOmnirigV2RigDrvFEin Port kann nicht gebunden werdenCannot bind a port PSTRotDrvLIP-Adresse kann nicht abgerufen werdenCannot get IP Address for PSTRotDrv,Fehler ist aufgetretenError Occurred PSTRotDrv,Keine IPv4-Adresse frNo IPv4 Address for PSTRotDrv$ZeitberschreitungOperation Timeout PSTRotDrvRot 1 PSTRotDrv Datei hinzufgenAdd FilePaperQSLDialogVerfgbare QSLAvailable QSLsPaperQSLDialog"Kopieren Sie die Bilddatei aus dem Quellordner in den Ordner "QLog Internal QSL Storage".<br/>Die Originaldatei bleibt unverndert im QuellordnerCopy the input file from the source folder to the QLog Internal QSL Storage folder.
The original file remains unchanged in the source folderPaperQSLDialogLschenDeletePaperQSLDialogLschen QSL? Delete QSL?PaperQSLDialogQSL importieren Import QSLPaperQSLDialog&QSL-Karte verwaltenManage QSL CardPaperQSLDialog ffnenOpenPaperQSLDialogEntfernenRemovePaperQSLDialogFavoritToggle FavoritePaperQSLDialog Alle Dateien (*) All Files (*)PlatformSettingsDialogFortsetzenContinuePlatformSettingsDialogFPlattform-spezifische EinstellungenPlatform-specific SettingsPlatformSettingsDialogDatei auswhlen Select FilePlatformSettingsDialogEinstellungenSettingPlatformSettingsDialogDie Datenbank wurde von einer anderen Plattform exportiert. Bitte berprfen oder aktualisieren Sie die folgenden Einstellungen. Sie knnen Felder leer lassen und spter in den Einstellungen konfigurieren.The database was exported from a different platform. Please verify or update the following settings. You can leave fields empty and configure them later in Settings.PlatformSettingsDialogWertValuePlatformSettingsDialogProfilfoto Profile ImageProfileImageWidgetQLog Hilfe QLog HelpQCoreApplicationd<b>TX-Bereich</b>: Max Frequenz darf nicht 0 sein.-TX Range: Max Frequency must not be 0. QMessageBox<b>TX-Bereich</b>: Die Maximalfrequenz darf nicht niedriger als die Minimalfrequenz sein.?TX Range: Max Frequency must not be under Min Frequency. QMessageBoxJDer Aktivittsname existiert bereits. Activity name is already exists. QMessageBox0CQZ darf nicht leer seinCQZ must not be empty QMessageBox.CW Keyer Port muss ein gltiger COM-Port sein.<br>Fr Windows verwenden Sie COMxx, fr unix-hnliche Betriebssysteme verwenden Sie einen Pfad zum GertgCW Keyer port must be a valid COM port.
For Windows use COMxx, for unix-like OS use a path to device QMessageBoxrDer regulre Ausdruck fr das Rufzeichen ist fehlerhaft..)Callsign Regular Expression is incorrect. QMessageBoxDRufzeichen hat ein falsches FormatCallsign has an invalid format QMessageBoxHKann Alarmregeln nicht aktualisierenCannot Update Alert Rules QMessageBoxKann das CW-Keyer Modell nicht zu <b>CW-ber-CAT</b> ndern.<br>Keine CW-ber-CAT Untersttzung fr Rig(s) <b>%1</b>kCannot change the CW Keyer Model to Morse over CAT
No Morse over CAT support for Rig(s) %1 QMessageBoxKann das CW-Keyer Profil nicht lschen.<br>Das Profil wird verwendet von Rig(s): <b>%1</b>UCannot delete the CW Keyer Profile
The CW Key Profile is used by Rig(s): %1 QMessageBoxEs kann kein Passwort fr %1 aus dem Passwort Speicher abgerufen werden6Cannot get a password for %1 from the Credential Store QMessageBoxDas Passwort fr %1 kann nicht im Passwort Speicher gespeichert werden5Cannot save a password for %1 to the Credential Store QMessageBoxRQSO-Filter kann nicht aktualisiert werden#Cannot update QSO Filter Conditions QMessageBoxBKann nicht in die Datei schreibenCannot write to the file QMessageBoxChat Fehler:  Chat Error:  QMessageBoxAktualisierung der Clubliste fehlgeschlagen. Kann keine neuen Downloads durchfhren2Club List Update failed. Cannot plan new downloads QMessageBoxAktualisierung der Clubliste fehlgeschlagen. Alte Datenstze knnen nicht entfernt werden2Club List Update failed. Cannot remove old records QMessageBoxXKommentar Regulrer Ausdruck ist fehlerhaft.(Comment Regular Expression is incorrect. QMessageBoxNKeine Verbindung zur Datenbank mglich.Could not connect to database. QMessageBoxKann QLog-Datenbank nicht als Backup nach ADIF exportieren.<p>Versuchen Sie, Ihr Log manuell nach ADIF zu exportieren_Could not export a QLog database to ADIF as a backup.